def handle_readbuf(self): netid = self.server.netid while self.ac_in_buffer: if self.ac_in_buffer[:4] != netid: p = self.ac_in_buffer.find(netid) if p == -1: p = asynchat.find_prefix_at_end(self.ac_in_buffer, netid) if p: self.ac_in_buffer = self.ac_in_buffer[-p:] else: self.ac_in_buffer = b'' break self.ac_in_buffer = self.ac_in_buffer[p:] cmd = self.ac_in_buffer[4:0x10].rstrip(b'\0').decode('utf8') payloadLen = unpack('<L', self.ac_in_buffer[0x10:0x14])[0] if payloadLen > MAX_PACKET_PAYLOAD: raise RuntimeError('Packet payload is too long (%d bytes)' % (payloadLen,)) payloadEnd = payloadLen + 0x18 if len(self.ac_in_buffer) < payloadEnd: # Don't have the whole packet yet break method = 'doCmd_' + cmd cksum = self.ac_in_buffer[0x14:0x18] payload = self.ac_in_buffer[0x18:payloadEnd] self.ac_in_buffer = self.ac_in_buffer[payloadEnd:] realcksum = dblsha(payload)[:4] if realcksum != cksum: self.logger.debug('Wrong checksum on `%s\' message (%s vs actual:%s); ignoring' % (cmd, b2a_hex(cksum), b2a_hex(realcksum))) return if hasattr(self, method): getattr(self, method)(payload)
def withFirst(self, f): if isinstance(f, Txn): f = f.txid steps = self._steps for s in steps: f = dblsha(f + s) return f
def recalculate(self, detailed=False): L = self.data steps = [] if detailed: detail = [] PreL = [] StartL = 0 else: detail = None PreL = [None] StartL = 2 Ll = len(L) if isinstance(L[1] if Ll > 1 else L[0], Txn): L = list(map(lambda a: a.txid if a else a, L)) else: L = list(L) if detailed or Ll > 1: while True: if detailed: detail += L if Ll == 1: break steps.append(L[1]) if Ll % 2: L += [L[-1]] L = PreL + [ dblsha(L[i] + L[i + 1]) for i in range(StartL, Ll, 2) ] Ll = len(L) self._steps = steps self.detail = detail
def recalculate(self, detailed=False): L = self.data steps = [] if detailed: detail = [] PreL = [] StartL = 0 else: detail = None PreL = [None] StartL = 2 Ll = len(L) if detailed or Ll > 1: if isinstance(L[1] if Ll > 1 else L[0], Txn): L = list(map(lambda a: a.txid if a else a, L)) while True: if detailed: detail += L if Ll == 1: break steps.append(L[1]) if Ll % 2: L += [L[-1]] L = PreL + [dblsha(L[i] + L[i + 1]) for i in range(StartL, Ll, 2)] Ll = len(L) self._steps = steps self.detail = detail
def makeMessage(self, cmd, payload=b""): cmd = cmd.encode("utf8") assert len(cmd) <= 12 cmd += b"\0" * (12 - len(cmd)) cksum = dblsha(payload)[:4] payloadLen = pack("<L", len(payload)) return self.netid + cmd + payloadLen + cksum + payload
def makeMessage(self, cmd, payload = b''): cmd = cmd.encode('utf8') assert len(cmd) <= 12 cmd += b'\0' * (12 - len(cmd)) cksum = dblsha(payload)[:4] payloadLen = pack('<L', len(payload)) return self.netid + cmd + payloadLen + cksum + payload
def idhash(self): if self.data[4:6] == b'\0\1': if hasattr(self, 'txid'): del self.txid raise NotImplementedError self.txid = dblsha(self.data) if hasattr(self, 'witness_hash'): del self.witness_hash
def makeMessage(self, cmd, payload=b''): cmd = cmd.encode('utf8') assert len(cmd) <= 12 cmd += b'\0' * (12 - len(cmd)) cksum = dblsha(payload)[:4] payloadLen = pack('<L', len(payload)) return self.netid + cmd + payloadLen + cksum + payload
def _Address2PKH(addr): try: addr = b58decode(addr, 25) except: return None if addr is None: return None ver = addr[0] cksumA = addr[-4:] cksumB = dblsha(addr[:-4])[:4] if cksumA != cksumB: return None return (ver, addr[1:-4])
def CalculateWitnessCommitment(txnobjs, nonce, force=False): gentx_withash = nonce withashes = (gentx_withash,) + tuple(a.get_witness_hash() for a in txnobjs[1:]) if not force: txids = (gentx_withash,) + tuple(a.txid for a in txnobjs[1:]) if withashes == txids: # Unnecessary return None wmr = MerkleTree(data=withashes).merkleRoot() commitment = util.dblsha(wmr + nonce) return commitment
def handle_readbuf(self): netid = self.server.netid while self.ac_in_buffer: if self.ac_in_buffer[:4] != netid: p = self.ac_in_buffer.find(netid) if p == -1: p = asynchat.find_prefix_at_end(self.ac_in_buffer, netid) if p: self.ac_in_buffer = self.ac_in_buffer[-p:] else: self.ac_in_buffer = b'' break self.ac_in_buffer = self.ac_in_buffer[p:] cmd = self.ac_in_buffer[4:0x10].rstrip(b'\0').decode('utf8') payloadLen = unpack('<L', self.ac_in_buffer[0x10:0x14])[0] if payloadLen > MAX_PACKET_PAYLOAD: raise RuntimeError('Packet payload is too long (%d bytes)' % (payloadLen, )) payloadEnd = payloadLen + 0x18 if len(self.ac_in_buffer) < payloadEnd: # Don't have the whole packet yet break method = 'doCmd_' + cmd cksum = self.ac_in_buffer[0x14:0x18] payload = self.ac_in_buffer[0x18:payloadEnd] self.ac_in_buffer = self.ac_in_buffer[payloadEnd:] realcksum = dblsha(payload)[:4] if realcksum != cksum: self.logger.debug( 'Wrong checksum on `%s\' message (%s vs actual:%s); ignoring' % (cmd, b2a_hex(cksum), b2a_hex(realcksum))) return if hasattr(self, method): getattr(self, method)(payload)
def buildStratumData(share, merkleroot): (prevBlock, height, bits) = MM.currentBlock data = b'\x02\0\0\0' data += prevBlock data += merkleroot data += share['ntime'][::-1] data += bits data += share['nonce'][::-1] share['bits'] = b2a_hex(bits[::-1]).decode('utf8') share['height'] = height share['merkleroot'] = b2a_hex(merkleroot[::-1]).decode('utf8') share['prevblock'] = b2a_hex(prevBlock[::-1]).decode('utf8') share['blkhash'] = b2a_hex(dblsha(data)[::-1]).decode('utf8') if ScryptCoin: share['crypto'] = 'scrypt' else: share['crypto'] = 'sha256' share['coin'] = CryptoCoin share['server'] = ServerName # do not touch! share['data'] = data return data
def checkShare(share): shareTime = share["time"] = time() username = share["username"] isstratum = False if "data" in share: # getwork/GBT checkData(share) data = share["data"] if username not in workLog: raise RejectedShare("unknown-user") MWL = workLog[username] shareMerkleRoot = data[36:68] if "blkdata" in share: pl = share["blkdata"] (txncount, pl) = varlenDecode(pl) cbtxn = bitcoin.txn.Txn(pl) othertxndata = cbtxn.disassemble(retExtra=True) coinbase = cbtxn.getCoinbase() wliPos = coinbase[0] + 2 wliLen = coinbase[wliPos - 1] wli = coinbase[wliPos : wliPos + wliLen] mode = "MC" moden = 1 else: wli = shareMerkleRoot mode = "MRD" moden = 0 coinbase = None else: # Stratum isstratum = True wli = share["jobid"] buildStratumData(share, b"\0" * 32) mode = "MC" moden = 1 othertxndata = b"" if None not in workLog: # We haven't yet sent any stratum work for this block raise RejectedShare("unknown-work") MWL = workLog[None] if wli not in MWL: raise RejectedShare("unknown-work") (wld, issueT) = MWL[wli] share[mode] = wld share["issuetime"] = issueT (workMerkleTree, workCoinbase) = wld[1:3] share["merkletree"] = workMerkleTree if "jobid" in share: cbtxn = deepcopy(workMerkleTree.data[0]) coinbase = workCoinbase + share["extranonce1"] + share["extranonce2"] cbtxn.setCoinbase(coinbase) cbtxn.assemble() data = buildStratumData(share, workMerkleTree.withFirst(cbtxn)) shareMerkleRoot = data[36:68] if data in DupeShareHACK: raise RejectedShare("duplicate") DupeShareHACK[data] = None blkhash = dblsha(data) if blkhash[28:] != b"\0\0\0\0": raise RejectedShare("H-not-zero") blkhashn = LEhash2int(blkhash) global networkTarget logfunc = getattr(checkShare.logger, "info" if blkhashn <= networkTarget else "debug") logfunc("BLKHASH: %64x" % (blkhashn,)) logfunc(" TARGET: %64x" % (networkTarget,)) # NOTE: this isn't actually needed for MC mode, but we're abusing it for a trivial share check... txlist = workMerkleTree.data txlist = [deepcopy(txlist[0])] + txlist[1:] cbtxn = txlist[0] cbtxn.setCoinbase(coinbase or workCoinbase) cbtxn.assemble() if blkhashn <= networkTarget: logfunc("Submitting upstream") RBDs.append(deepcopy((data, txlist, share.get("blkdata", None), workMerkleTree, share, wld))) if not moden: payload = assembleBlock(data, txlist) else: payload = share["data"] if len(othertxndata): payload += share["blkdata"] else: payload += assembleBlock(data, txlist)[80:] logfunc("Real block payload: %s" % (b2a_hex(payload).decode("utf8"),)) RBPs.append(payload) threading.Thread(target=blockSubmissionThread, args=(payload, blkhash, share)).start() bcnode.submitBlock(payload) if config.DelayLogForUpstream: share["upstreamRejectReason"] = PendingUpstream else: share["upstreamRejectReason"] = None share["upstreamResult"] = True MM.updateBlock(blkhash) # Gotwork hack... if gotwork and blkhashn <= config.GotWorkTarget: try: coinbaseMrkl = cbtxn.data coinbaseMrkl += blkhash steps = workMerkleTree._steps coinbaseMrkl += pack("B", len(steps)) for step in steps: coinbaseMrkl += step coinbaseMrkl += b"\0\0\0\0" info = {} info["hash"] = b2a_hex(blkhash).decode("ascii") info["header"] = b2a_hex(data).decode("ascii") info["coinbaseMrkl"] = b2a_hex(coinbaseMrkl).decode("ascii") thr = threading.Thread(target=submitGotwork, args=(info,)) thr.daemon = True thr.start() except: checkShare.logger.warning("Failed to build gotwork request") if "target" in share: workTarget = share["target"] elif len(wld) > 6: workTarget = wld[6] else: workTarget = None if workTarget is None: workTarget = config.ShareTarget if blkhashn > workTarget: raise RejectedShare("high-hash") share["target"] = workTarget share["_targethex"] = "%064x" % (workTarget,) shareTimestamp = unpack("<L", data[68:72])[0] if shareTime < issueT - 120: raise RejectedShare("stale-work") if shareTimestamp < shareTime - 300: raise RejectedShare("time-too-old") if shareTimestamp > shareTime + 7200: raise RejectedShare("time-too-new") if moden: cbpre = workCoinbase cbpreLen = len(cbpre) if coinbase[:cbpreLen] != cbpre: raise RejectedShare("bad-cb-prefix") # Filter out known "I support" flags, to prevent exploits for ff in (b"/P2SH/", b"NOP2SH", b"p2sh/CHV", b"p2sh/NOCHV"): if coinbase.find(ff) > max(-1, cbpreLen - len(ff)): raise RejectedShare("bad-cb-flag") if len(coinbase) > 100: raise RejectedShare("bad-cb-length") if shareMerkleRoot != workMerkleTree.withFirst(cbtxn): raise RejectedShare("bad-txnmrklroot") if len(othertxndata): allowed = assembleBlock(data, txlist)[80:] if allowed != share["blkdata"]: raise RejectedShare("bad-txns") if config.DynamicTargetting and username in userStatus: # NOTE: userStatus[username] only doesn't exist across restarts status = userStatus[username] target = status[0] or config.ShareTarget if target == workTarget: userStatus[username][2] += 1 else: userStatus[username][2] += float(target) / workTarget if isstratum and userStatus[username][2] > config.DynamicTargetGoal * 2: stratumsrv.quickDifficultyUpdate(username)
def idhash(self): self.txid = dblsha(self.data)
def checkShare(share): global rskLastReceivedShareTime global rskSubmittedShares shareTime = share['time'] = time() username = share['username'] checkQuickDiffAdjustment = False if 'data' in share: # getwork/GBT data = share['data'] shareMerkleRoot = data[36:68] if 'blkdata' in share: pl = share['blkdata'] (txncount, pl) = varlenDecode(pl) cbtxn = bitcoin.txn.Txn(pl) othertxndata = cbtxn.disassemble(retExtra=True) coinbase = cbtxn.getCoinbase() wliPos = coinbase[0] + 2 wliLen = coinbase[wliPos - 1] wli = coinbase[wliPos:wliPos + wliLen] mode = 'MC' moden = 1 else: wli = shareMerkleRoot mode = 'MRD' moden = 0 coinbase = None (wld, issueT) = LookupWork(username, wli) checkData(share, wld) else: # Stratum checkQuickDiffAdjustment = config.DynamicTargetQuick wli = share['jobid'] (wld, issueT) = LookupWork(None, wli) mode = 'MC' moden = 1 othertxndata = b'' share[mode] = wld share['issuetime'] = issueT (workMerkleTree, workCoinbase) = wld[1:3] share['merkletree'] = workMerkleTree if 'jobid' in share: cbtxn = deepcopy(workMerkleTree.data[0]) coinbase = workCoinbase + share['extranonce1'] + share['extranonce2'] cbtxn.setCoinbase(coinbase) cbtxn.assemble() data = buildStratumData(share, workMerkleTree.withFirst(cbtxn), workMerkleTree.MP['_BlockVersionBytes']) shareMerkleRoot = data[36:68] if data in DupeShareHACK: raise RejectedShare('duplicate') DupeShareHACK[data] = None blkhash = dblsha(data) if not hasattr(config, 'DEV_MODE_ON') or not config.DEV_MODE_ON: if not _reachesLowestDifficulty(blkhash): if len(share[mode]) >= 4: # currentblock may be changed, so we retry looking up some previous block saved (in RKS could be usefull prev blocks). blockToUse = (share[mode][3], share[mode][0], share[mode][4]) retryData = buildStratumData( share, workMerkleTree.withFirst(cbtxn), workMerkleTree.MP['_BlockVersionBytes'], blockToUse) shareMerkleRoot = retryData[36:68] blkhash = dblsha(retryData) # retryData could be equal than data so we check again previous conditions if retryData == data or not _reachesLowestDifficulty(blkhash): raise RejectedShare('H-not-zero') data = retryData DupeShareHACK[data] = None else: raise RejectedShare('H-not-zero') blkhashn = LEhash2int(blkhash) global networkTarget logfunc = getattr(checkShare.logger, 'info' if blkhashn <= networkTarget else 'debug') logfunc('BLKHASH: %64x' % (blkhashn, )) logfunc(' TARGET: %64x' % (networkTarget, )) # NOTE: this isn't actually needed for MC mode, but we're abusing it for a trivial share check... txlist = workMerkleTree.data txlist = [ deepcopy(txlist[0]), ] + txlist[1:] cbtxn = txlist[0] cbtxn.setCoinbase(coinbase or workCoinbase) cbtxn.assemble() rootstockBlockHash = None rootstockTarget = None if hasattr(workMerkleTree, "rootstockBlockInfo" ) and workMerkleTree.rootstockBlockInfo is not None: rootstockBlockHash = workMerkleTree.rootstockBlockInfo[0] if hasattr(config, 'DEV_MODE_ON') and config.DEV_MODE_ON: rootstockTarget = bdiff2target(config.RSK_ELOIPOOL_DIFF) else: rootstockTarget = workMerkleTree.rootstockBlockInfo[1] submitRootstock = rootstockTarget is not None and blkhashn <= rootstockTarget if rskLastReceivedShareTime is None: rskLastReceivedShareTime = int(round(time() * 1000)) rskSubmittedShares = 0 lastReceivedShareTimeNow = int(round(time() * 1000)) if lastReceivedShareTimeNow - rskLastReceivedShareTime >= 1000: rskSubmittedShares = 0 rskLastReceivedShareTime = lastReceivedShareTimeNow checkShare.logger.info( "ROOTSTOCK_DEBUG: RSKValidShare: {0} {1} {2}".format( blkhashn, rootstockTarget, submitRootstock)) if lastReceivedShareTimeNow - rskLastReceivedShareTime < 1000 and rskSubmittedShares < 1 and submitRootstock: rskSubmittedShares += 1 else: submitRootstock = False submitBitcoin = blkhashn <= networkTarget #checkShare.logger.info("ROOTSTOCK_DEBUG: BTCValidShare: {0} {1} {2}".format(blkhashn, networkTarget, submitBitcoin)) if submitBitcoin or submitRootstock: if submitBitcoin: share['BTC_SOLUTION'] = True logfunc("Submitting upstream") RBDs.append( deepcopy((data, txlist, share.get('blkdata', None), workMerkleTree, share, wld))) if not moden: payload = assembleBlock(data, txlist) else: payload = share['data'] if len(othertxndata): payload += share['blkdata'] else: payload += assembleBlock(data, txlist)[80:] if submitRootstock: share['RSK_SOLUTION'] = True blockhashHexRskSubmit = b2a_hex(blkhash).decode('ascii') blockheaderHexRskSubmit = b2a_hex(share['data']).decode('ascii') coinbaseHexRskSubmit = b2a_hex(cbtxn.data).decode('ascii') coinbaseHashHexRskSubmit = b2a_hex(cbtxn.txid).decode('ascii') merkleHashesRskSubmit = [ b2a_hex(x).decode('ascii') for x in workMerkleTree._steps ] merkleHashesRskSubmit.insert(0, coinbaseHashHexRskSubmit) merkleHashesRskSubmit = ' '.join(merkleHashesRskSubmit) txnCountRskSubmit = hex(len(txlist))[2:] threading.Thread(target=rootstockSubmissionThread, args=(blockhashHexRskSubmit, blockheaderHexRskSubmit, coinbaseHexRskSubmit, merkleHashesRskSubmit, txnCountRskSubmit, share)).start() if not submitBitcoin: return logfunc('Real block payload: %s' % (b2a_hex(payload).decode('utf8'), )) RBPs.append(payload) threading.Thread(target=blockSubmissionThread, args=(payload, blkhash, share)).start() bcnode.submitBlock(payload) if config.DelayLogForUpstream: share['upstreamRejectReason'] = PendingUpstream else: share['upstreamRejectReason'] = None share['upstreamResult'] = True MM.updateBlock(blkhash) # Gotwork hack... if gotwork and blkhashn <= config.GotWorkTarget: try: coinbaseMrkl = cbtxn.data coinbaseMrkl += blkhash steps = workMerkleTree._steps coinbaseMrkl += pack('B', len(steps)) for step in steps: coinbaseMrkl += step coinbaseMrkl += b"\0\0\0\0" info = {} info['hash'] = b2a_hex(blkhash).decode('ascii') info['header'] = b2a_hex(data).decode('ascii') info['coinbaseMrkl'] = b2a_hex(coinbaseMrkl).decode('ascii') thr = threading.Thread(target=submitGotwork, args=(info, )) thr.daemon = True thr.start() except: checkShare.logger.warning('Failed to build gotwork request') if 'target' in share: workTarget = share['target'] elif len(wld) > 6: workTarget = wld[6] else: workTarget = None if workTarget is None: workTarget = config.ShareTarget if blkhashn > workTarget: raise RejectedShare('high-hash') share['target'] = workTarget share['_targethex'] = '%064x' % (workTarget, ) shareTimestamp = unpack('<L', data[68:72])[0] if shareTime < issueT - config.StaleWorkTimeout: raise RejectedShare('stale-work') if shareTimestamp < shareTime - 300: raise RejectedShare('time-too-old') if shareTimestamp > shareTime + 7200: raise RejectedShare('time-too-new') if moden: cbpre = workCoinbase cbpreLen = len(cbpre) if coinbase[:cbpreLen] != cbpre: raise RejectedShare('bad-cb-prefix') # Filter out known "I support" flags, to prevent exploits for ff in (b'/P2SH/', b'NOP2SH', b'p2sh/CHV', b'p2sh/NOCHV'): if coinbase.find(ff) > max(-1, cbpreLen - len(ff)): raise RejectedShare('bad-cb-flag') if len(coinbase) > 100: raise RejectedShare('bad-cb-length') if shareMerkleRoot != workMerkleTree.withFirst(cbtxn): raise RejectedShare('bad-txnmrklroot') if len(othertxndata): allowed = assembleBlock(data, txlist)[80:] if allowed != share['blkdata']: raise RejectedShare('bad-txns') if config.DynamicTargetting and username in userStatus: # NOTE: userStatus[username] only doesn't exist across restarts status = userStatus[username] target = status[0] or config.ShareTarget if target == workTarget: userStatus[username][2] += 1 else: userStatus[username][2] += float(target) / workTarget if checkQuickDiffAdjustment and userStatus[username][ 2] > config.DynamicTargetGoal * 2: stratumsrv.quickDifficultyUpdate(username)
def withash(self): self.witness_hash = dblsha(self.data)
def checkShare(share): shareTime = share['time'] = time() username = share['username'] if 'data' in share: # getwork/GBT checkData(share) data = share['data'] if username not in workLog: raise RejectedShare('unknown-user') MWL = workLog[username] shareMerkleRoot = data[36:68] if 'blkdata' in share: pl = share['blkdata'] (txncount, pl) = varlenDecode(pl) cbtxn = bitcoin.txn.Txn(pl) othertxndata = cbtxn.disassemble(retExtra=True) coinbase = cbtxn.getCoinbase() wliPos = coinbase[0] + 2 wliLen = coinbase[wliPos - 1] wli = coinbase[wliPos:wliPos + wliLen] mode = 'MC' moden = 1 else: wli = shareMerkleRoot mode = 'MRD' moden = 0 coinbase = None else: # Stratum MWL = workLog[None] wli = share['jobid'] buildStratumData(share, b'\0' * 32) mode = 'MC' moden = 1 othertxndata = b'' if wli not in MWL: raise RejectedShare('unknown-work') (wld, issueT) = MWL[wli] share[mode] = wld share['issuetime'] = issueT (workMerkleTree, workCoinbase) = wld[1:3] share['merkletree'] = workMerkleTree if 'jobid' in share: cbtxn = deepcopy(workMerkleTree.data[0]) coinbase = workCoinbase + share['extranonce1'] + share['extranonce2'] cbtxn.setCoinbase(coinbase) cbtxn.assemble() data = buildStratumData(share, workMerkleTree.withFirst(cbtxn)) shareMerkleRoot = data[36:68] if data in DupeShareHACK: raise RejectedShare('duplicate') DupeShareHACK[data] = None blkhash = dblsha(data) if blkhash[28:] != b'\0\0\0\0': raise RejectedShare('H-not-zero') blkhashn = LEhash2int(blkhash) global networkTarget logfunc = getattr(checkShare.logger, 'info' if blkhashn <= networkTarget else 'debug') logfunc('BLKHASH: %64x' % (blkhashn, )) logfunc(' TARGET: %64x' % (networkTarget, )) # NOTE: this isn't actually needed for MC mode, but we're abusing it for a trivial share check... txlist = workMerkleTree.data txlist = [ deepcopy(txlist[0]), ] + txlist[1:] cbtxn = txlist[0] cbtxn.setCoinbase(coinbase or workCoinbase) cbtxn.assemble() if blkhashn <= networkTarget: logfunc("Submitting upstream") RBDs.append( deepcopy( (data, txlist, share.get('blkdata', None), workMerkleTree, share, wld))) if not moden: payload = assembleBlock(data, txlist) else: payload = share['data'] if len(othertxndata): payload += share['blkdata'] else: payload += assembleBlock(data, txlist)[80:] logfunc('Real block payload: %s' % (b2a_hex(payload).decode('utf8'), )) RBPs.append(payload) threading.Thread(target=blockSubmissionThread, args=(payload, blkhash, share)).start() bcnode.submitBlock(payload) if config.DelayLogForUpstream: share['upstreamRejectReason'] = PendingUpstream else: share['upstreamRejectReason'] = None share['upstreamResult'] = True MM.updateBlock(blkhash) # Gotwork hack... if gotwork and blkhashn <= config.GotWorkTarget: try: coinbaseMrkl = cbtxn.data coinbaseMrkl += blkhash steps = workMerkleTree._steps coinbaseMrkl += pack('B', len(steps)) for step in steps: coinbaseMrkl += step coinbaseMrkl += b"\0\0\0\0" info = {} info['hash'] = b2a_hex(blkhash).decode('ascii') info['header'] = b2a_hex(data).decode('ascii') info['coinbaseMrkl'] = b2a_hex(coinbaseMrkl).decode('ascii') thr = threading.Thread(target=submitGotwork, args=(info, )) thr.daemon = True thr.start() except: checkShare.logger.warning('Failed to build gotwork request') if 'target' in share: workTarget = share['target'] elif len(wld) > 6: workTarget = wld[6] else: workTarget = None if workTarget is None: workTarget = config.ShareTarget if blkhashn > workTarget: raise RejectedShare('high-hash') share['target'] = workTarget share['_targethex'] = '%064x' % (workTarget, ) shareTimestamp = unpack('<L', data[68:72])[0] if shareTime < issueT - 120: raise RejectedShare('stale-work') if shareTimestamp < shareTime - 300: raise RejectedShare('time-too-old') if shareTimestamp > shareTime + 7200: raise RejectedShare('time-too-new') if config.DynamicTargetting and username in userStatus: # NOTE: userStatus[username] only doesn't exist across restarts status = userStatus[username] target = status[0] or config.ShareTarget if target == workTarget: userStatus[username][2] += 1 else: userStatus[username][2] += float(target) / workTarget if moden: cbpre = workCoinbase cbpreLen = len(cbpre) if coinbase[:cbpreLen] != cbpre: raise RejectedShare('bad-cb-prefix') # Filter out known "I support" flags, to prevent exploits for ff in (b'/P2SH/', b'NOP2SH', b'p2sh/CHV', b'p2sh/NOCHV'): if coinbase.find(ff) > max(-1, cbpreLen - len(ff)): raise RejectedShare('bad-cb-flag') if len(coinbase) > 100: raise RejectedShare('bad-cb-length') if shareMerkleRoot != workMerkleTree.withFirst(cbtxn): raise RejectedShare('bad-txnmrklroot') if len(othertxndata): allowed = assembleBlock(data, txlist)[80:] if allowed != share['blkdata']: raise RejectedShare('bad-txns')
def checkShare(share): shareTime = share['time'] = time() username = share['username'] if 'data' in share: # getwork/GBT checkData(share) data = share['data'] if username not in workLog: raise RejectedShare('unknown-user') MWL = workLog[username] shareMerkleRoot = data[36:68] if 'blkdata' in share: pl = share['blkdata'] (txncount, pl) = varlenDecode(pl) cbtxn = bitcoin.txn.Txn(pl) othertxndata = cbtxn.disassemble(retExtra=True) coinbase = cbtxn.getCoinbase() wliPos = coinbase[0] + 2 wliLen = coinbase[wliPos - 1] wli = coinbase[wliPos:wliPos+wliLen] mode = 'MC' moden = 1 else: wli = shareMerkleRoot mode = 'MRD' moden = 0 coinbase = None else: # Stratum MWL = workLog[None] wli = share['jobid'] buildStratumData(share, b'\0' * 32) mode = 'MC' moden = 1 othertxndata = b'' if wli not in MWL: raise RejectedShare('unknown-work') (wld, issueT) = MWL[wli] share[mode] = wld share['issuetime'] = issueT (workMerkleTree, workCoinbase) = wld[1:3] share['merkletree'] = workMerkleTree if 'jobid' in share: cbtxn = deepcopy(workMerkleTree.data[0]) coinbase = workCoinbase + share['extranonce1'] + share['extranonce2'] cbtxn.setCoinbase(coinbase) cbtxn.assemble() data = buildStratumData(share, workMerkleTree.withFirst(cbtxn)) shareMerkleRoot = data[36:68] if data in DupeShareHACK: raise RejectedShare('duplicate') DupeShareHACK[data] = None blkhash = dblsha(data) if blkhash[28:] != b'\0\0\0\0': raise RejectedShare('H-not-zero') blkhashn = LEhash2int(blkhash) global networkTarget logfunc = getattr(checkShare.logger, 'info' if blkhashn <= networkTarget else 'debug') logfunc('BLKHASH: %64x' % (blkhashn,)) logfunc(' TARGET: %64x' % (networkTarget,)) # NOTE: this isn't actually needed for MC mode, but we're abusing it for a trivial share check... txlist = workMerkleTree.data txlist = [deepcopy(txlist[0]),] + txlist[1:] cbtxn = txlist[0] cbtxn.setCoinbase(coinbase or workCoinbase) cbtxn.assemble() if blkhashn <= networkTarget: logfunc("Submitting upstream") RBDs.append( deepcopy( (data, txlist, share.get('blkdata', None), workMerkleTree, share, wld) ) ) if not moden: payload = assembleBlock(data, txlist) else: payload = share['data'] if len(othertxndata): payload += share['blkdata'] else: payload += assembleBlock(data, txlist)[80:] logfunc('Real block payload: %s' % (b2a_hex(payload).decode('utf8'),)) RBPs.append(payload) threading.Thread(target=blockSubmissionThread, args=(payload, blkhash, share)).start() bcnode.submitBlock(payload) if config.DelayLogForUpstream: share['upstreamRejectReason'] = PendingUpstream else: share['upstreamRejectReason'] = None share['upstreamResult'] = True MM.updateBlock(blkhash) # Gotwork hack... if gotwork and blkhashn <= config.GotWorkTarget: try: coinbaseMrkl = cbtxn.data coinbaseMrkl += blkhash steps = workMerkleTree._steps coinbaseMrkl += pack('B', len(steps)) for step in steps: coinbaseMrkl += step coinbaseMrkl += b"\0\0\0\0" info = {} info['hash'] = b2a_hex(blkhash).decode('ascii') info['header'] = b2a_hex(data).decode('ascii') info['coinbaseMrkl'] = b2a_hex(coinbaseMrkl).decode('ascii') thr = threading.Thread(target=submitGotwork, args=(info,)) thr.daemon = True thr.start() except: checkShare.logger.warning('Failed to build gotwork request') if 'target' in share: workTarget = share['target'] elif len(wld) > 6: workTarget = wld[6] else: workTarget = None if workTarget is None: workTarget = config.ShareTarget if blkhashn > workTarget: raise RejectedShare('high-hash') share['target'] = workTarget share['_targethex'] = '%064x' % (workTarget,) shareTimestamp = unpack('<L', data[68:72])[0] if shareTime < issueT - 120: raise RejectedShare('stale-work') if shareTimestamp < shareTime - 300: raise RejectedShare('time-too-old') if shareTimestamp > shareTime + 7200: raise RejectedShare('time-too-new') if config.DynamicTargetting and username in userStatus: # NOTE: userStatus[username] only doesn't exist across restarts status = userStatus[username] target = status[0] or config.ShareTarget if target == workTarget: userStatus[username][2] += 1 else: userStatus[username][2] += float(target) / workTarget if moden: cbpre = workCoinbase cbpreLen = len(cbpre) if coinbase[:cbpreLen] != cbpre: raise RejectedShare('bad-cb-prefix') # Filter out known "I support" flags, to prevent exploits for ff in (b'/P2SH/', b'NOP2SH', b'p2sh/CHV', b'p2sh/NOCHV'): if coinbase.find(ff) > max(-1, cbpreLen - len(ff)): raise RejectedShare('bad-cb-flag') if len(coinbase) > 100: raise RejectedShare('bad-cb-length') if shareMerkleRoot != workMerkleTree.withFirst(cbtxn): raise RejectedShare('bad-txnmrklroot') if len(othertxndata): allowed = assembleBlock(data, txlist)[80:] if allowed != share['blkdata']: raise RejectedShare('bad-txns')