def block_from_template(self, block_template): coinbase = create_coinbase(block_template['height']) coinbase.vout[1].scriptPubKey = CScript( [OP_HASH160, bytes(20), OP_EQUAL]) block = CBlock() block.hashPrevBlock = int(block_template['previousblockhash'], 16) block.nBits = 0x207fffff block.nTime = block_template['mintime'] block.nHeight = block_template['height'] block.hashEpochBlock = int(block_template['epochblockhash'], 16) block.vtx = [coinbase] return block
def run_test(self): node = self.nodes[0] node.add_p2p_connection(P2PDataStore()) # OP_TRUE in P2SH address = node.decodescript('51')['p2sh'] # burn script p2sh_script = CScript([OP_HASH160, bytes(20), OP_EQUAL]) prevblockhash = node.getbestblockhash() coinbase = create_coinbase(201) coinbase.vout[1].scriptPubKey = p2sh_script coinbase.rehash() sample_block = CBlock() sample_block.vtx = [coinbase] sample_block.hashPrevBlock = int(prevblockhash, 16) sample_block.nBits = 0x207fffff sample_block.nTime = 1600000036 sample_block.nReserved = 0 sample_block.nHeaderVersion = 1 sample_block.nHeight = 201 sample_block.hashEpochBlock = 0 sample_block.hashMerkleRoot = sample_block.calc_merkle_root() sample_block.hashExtendedMetadata = hash256_int(b'\0') sample_block.update_size() # Using legacy hashing algo block = copy.deepcopy(sample_block) target = uint256_from_compact(block.nBits) block.rehash() while hash256_int( block.serialize()) > target or block.sha256 <= target: block.nNonce += 1 block.rehash() self.fail_block(block, force_send=True, reject_reason='high-hash') del block # Claimed size already excessive (before doing any other checks) block = copy.deepcopy(sample_block) block.nSize = 32_000_001 block.solve() self.fail_block(block, force_send=True, reject_reason='bad-blk-size') del block # Incorrect nBits block = copy.deepcopy(sample_block) block.nBits = 0x207ffffe block.solve() self.fail_block(block, force_send=True, reject_reason='bad-diffbits') del block # Block too old block = copy.deepcopy(sample_block) block.nTime = 1600000035 block.solve() self.fail_block(block, force_send=True, reject_reason='time-too-old') del block # nReserved must be 0 block = copy.deepcopy(sample_block) block.nReserved = 0x0100 block.solve() self.fail_block(block, force_send=True, reject_reason='bad-blk-reserved') del block # nHeaderVersion must be 1 block = copy.deepcopy(sample_block) block.nHeaderVersion = 0 block.solve() self.fail_block(block, force_send=True, reject_reason='bad-blk-version') block.nHeaderVersion = 2 block.solve() self.fail_block(block, force_send=True, reject_reason='bad-blk-version') del block # Incorrect claimed height block = copy.deepcopy(sample_block) block.nHeight = 200 block.solve() self.fail_block(block, force_send=True, reject_reason='bad-blk-height') block.nHeight = 202 block.solve() self.fail_block(block, force_send=True, reject_reason='bad-blk-height') del block # Invalid epoch block block = copy.deepcopy(sample_block) block.hashEpochBlock = 1 block.solve() self.fail_block(block, force_send=True, reject_reason='bad-blk-epoch') del block # Time too far into the future block = copy.deepcopy(sample_block) block.nTime = int(time.time()) + 2 * 60 * 60 + 1 block.solve() self.fail_block(block, force_send=True, reject_reason='time-too-new') del block # Invalid merkle root block = copy.deepcopy(sample_block) block.hashMerkleRoot = 0 block.solve() self.fail_block(block, reject_reason='bad-txnmrklroot') del block # Invalid metadata hash block = copy.deepcopy(sample_block) block.hashExtendedMetadata = 0 block.solve() self.fail_block(block, reject_reason='bad-metadata-hash') del block # Non-empty metadata block = copy.deepcopy(sample_block) block.vMetadata.append(CBlockMetadataField(0, b'')) block.rehash_extended_metadata() block.solve() self.fail_block(block, reject_reason='bad-metadata') del block # Claimed nSize doesn't match actual size block = copy.deepcopy(sample_block) block.nSize = 1 block.solve() self.fail_block(block, reject_reason='blk-size-mismatch') del block block_template = node.getblocktemplate() assert_equal(block_template.pop('capabilities'), ['proposal']) assert_equal(block_template.pop('version'), 1) assert_equal(block_template.pop('previousblockhash'), prevblockhash) assert_equal( block_template.pop('epochblockhash'), '0000000000000000000000000000000000000000000000000000000000000000') assert_equal( block_template.pop('extendedmetadatahash'), '9a538906e6466ebd2617d321f71bc94e56056ce213d366773699e28158e00614') assert_equal(block_template.pop('transactions'), []) assert_equal(block_template.pop('coinbaseaux'), {}) assert_equal(block_template.pop('coinbasevalue'), int(SUBSIDY * COIN)) assert_equal(block_template.pop('coinbasetxn'), {'minerfund': { 'outputs': [] }}) block_template.pop('longpollid') assert_equal( block_template.pop('target'), '7fffff0000000000000000000000000000000000000000000000000000000000') assert_equal(block_template.pop('mintime'), 1600000036) assert_equal(block_template.pop('mutable'), ['time', 'transactions', 'prevblock']) assert_equal(block_template.pop('noncerange'), '00000000ffffffff') assert_equal(block_template.pop('sigoplimit'), 226950) assert_equal(block_template.pop('sizelimit'), 32000000) block_template.pop('curtime') assert_equal(block_template.pop('bits'), '207fffff') assert_equal(block_template.pop('height'), 201) assert_equal(block_template, {}) # Check epoch hash is 0 for the first 20 blocks for height in range(201, 221): block_template = node.getblocktemplate() assert_equal(block_template['epochblockhash'], '00' * 32) block = self.block_from_template(block_template) block.hashEpochBlock = 0 prepare_block(block) node.p2p.send_blocks_and_test([block], node) del block # Move to end of epoch node.generatetoaddress(4819, address) assert_equal(node.getblockcount(), 5039) epochblockhash = node.getbestblockhash() epochblock = node.getblock(epochblockhash) assert_equal(epochblock['epochblockhash'], '00' * 32) # getblocktemplate gives us current tip as epoch block hash block_template = node.getblocktemplate() assert_equal(block_template['epochblockhash'], epochblockhash) assert_equal(block_template['previousblockhash'], epochblockhash) # Using 0 as epoch block hash is now invalid block = self.block_from_template(block_template) block.hashEpochBlock = 0 prepare_block(block) self.fail_block(block, force_send=True, reject_reason='bad-blk-epoch') # Setting current tip as epoch hash makes the block valid block.hashEpochBlock = int(epochblockhash, 16) prepare_block(block) node.p2p.send_blocks_and_test([block], node) del block # getblocktemplate still gives us the same epoch block hash block_template = node.getblocktemplate() assert_equal(block_template['epochblockhash'], epochblockhash) assert_equal(block_template['previousblockhash'], node.getbestblockhash()) # Block after that still requires epoch block hash block = self.block_from_template(block_template) block.hashEpochBlock = int(epochblockhash, 16) prepare_block(block) node.p2p.send_blocks_and_test([block], node) del block # Test 48-bit nTime node.setmocktime( 2**32) # smallest number that does not fit in 32-bit number block_template = node.getblocktemplate() assert_equal(block_template['curtime'], 2**32) block = self.block_from_template(block_template) block.nTime = 2**32 prepare_block(block) node.p2p.send_blocks_and_test([block], node) del block node.setmocktime(2**48 - 1) # biggest possible 48-bit number block_template = node.getblocktemplate() assert_equal(block_template['curtime'], 2**48 - 1) block = self.block_from_template(block_template) block.nTime = 2**48 - 1 prepare_block(block) node.p2p.send_blocks_and_test([block], node) del block