def do_test_bound_needle_dirs(self, hashtype): """test directories four deep with one data file at the lowest level""" (dir_name1, dir_path1, dir_name2, dir_path2) =\ self.make_two_test_directories(FOUR, ONE) tree1 = MerkleTree.create_from_file_system(dir_path1, hashtype) self.assertEqual(dir_name1, tree1.name) nodes1 = tree1.nodes self.assertTrue(nodes1 is not None) self.assertEqual(ONE, len(nodes1)) self.verify_tree_sha(tree1, dir_path1, hashtype) tree2 = MerkleTree.create_from_file_system(dir_path2, hashtype) self.assertEqual(dir_name2, tree2.name) nodes2 = tree2.nodes self.assertTrue(nodes2 is not None) self.assertEqual(ONE, len(nodes2)) self.verify_tree_sha(tree2, dir_path2, hashtype) self.assertTrue(tree1 == tree1) self.assertFalse(tree1 == tree2) tree1_str = tree1.to_string(0) tree1_rebuilt = MerkleTree.create_from_serialization( tree1_str, hashtype) # # DEBUG # print "NEEDLEDIR TREE1:\n" + tree1Str # print "REBUILT TREE1:\n" + tree1Rebuilt.toString("") # # END self.assertTrue(tree1 == tree1_rebuilt)
def do_test_bound_flat_dirs(self, hashtype): """test directory is single level, with four data files""" check_hashtype(hashtype) (dir_name1, dir_path1, dir_name2, dir_path2) =\ self.make_two_test_directories(ONE, FOUR) tree1 = MerkleTree.create_from_file_system(dir_path1, hashtype) self.assertEqual(dir_name1, tree1.name) nodes1 = tree1.nodes self.assertTrue(nodes1 is not None) self.assertEqual(FOUR, len(nodes1)) self.verify_tree_sha(tree1, dir_path1, hashtype) tree2 = MerkleTree.create_from_file_system(dir_path2, hashtype) self.assertEqual(dir_name2, tree2.name) nodes2 = tree2.nodes self.assertTrue(nodes2 is not None) self.assertEqual(FOUR, len(nodes2)) self.verify_tree_sha(tree2, dir_path2, hashtype) self.assertFalse(tree1 is None) self.assertTrue(tree1 == tree1) self.assertFalse(tree1 == tree2) tree1_str = tree1.to_string(0) tree1_rebuilt = MerkleTree.create_from_serialization( tree1_str, hashtype) self.assertTrue(tree1 == tree1_rebuilt)
def test_xlattice_bug1(self): """ this test relies on dat.xlattice.org being locally present and an internally consistent merkleization """ with open('tests/test_data/dat.xlattice.org', 'rb') as file: serialization = str(file.read(), 'utf-8') # create from serialization --------------------------------- tree1 = MerkleTree.create_from_serialization( serialization, HashTypes.SHA1) # # DEBUG # print "tree1 has %d nodes" % len(tree1.nodes) # with open('junk.tree1', 'w') as t: # t.write( tree1.toString(0) ) # # END ser1 = tree1.to_string(0) self.assertEqual(serialization, ser1) # create from string array ---------------------------------- string = serialization.split('\n') string = string[:-1] self.assertEqual(2511, len(string)) tree2 = MerkleTree.create_from_string_array(string, HashTypes.SHA1) ser2 = tree2.to_string(0) self.assertEqual(serialization, ser2) self.assertTrue(tree1 == tree2)
def test_xlattice_bug3(self): """ this test relies on dat2.xlattice.org being locally present and an internally consistent merkleization """ with open('tests/test_data/dat2.xlattice.org', 'rb') as file: serialization = str(file.read(), 'utf-8') # create from serialization --------------------------------- tree1 = MerkleTree.create_from_serialization( serialization, HashTypes.SHA2) ser1 = tree1.to_string(0) self.assertEqual(serialization, ser1) # create from string array ---------------------------------- string = serialization.split('\n') string = string[:-1] self.assertEqual(2511, len(string)) tree2 = MerkleTree.create_from_string_array(string, HashTypes.SHA2) ser2 = tree2.to_string(0) self.assertEqual(serialization, ser2) self.assertTrue(tree1 == tree2)
def test2(): m = MerkleTree(data[0:2]) merkle_hashes = m.get_hashes() assert merkle_hashes[0][0] == sha256(hashes[0] + hashes[1]).digest() assert merkle_hashes[1][0] == hashes[0] assert merkle_hashes[1][1] == hashes[1] for h in merkle_hashes[2]: assert h == None
def createClearMerkleTree(self, height): subsidy = self.SubsidyAlgo(height) cbtxn = self.makeCoinbaseTxn(subsidy, False, witness_commitment=None) cbtxn.setCoinbase(b'\0\0') # necessary to avoid triggering segwit marker+flags cbtxn.assemble() MT = MerkleTree([cbtxn]) if self.currentMerkleTree: self.UpdateClearMerkleTree(MT, self.currentMerkleTree.MP) MT.witness_commitment = None return MT
def test3(): m = MerkleTree(data[0:3]) merkle_hashes = m.get_hashes() assert merkle_hashes[0][0] == hash_abc assert merkle_hashes[1][0] == hash_ab assert merkle_hashes[1][1] == hashes[2] assert merkle_hashes[2][0] == hashes[0] assert merkle_hashes[2][1] == hashes[1] assert merkle_hashes[2][2] == None assert merkle_hashes[2][3] == None
def get_merklepath(self, txn): # Get Tree information from minernode proof = None for block in self.blockchain.blockchain: if txn in block[0].txnlist: merkletree = MerkleTree(block[0].txnlist) merkletree.build() arrayTree = merkletree.tree # Get merkle path proof = merkletree.get_proof(txn) return proof
def test4(): m = MerkleTree(data[0:4]) merkle_hashes = m.get_hashes() assert merkle_hashes[0][0] == hash_abcd assert merkle_hashes[1][0] == hash_ab assert merkle_hashes[1][1] == hash_cd assert merkle_hashes[2][0] == hashes[0] assert merkle_hashes[2][1] == hashes[1] assert merkle_hashes[2][2] == hashes[2] assert merkle_hashes[2][3] == hashes[3] for n in merkle_hashes[3]: assert n == None
def test5(): m = MerkleTree(data[0:5]) merkle_hashes = m.get_hashes() assert merkle_hashes[0][0] == hash_abcde assert merkle_hashes[1][0] == hash_abcd assert merkle_hashes[1][1] == hashes[4] assert merkle_hashes[2][0] == hash_ab assert merkle_hashes[2][1] == hash_cd assert merkle_hashes[2][2] == None assert merkle_hashes[2][3] == None assert merkle_hashes[3][0] == hashes[0] assert merkle_hashes[3][1] == hashes[1] assert merkle_hashes[3][2] == hashes[2] assert merkle_hashes[3][3] == hashes[3]
def merkle_test(): m = MerkleChain() b1 = [ "Hey!", "Hi!", "How are ya?", "Not bad!", "Cool!", "School good?", "Yes!", "Aight Imma head out" ] b2 = [ "My life is a lie", "The void grows bigger.", "I smell pennies", "Hmmm yes", "Enslaved water?", "Yes indeed", "Big yums", "Lovely" ] b3 = [ "Oof", "No", "Ah yes", "Ahhh no", "Big oofs", "No oofs here", "Stop", "go" ] blocks = [b1, b2, b3] for i in range(0, len(blocks)): ## cons nonce prev_hash = m.get_latest_block_hash() root = MerkleTree(blocks[i]).get_merkle_root() nonce = generate_hash(prev_hash, root, 3) ## add entry m.insert(blocks[i], nonce) assert m.latest_block_idx == i + 1 print(m.get_latest_block_hash()) ## run some test cases against blocks assert m.verify("Hey!", 1, 0) assert not m.verify("Ah yes", 3, 1) assert m.verify("Ah yes", 3, 2) assert m.verify("The void grows bigger.", 2, 1) assert m.verify("Aight Imma head out", 1, 7) assert not m.verify("Oofie", 3, 0)
def createClearMerkleTree(self, height): subsidy = self.SubsidyAlgo(height) cbtxn = self.makeCoinbaseTxn(subsidy, False) cbtxn.assemble() MT = MerkleTree([cbtxn]) if self.currentMerkleTree: self.UpdateClearMerkleTree(MT, self.currentMerkleTree.MP) return MT
def createClearMerkleTree(self, height): subsidy = self.SubsidyAlgo(height) blockInfo = (None, None) if hasattr(self, 'Rootstock') and self.Rootstock is not None: blockInfo = self.Rootstock.getBlockInfo() cbtxn = self.makeCoinbaseTxn(subsidy, False, witness_commitment=None) cbtxn.setCoinbase(b'\0\0') # necessary to avoid triggering segwit marker+flags cbtxn.assemble() MT = MerkleTree([cbtxn]) self.merkleTreeLock.acquire() if self.currentMerkleTree: self.UpdateClearMerkleTree(MT, self.currentMerkleTree.MP) self.merkleTreeLock.release() MT.witness_commitment = None if blockInfo[0] is not None: MT.rootstockBlockInfo = blockInfo return MT
def validate(self): boolean = True for i in range(1, len(self.transactions)): transaction = self.transactions[i] boolean = transaction.validate() if not boolean: return boolean return self.header['tree_root'] == MerkleTree(self.transactions).get_root()
def _ProcessGBT(self, MP, TS = None): oMP = MP MP = deepcopy(MP) prevBlock = bytes.fromhex(MP['previousblockhash'])[::-1] if 'height' not in MP: MP['height'] = TS['access'].getinfo()['blocks'] + 1 height = MP['height'] bits = bytes.fromhex(MP['bits'])[::-1] (MP['_bits'], MP['_prevBlock']) = (bits, prevBlock) if (prevBlock, height, bits) != self.currentBlock and (self.currentBlock[1] is None or height > self.currentBlock[1]): self.updateBlock(prevBlock, height, bits, _HBH=(MP['previousblockhash'], MP['bits'])) txnlist = MP['transactions'] if len(txnlist) and isinstance(txnlist[0], dict): txninfo = txnlist txnlist = tuple(a['data'] for a in txnlist) elif 'transactionfees' in MP: # Backward compatibility with pre-BIP22 gmp_fees branch txninfo = [{'fee':a} for a in MP['transactionfees']] else: # Backward compatibility with pre-BIP22 hex-only (bitcoind <0.7, Eloipool <future) txninfo = [{}] * len(txnlist) # TODO: cache Txn or at least txid from previous merkle roots? txnlist = [a for a in map(bytes.fromhex, txnlist)] self._makeBlockSafe(MP, txnlist, txninfo) cbtxn = self.makeCoinbaseTxn(MP['coinbasevalue'], prevBlockHex = MP['previousblockhash']) cbtxn.setCoinbase(b'\0\0') cbtxn.assemble() txnlist.insert(0, cbtxn.data) txninfo.insert(0, { }) txnlist = [a for a in map(Txn, txnlist[1:])] txnlist.insert(0, cbtxn) txnlist = list(txnlist) newMerkleTree = MerkleTree(txnlist) newMerkleTree.POTInfo = MP.get('POTInfo') newMerkleTree.MP = MP newMerkleTree.oMP = oMP return newMerkleTree
def do_test_pathless_unbound(self, hashtype): """ Test basic characteristics of very simple MerkleTrees created using a specific SHA hash type. """ (dir_name1, dir_name2) = self.get_two_unique_directory_names() check_hashtype(hashtype) tree1 = MerkleTree(dir_name1, hashtype) self.assertEqual(dir_name1, tree1.name) if hashtype == HashTypes.SHA1: self.assertEqual(SHA1_HEX_NONE, tree1.hex_hash) elif hashtype == HashTypes.SHA2: self.assertEqual(SHA2_HEX_NONE, tree1.hex_hash) elif hashtype == HashTypes.SHA3: self.assertEqual(SHA3_HEX_NONE, tree1.hex_hash) elif hashtype == HashTypes.BLAKE2B_256: self.assertEqual(BLAKE2B_256_HEX_NONE, tree1.hex_hash) else: raise NotImplementedError tree2 = MerkleTree(dir_name2, hashtype) self.assertEqual(dir_name2, tree2.name) # these tests remain skimpy self.assertFalse(tree1 is None) self.assertTrue(tree1 == tree1) self.assertFalse(tree1 == tree2) tree1_str = tree1.to_string(0) # there should be no indent on the first line self.assertFalse(tree1_str[0] == ' ') # no extra lines should be added lines = tree1_str.split('\n') # this split generates an extra blank line, because the serialization # ends with CR-LF if lines[-1] == '': lines = lines[:-1] self.assertEqual(1, len(lines)) tree1_rebuilt = MerkleTree.create_from_serialization( tree1_str, hashtype) self.assertTrue(tree1 == tree1_rebuilt)
def do_test_deepish_trees(self, hashtype): """ Build a directory of random data, then its MerkleTree, then round trip to a serialization and back. """ tree_top = os.path.join('tmp', self.rng.next_file_name(MAX_NAME_LEN)) while os.path.exists(tree_top): tree_top = os.path.join( 'tmp', self.rng.next_file_name(MAX_NAME_LEN)) # Generate a quasi-random data directory, 7 deep, up to 5 files/dir self.rng.next_data_dir(tree_top, depth=7, width=5, max_len=4096) # Build a MerkleTree specifying the directory. tree = MerkleTree.create_from_file_system(tree_top, hashtype) # ROUND TRIP 1 ---------------------------------------------- # Serialize it. ser = tree.__str__() # Deserialize to make another MerkleTree. tree2 = MerkleTree.create_from_serialization(ser, hashtype) self.assertTrue(tree2.__eq__(tree)) self.assertEqual(tree2, tree) # identical test # ROUND TRIP 2 ---------------------------------------------- strings = ser.split('\n') strings = strings[:-1] tree3 = MerkleTree.create_from_string_array(strings, hashtype) self.assertEqual(tree3, tree) # ROUND TRIP 3 ---------------------------------------------- filename = os.path.join('tmp', self.rng.next_file_name(8)) while os.path.exists(filename): filename = os.path.join('tmp', self.rng.next_file_name(8)) with open(filename, 'w') as file: file.write(ser) tree4 = MerkleTree.create_from_file(filename, hashtype) self.assertEqual(tree4, tree)
def append_chain(): conn = sqlite3.connect("message.db") c = conn.cursor() res = c.execute("SELECT merkle_idx FROM messages " + "WHERE blk_index = -1 ORDER BY merkle_idx DESC") msgs = [r[i] for r in res] root = MerkleTree(msgs).get_merkle_root() prev_hash = MerkleChainClientHandler.chain.get_latest_block_hash() nonce = generate_hash(prev_hash, root, 3) return MerkleChainClientHandler.chain.insert(msgs, nonce)
def do_test_deepish_trees(self, hashtype): """ Build a directory of random data, then its MerkleTree, then round trip to a serialization and back. """ tree_top = os.path.join('tmp', self.rng.next_file_name(MAX_NAME_LEN)) while os.path.exists(tree_top): tree_top = os.path.join('tmp', self.rng.next_file_name(MAX_NAME_LEN)) # Generate a quasi-random data directory, 7 deep, up to 5 files/dir self.rng.next_data_dir(tree_top, depth=7, width=5, max_len=4096) # Build a MerkleTree specifying the directory. tree = MerkleTree.create_from_file_system(tree_top, hashtype) # ROUND TRIP 1 ---------------------------------------------- # Serialize it. ser = tree.__str__() # Deserialize to make another MerkleTree. tree2 = MerkleTree.create_from_serialization(ser, hashtype) self.assertTrue(tree2.__eq__(tree)) self.assertEqual(tree2, tree) # identical test # ROUND TRIP 2 ---------------------------------------------- strings = ser.split('\n') strings = strings[:-1] tree3 = MerkleTree.create_from_string_array(strings, hashtype) self.assertEqual(tree3, tree) # ROUND TRIP 3 ---------------------------------------------- filename = os.path.join('tmp', self.rng.next_file_name(8)) while os.path.exists(filename): filename = os.path.join('tmp', self.rng.next_file_name(8)) with open(filename, 'w') as file: file.write(ser) tree4 = MerkleTree.create_from_file(filename, hashtype) self.assertEqual(tree4, tree)
def __init__(self, transactions=None, prev_header=None, header=None): self.transactions = transactions if header is None: self.header = { 'prev_header': prev_header, 'tree_root': MerkleTree(transactions).get_root(), 'timestamp': int(time.time()), 'nonce': uuid.uuid4().hex } else: self.header = header
def test6(): m = MerkleTree(data[0:6]) merkle_hashes = m.get_hashes() assert merkle_hashes[0][0] == hash_abcdef assert merkle_hashes[1][0] == hash_abcd assert merkle_hashes[1][1] == hash_ef assert merkle_hashes[2][0] == hash_ab assert merkle_hashes[2][1] == hash_cd assert merkle_hashes[2][2] == hashes[4] assert merkle_hashes[2][3] == hashes[5] assert merkle_hashes[3][0] == hashes[0] assert merkle_hashes[3][1] == hashes[1] assert merkle_hashes[3][2] == hashes[2] assert merkle_hashes[3][3] == hashes[3] assert merkle_hashes[3][4] == None assert merkle_hashes[3][5] == None assert merkle_hashes[3][6] == None assert merkle_hashes[3][7] == None
def test_gray_boxes_bug3(self): """ Test solution to bug in handling grayboxes website. """ serialization =\ '088d0e391e1a4872329e0f7ac5d45b2025363e26c199a7' + \ '4ea39901d109afd6ba grayboxes.com/\n' +\ ' 24652ddc14687866e6b1251589aee7e1e3079a87f80cd' + \ '7775214f6d837612a90 images/\n' +\ ' 1eb774eef9be1e696f69a2f95711be37915aac283bb4' + \ 'b34dcbaf7d032233e090 grayboxes.gif\n' +\ ' 6eacebda9fd55b59c0d2e48e2ed59ce9fd683379592f8' + \ 'e662b1de88e041f53c9 index.html\n' # create from string array ---------------------------------- string = serialization.split('\n') string = string[:-1] self.assertEqual(4, len(string)) tree2 = MerkleTree.create_from_string_array(string, HashTypes.SHA2) ser2 = tree2.to_string(0) self.assertEqual(serialization, ser2) # create from serialization --------------------------------- tree1 = MerkleTree.create_from_serialization( serialization, HashTypes.SHA2) ser1 = tree1.to_string(0) self.assertEqual(serialization, ser1) self.assertTrue(tree1 == tree2) # 2014-06-26 tagged this on here to test firstLineRE_1() first_line = string[0] match_ = MerkleTree.first_line_re_2().match(first_line) self.assertTrue(match_ is not None) self.assertEqual(match_.group(1), '') # indent tree_hash = match_.group(2) dir_name = match_.group(3) self.assertEqual(tree_hash + ' ' + dir_name, first_line)
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 test_gray_boxes_bug1(self): """ Verify that bug #1 in handling serialization of grayboxes website has been corrected. """ serialization =\ '721a08022dd26e7be98b723f26131786fd2c0dc3 grayboxes.com/\n' +\ ' fcd3973c66230b9078a86a5642b4c359fe72d7da images/\n' +\ ' 15e47f4eb55197e1bfffae897e9d5ce4cba49623 grayboxes.gif\n' +\ ' 2477b9ea649f3f30c6ed0aebacfa32cb8250f3df index.html\n' # create from string array ---------------------------------- string = serialization.split('\n') string = string[:-1] self.assertEqual(4, len(string)) tree2 = MerkleTree.create_from_string_array(string, HashTypes.SHA1) ser2 = tree2.to_string(0) self.assertEqual(serialization, ser2) # create from serialization --------------------------------- tree1 = MerkleTree.create_from_serialization( serialization, HashTypes.SHA1) ser1 = tree1.to_string(0) self.assertEqual(serialization, ser1) self.assertTrue(tree1 == tree2) # 2014-06-26 tagged this on here to test firstLineRE_1() first_line = string[0] match_ = MerkleTree.first_line_re_1().match(first_line) self.assertTrue(match_ is not None) self.assertEqual(match_.group(1), '') # indent tree_hash = match_.group(2) dir_name = match_.group(3) self.assertEqual(tree_hash + ' ' + dir_name, first_line)
def createClearMerkleTree(self, height, bits): basenBits = 0x1E00FFFF nShift = ((basenBits >> 24) & 0xff) - ((bits >> 24) & 0xff) dDiff = float(basenBits & 0x007fffff) / float(bits & 0x007fffff) while (nShift > 0): dDiff *= 256.0 nShift -= 1 while (nShift < 0): dDiff /= 256.0 nShift += 1 nSubsidy1 = int(sqrt(dDiff * height)) subsidy = nSubsidy1 + 2500000000 cbtxn = self.makeCoinbaseTxn(subsidy, False) cbtxn.assemble() return MerkleTree([cbtxn])
def updateMerkleTree(self): global now self.logger.debug('Polling bitcoind for memorypool') self.nextMerkleUpdate = now + self.TxnUpdateRetryWait try: # First, try BIP 22 standard getblocktemplate :) MP = self.access.getblocktemplate(self.GBTReq) self.OldGMP = False except: try: # Failing that, give BIP 22 draft (2012-02 through 2012-07) getmemorypool a chance MP = self.access.getmemorypool(self.GMPReq) except: try: # Finally, fall back to bitcoind 0.5/0.6 getmemorypool MP = self.access.getmemorypool() except: MP = False if MP is False: # This way, we get the error from the BIP22 call if the old one fails too raise # Pre-BIP22 server (bitcoind <0.7 or Eloipool <20120513) if not self.OldGMP: self.OldGMP = True self.logger.warning('Upstream server is not BIP 22 compatible') oMP = deepcopy(MP) prevBlock = bytes.fromhex(MP['previousblockhash'])[::-1] if 'height' in MP: height = MP['height'] else: height = self.access.getinfo()['blocks'] + 1 bits = bytes.fromhex(MP['bits'])[::-1] if (prevBlock, height, bits) != self.currentBlock: self.updateBlock(prevBlock, height, bits, _HBH=(MP['previousblockhash'], MP['bits'])) txnlist = MP['transactions'] if len(txnlist) and isinstance(txnlist[0], dict): txninfo = txnlist txnlist = tuple(a['data'] for a in txnlist) txninfo.insert(0, { }) elif 'transactionfees' in MP: # Backward compatibility with pre-BIP22 gmp_fees branch txninfo = [{'fee':a} for a in MP['transactionfees']] else: # Backward compatibility with pre-BIP22 hex-only (bitcoind <0.7, Eloipool <future) txninfo = [{}] * len(txnlist) # TODO: cache Txn or at least txid from previous merkle roots? txnlist = [a for a in map(bytes.fromhex, txnlist)] self._makeBlockSafe(MP, txnlist, txninfo) cbtxn = self.makeCoinbaseTxn(MP['coinbasevalue']) cbtxn.setCoinbase(b'\0\0') cbtxn.assemble() txnlist.insert(0, cbtxn.data) txnlist = [a for a in map(Txn, txnlist[1:])] txnlist.insert(0, cbtxn) txnlist = list(txnlist) newMerkleTree = MerkleTree(txnlist) if newMerkleTree.merkleRoot() != self.currentMerkleTree.merkleRoot(): newMerkleTree.POTInfo = MP.get('POTInfo') newMerkleTree.oMP = oMP if (not self.OldGMP) and 'proposal' in MP.get('capabilities', ()): (prevBlock, height, bits) = self.currentBlock coinbase = self.makeCoinbase(height=height) cbtxn.setCoinbase(coinbase) cbtxn.assemble() merkleRoot = newMerkleTree.merkleRoot() MRD = (merkleRoot, newMerkleTree, coinbase, prevBlock, bits) blkhdr = MakeBlockHeader(MRD) data = assembleBlock(blkhdr, txnlist) propose = self.access.getblocktemplate({ "mode": "proposal", "data": b2a_hex(data).decode('utf8'), }) if propose is None: self.logger.debug('Updating merkle tree (upstream accepted proposal)') self.currentMerkleTree = newMerkleTree else: self.RejectedProposal = (newMerkleTree, propose) try: propose = propose['reject-reason'] except: pass self.logger.error('Upstream rejected proposed block: %s' % (propose,)) else: self.logger.debug('Updating merkle tree (no proposal support)') self.currentMerkleTree = newMerkleTree self.lastMerkleUpdate = now self.nextMerkleUpdate = now + self.MinimumTxnUpdateWait if self.needMerkle == 2: self.needMerkle = 1 self.needMerkleSince = now
def _ProcessGBT(self, MP, TS = None): oMP = MP MP = deepcopy(MP) if MP['version'] & 0xe0000000 != 0x20000000: self.logger.error('Template from \'%s\' has non-BIP9 block version (%x)' % (TS['name'], MP['version'])) return None ISupportAllRules = True for ruleflag in MP['rules']: (MandatoryRule, rule) = SplitRuleFlag(ruleflag) if rule not in SupportedRules: ISupportAllRules = False if MandatoryRule: self.logger.error('Template from \'%s\' strictly requires unsupported rule \'%s\'', TS['name'], rule) return None else: self.logger.warning('Template from \'%s\' loosely requires unsupported rule \'%s\'', TS['name'], rule) MP['_filtered_vbavailable'] = {} for ruleflag in MP['vbavailable']: rulebit = MP['vbavailable'][ruleflag] rulemask = (1 << rulebit) if MP['version'] & rulemask: MP['_filtered_vbavailable'][ruleflag] = rulebit prevBlock = bytes.fromhex(MP['previousblockhash'])[::-1] if 'height' not in MP: MP['height'] = TS['access'].getinfo()['blocks'] + 1 height = MP['height'] bits = bytes.fromhex(MP['bits'])[::-1] (MP['_bits'], MP['_prevBlock']) = (bits, prevBlock) MP['_BlockVersionBytes'] = struct.pack('<L', MP['version']) if (prevBlock, height, bits) != self.currentBlock and (self.currentBlock[1] is None or height > self.currentBlock[1]): self.updateBlock(prevBlock, height, bits, _HBH=(MP['previousblockhash'], MP['bits'])) txnlist = MP['transactions'] if len(txnlist) and isinstance(txnlist[0], dict): txninfo = txnlist txnlist = tuple(a['data'] for a in txnlist) elif 'transactionfees' in MP: # Backward compatibility with pre-BIP22 gmp_fees branch txninfo = [{'fee':a} for a in MP['transactionfees']] else: # Backward compatibility with pre-BIP22 hex-only (bitcoind <0.7, Eloipool <future) txninfo = [{}] * len(txnlist) # TODO: cache Txn or at least txid from previous merkle roots? txnlist = [a for a in map(bytes.fromhex, txnlist)] self._makeBlockSafe(MP, txnlist, txninfo) if len(MP['transactions']) != len(txnlist) and not ISupportAllRules: self.logger.error('Template from \'%s\' should be trimmed, but requires unsupported rule(s)', TS['name']) return None txnobjs = [None] for i in range(len(txnlist)): iinfo = txninfo[i] ka = {} if 'txid' in iinfo: ka['txid'] = bytes.fromhex(iinfo['txid'])[::-1] txnobjs.append(Txn(data=txnlist[i], **ka)) witness_commitment = CalculateWitnessCommitment(txnobjs, self.WitnessNonce, force=self.ForceWitnessCommitment) cbtxn = self.makeCoinbaseTxn(MP['coinbasevalue'], prevBlockHex = MP['previousblockhash'], witness_commitment=witness_commitment) cbtxn.setCoinbase(b'\0\0') cbtxn.assemble() txnobjs[0] = cbtxn txnobjs = list(txnobjs) newMerkleTree = MerkleTree(txnobjs) newMerkleTree.POTInfo = MP.get('POTInfo') newMerkleTree.MP = MP newMerkleTree.oMP = oMP newMerkleTree.witness_commitment = witness_commitment return newMerkleTree