def run_test(self): node0 = self.nodes[0] node1 = self.nodes[1] node0.importprivkey(mandatory_privkey) self.log.info( "generatetoaddress: Making blocks of various kinds, checking for rejection" ) # Create valid blocks to get out of IBD and get some funds (subsidy goes to permitted addr) node0.generatetoaddress(101, mandatory_address) # Generating for another address will not work assert_raises_rpc_error( -1, "CreateNewBlock: TestBlockValidity failed: bad-coinbase-txos", node0.generatetoaddress, 1, node0.getnewaddress()) # Have non-mandatory node make a template self.sync_all() tmpl = node1.getblocktemplate() # We make a block with OP_TRUE coinbase output that will fail on node0 coinbase_tx = create_coinbase(height=int(tmpl["height"])) # sequence numbers must not be max for nLockTime to have effect coinbase_tx.vin[0].nSequence = 2**32 - 2 coinbase_tx.rehash() block = CBlock() block.nVersion = tmpl["version"] block.hashPrevBlock = int(tmpl["previousblockhash"], 16) block.nTime = tmpl["curtime"] block.nBits = int(tmpl["bits"], 16) block.nNonce = 0 block.proof = CProof(bytearray.fromhex('51')) block.vtx = [coinbase_tx] block.block_height = int(tmpl["height"]) block.hashMerkleRoot = block.calc_merkle_root() self.log.info("getblocktemplate: Test block on both nodes") assert_template(node1, block, None) assert_template(node0, block, 'bad-coinbase-txos') self.log.info("getblocktemplate: Test non-subsidy block on both nodes") # Without block reward anything goes, this allows commitment outputs like segwit coinbase_tx.vout[0].nValue = CTxOutValue(0) coinbase_tx.vout[0].scriptPubKey = CScript([OP_RETURN, b'\xff']) coinbase_tx.rehash() block.vtx = [coinbase_tx] assert_template(node0, block, None) assert_template(node1, block, None) # # Also test that coinbases can't have fees. self.sync_all() tmpl = node1.getblocktemplate() coinbase_tx = create_coinbase(height=int(tmpl["height"])) # sequence numbers must not be max for nLockTime to have effect coinbase_tx.vin[0].nSequence = 2**32 - 2 # Add fee output. coinbase_tx.vout[0].nValue.setToAmount( coinbase_tx.vout[0].nValue.getAmount() - 1) coinbase_tx.vout.append(CTxOut(1)) coinbase_tx.rehash() block = CBlock() block.nVersion = tmpl["version"] block.hashPrevBlock = int(tmpl["previousblockhash"], 16) block.nTime = tmpl["curtime"] block.nBits = int(tmpl["bits"], 16) block.nNonce = 0 block.proof = CProof(bytearray.fromhex('51')) block.vtx = [coinbase_tx] block.block_height = int(tmpl["height"]) block.hashMerkleRoot = block.calc_merkle_root() # should not be accepted assert_template(node0, block, "bad-cb-fee") assert_template(node1, block, "bad-cb-fee")
def run_test(self): node = self.nodes[0] def assert_submitblock(block, result_str_1, result_str_2=None): block.solve() result_str_2 = result_str_2 or 'duplicate-invalid' assert_equal(result_str_1, node.submitblock(hexdata=b2x(block.serialize()))) assert_equal(result_str_2, node.submitblock(hexdata=b2x(block.serialize()))) self.log.info('getmininginfo') mining_info = node.getmininginfo() assert_equal(mining_info['blocks'], 200) assert_equal(mining_info['chain'], self.chain) assert_equal(mining_info['currentblocktx'], 0) assert_equal(mining_info['currentblockweight'], 0) assert_equal(mining_info['pooledtx'], 0) # Mine a block to leave initial block download node.generate(1) tmpl = node.getblocktemplate() self.log.info("getblocktemplate: Test capability advertised") assert 'proposal' in tmpl['capabilities'] assert 'coinbasetxn' not in tmpl coinbase_tx = create_coinbase(height=int(tmpl["height"]) + 1) # sequence numbers must not be max for nLockTime to have effect coinbase_tx.vin[0].nSequence = 2**32 - 2 coinbase_tx.rehash() block = CBlock() block.nVersion = tmpl["version"] block.hashPrevBlock = int(tmpl["previousblockhash"], 16) block.nTime = tmpl["curtime"] block.block_height = node.getblockcount() + 1 block.nBits = 0 block.nNonce = 0 block.vtx = [coinbase_tx] self.log.info("getblocktemplate: Test valid block") assert_template(node, block, None) self.log.info("submitblock: Test block decode failure") assert_raises_rpc_error(-22, "Block decode failed", node.submitblock, b2x(block.serialize()[:-15])) self.log.info( "getblocktemplate: Test bad input hash for coinbase transaction") bad_block = copy.deepcopy(block) bad_block.vtx[0].vin[0].prevout.hash += 1 bad_block.vtx[0].rehash() assert_template(node, bad_block, 'bad-cb-missing') self.log.info("submitblock: Test invalid coinbase transaction") assert_raises_rpc_error(-22, "Block does not start with a coinbase", node.submitblock, b2x(bad_block.serialize())) self.log.info("getblocktemplate: Test truncated final transaction") assert_raises_rpc_error(-22, "Block decode failed", node.getblocktemplate, { 'data': b2x(block.serialize()[:-1]), 'mode': 'proposal' }) self.log.info("getblocktemplate: Test duplicate transaction") bad_block = copy.deepcopy(block) bad_block.vtx.append(bad_block.vtx[0]) assert_template(node, bad_block, 'bad-txns-duplicate') assert_submitblock(bad_block, 'bad-txns-duplicate', 'bad-txns-duplicate') self.log.info("getblocktemplate: Test invalid transaction") bad_block = copy.deepcopy(block) bad_tx = copy.deepcopy(bad_block.vtx[0]) bad_tx.vin[0].prevout.hash = 255 bad_tx.rehash() bad_block.vtx.append(bad_tx) assert_template(node, bad_block, 'bad-txns-inputs-missingorspent') assert_submitblock(bad_block, 'bad-txns-inputs-missingorspent') self.log.info("getblocktemplate: Test nonfinal transaction") bad_block = copy.deepcopy(block) bad_block.vtx[0].nLockTime = 2**32 - 1 bad_block.vtx[0].rehash() assert_template(node, bad_block, 'bad-txns-nonfinal') assert_submitblock(bad_block, 'bad-txns-nonfinal') self.log.info("getblocktemplate: Test bad tx count") # The tx count is immediately after the block header TX_COUNT_OFFSET = len(super(CBlock, block).serialize()) bad_block_sn = bytearray(block.serialize()) assert_equal(bad_block_sn[TX_COUNT_OFFSET], 1) bad_block_sn[TX_COUNT_OFFSET] += 1 assert_raises_rpc_error(-22, "Block decode failed", node.getblocktemplate, { 'data': b2x(bad_block_sn), 'mode': 'proposal' }) # No PoW test # self.log.info("getblocktemplate: Test bad bits") # bad_block = copy.deepcopy(block) # bad_block.nBits = 469762303 # impossible in the real world # assert_template(node, bad_block, 'bad-diffbits') self.log.info("getblocktemplate: Test bad merkle root") bad_block = copy.deepcopy(block) bad_block.hashMerkleRoot += 1 assert_template(node, bad_block, 'bad-txnmrklroot', False) assert_submitblock(bad_block, 'bad-txnmrklroot', 'bad-txnmrklroot') self.log.info("getblocktemplate: Test bad timestamps") bad_block = copy.deepcopy(block) bad_block.nTime = 2**31 - 1 assert_template(node, bad_block, 'time-too-new') assert_submitblock(bad_block, 'time-too-new', 'time-too-new') bad_block.nTime = 0 assert_template(node, bad_block, 'time-too-old') assert_submitblock(bad_block, 'time-too-old', 'time-too-old') self.log.info("getblocktemplate: Test not best block") bad_block = copy.deepcopy(block) bad_block.hashPrevBlock = 123 assert_template(node, bad_block, 'inconclusive-not-best-prevblk') assert_submitblock(bad_block, 'prev-blk-not-found', 'prev-blk-not-found') self.log.info('submitheader tests') assert_raises_rpc_error( -22, 'Block header decode failed', lambda: node.submitheader(hexdata='xx' * TX_COUNT_OFFSET)) assert_raises_rpc_error( -22, 'Block header decode failed', lambda: node.submitheader(hexdata='ff' * (TX_COUNT_OFFSET - 2))) assert_raises_rpc_error( -25, 'Must submit previous header', lambda: node.submitheader( hexdata=super(CBlock, bad_block).serialize().hex())) block.nTime += 1 block.solve() def chain_tip(b_hash, *, status='headers-only', branchlen=1): return { 'hash': b_hash, 'height': 202, 'branchlen': branchlen, 'status': status } assert chain_tip(block.hash) not in node.getchaintips() node.submitheader(hexdata=b2x(block.serialize())) assert chain_tip(block.hash) in node.getchaintips() node.submitheader(hexdata=b2x(CBlockHeader(block).serialize())) # Noop assert chain_tip(block.hash) in node.getchaintips() bad_block_root = copy.deepcopy(block) bad_block_root.hashMerkleRoot += 2 bad_block_root.solve() assert chain_tip(bad_block_root.hash) not in node.getchaintips() node.submitheader( hexdata=b2x(CBlockHeader(bad_block_root).serialize())) assert chain_tip(bad_block_root.hash) in node.getchaintips() # Should still reject invalid blocks, even if we have the header: assert_equal(node.submitblock(hexdata=b2x(bad_block_root.serialize())), 'bad-txnmrklroot') assert_equal(node.submitblock(hexdata=b2x(bad_block_root.serialize())), 'bad-txnmrklroot') assert chain_tip(bad_block_root.hash) in node.getchaintips() # We know the header for this invalid block, so should just return early without error: node.submitheader( hexdata=b2x(CBlockHeader(bad_block_root).serialize())) assert chain_tip(bad_block_root.hash) in node.getchaintips() bad_block_lock = copy.deepcopy(block) bad_block_lock.vtx[0].nLockTime = 2**32 - 1 bad_block_lock.vtx[0].rehash() bad_block_lock.hashMerkleRoot = bad_block_lock.calc_merkle_root() bad_block_lock.solve() assert_equal(node.submitblock(hexdata=b2x(bad_block_lock.serialize())), 'bad-txns-nonfinal') assert_equal(node.submitblock(hexdata=b2x(bad_block_lock.serialize())), 'duplicate-invalid') # Build a "good" block on top of the submitted bad block bad_block2 = copy.deepcopy(block) bad_block2.hashPrevBlock = bad_block_lock.sha256 bad_block2.solve() assert_raises_rpc_error( -25, 'bad-prevblk', lambda: node.submitheader(hexdata=b2x( CBlockHeader(bad_block2).serialize()))) # Should reject invalid header right away bad_block_time = copy.deepcopy(block) bad_block_time.nTime = 1 bad_block_time.solve() assert_raises_rpc_error( -25, 'time-too-old', lambda: node.submitheader(hexdata=b2x( CBlockHeader(bad_block_time).serialize()))) # Should ask for the block from a p2p node, if they announce the header as well: node.add_p2p_connection(P2PDataStore()) node.p2p.wait_for_getheaders(timeout=5) # Drop the first getheaders node.p2p.send_blocks_and_test(blocks=[block], node=node) # Must be active now: assert chain_tip(block.hash, status='active', branchlen=0) in node.getchaintips() # Building a few blocks should give the same results node.generate(10) assert_raises_rpc_error( -25, 'time-too-old', lambda: node.submitheader(hexdata=b2x( CBlockHeader(bad_block_time).serialize()))) assert_raises_rpc_error( -25, 'bad-prevblk', lambda: node.submitheader(hexdata=b2x( CBlockHeader(bad_block2).serialize()))) node.submitheader(hexdata=b2x(CBlockHeader(block).serialize())) node.submitheader( hexdata=b2x(CBlockHeader(bad_block_root).serialize())) assert_equal(node.submitblock(hexdata=b2x(block.serialize())), 'duplicate') # valid
def run_test(self): node = self.nodes[0] def assert_submitblock(block, result_str_1, result_str_2=None): block.solve() result_str_2 = result_str_2 or 'duplicate-invalid' assert_equal(result_str_1, node.submitblock(hexdata=b2x(block.serialize()))) assert_equal(result_str_2, node.submitblock(hexdata=b2x(block.serialize()))) self.log.info('getmininginfo') mining_info = node.getmininginfo() assert_equal(mining_info['blocks'], 200) assert_equal(mining_info['chain'], self.chain) assert_equal(mining_info['currentblocktx'], 0) assert_equal(mining_info['currentblockweight'], 0) assert_equal(mining_info['pooledtx'], 0) # Mine a block to leave initial block download node.generate(1) tmpl = node.getblocktemplate() self.log.info("getblocktemplate: Test capability advertised") assert 'proposal' in tmpl['capabilities'] assert 'coinbasetxn' not in tmpl coinbase_tx = create_coinbase(height=int(tmpl["height"]) + 1) # sequence numbers must not be max for nLockTime to have effect coinbase_tx.vin[0].nSequence = 2 ** 32 - 2 coinbase_tx.rehash() block = CBlock() block.nVersion = tmpl["version"] block.hashPrevBlock = int(tmpl["previousblockhash"], 16) block.nTime = tmpl["curtime"] block.block_height = node.getblockcount()+1 block.nBits = 0 block.nNonce = 0 block.vtx = [coinbase_tx] self.log.info("getblocktemplate: Test valid block") assert_template(node, block, None) self.log.info("submitblock: Test block decode failure") assert_raises_rpc_error(-22, "Block decode failed", node.submitblock, b2x(block.serialize()[:-15])) self.log.info("getblocktemplate: Test bad input hash for coinbase transaction") bad_block = copy.deepcopy(block) bad_block.vtx[0].vin[0].prevout.hash += 1 bad_block.vtx[0].rehash() assert_template(node, bad_block, 'bad-cb-missing') self.log.info("submitblock: Test invalid coinbase transaction") assert_raises_rpc_error(-22, "Block does not start with a coinbase", node.submitblock, b2x(bad_block.serialize())) self.log.info("getblocktemplate: Test truncated final transaction") assert_raises_rpc_error(-22, "Block decode failed", node.getblocktemplate, {'data': b2x(block.serialize()[:-1]), 'mode': 'proposal'}) self.log.info("getblocktemplate: Test duplicate transaction") bad_block = copy.deepcopy(block) bad_block.vtx.append(bad_block.vtx[0]) assert_template(node, bad_block, 'bad-txns-duplicate') assert_submitblock(bad_block, 'bad-txns-duplicate', 'bad-txns-duplicate') self.log.info("getblocktemplate: Test invalid transaction") bad_block = copy.deepcopy(block) bad_tx = copy.deepcopy(bad_block.vtx[0]) bad_tx.vin[0].prevout.hash = 255 bad_tx.rehash() bad_block.vtx.append(bad_tx) assert_template(node, bad_block, 'bad-txns-inputs-missingorspent') assert_submitblock(bad_block, 'bad-txns-inputs-missingorspent') self.log.info("getblocktemplate: Test nonfinal transaction") bad_block = copy.deepcopy(block) bad_block.vtx[0].nLockTime = 2 ** 32 - 1 bad_block.vtx[0].rehash() assert_template(node, bad_block, 'bad-txns-nonfinal') assert_submitblock(bad_block, 'bad-txns-nonfinal') self.log.info("getblocktemplate: Test bad tx count") # The tx count is immediately after the block header TX_COUNT_OFFSET = len(super(CBlock, block).serialize()) bad_block_sn = bytearray(block.serialize()) assert_equal(bad_block_sn[TX_COUNT_OFFSET], 1) bad_block_sn[TX_COUNT_OFFSET] += 1 assert_raises_rpc_error(-22, "Block decode failed", node.getblocktemplate, {'data': b2x(bad_block_sn), 'mode': 'proposal'}) # No PoW test # self.log.info("getblocktemplate: Test bad bits") # bad_block = copy.deepcopy(block) # bad_block.nBits = 469762303 # impossible in the real world # assert_template(node, bad_block, 'bad-diffbits') self.log.info("getblocktemplate: Test bad merkle root") bad_block = copy.deepcopy(block) bad_block.hashMerkleRoot += 1 assert_template(node, bad_block, 'bad-txnmrklroot', False) assert_submitblock(bad_block, 'bad-txnmrklroot', 'bad-txnmrklroot') self.log.info("getblocktemplate: Test bad timestamps") bad_block = copy.deepcopy(block) bad_block.nTime = 2 ** 31 - 1 assert_template(node, bad_block, 'time-too-new') assert_submitblock(bad_block, 'time-too-new', 'time-too-new') bad_block.nTime = 0 assert_template(node, bad_block, 'time-too-old') assert_submitblock(bad_block, 'time-too-old', 'time-too-old') self.log.info("getblocktemplate: Test not best block") bad_block = copy.deepcopy(block) bad_block.hashPrevBlock = 123 assert_template(node, bad_block, 'inconclusive-not-best-prevblk') assert_submitblock(bad_block, 'prev-blk-not-found', 'prev-blk-not-found') self.log.info('submitheader tests') assert_raises_rpc_error(-22, 'Block header decode failed', lambda: node.submitheader(hexdata='xx' * TX_COUNT_OFFSET)) assert_raises_rpc_error(-22, 'Block header decode failed', lambda: node.submitheader(hexdata='ff' * (TX_COUNT_OFFSET-2))) assert_raises_rpc_error(-25, 'Must submit previous header', lambda: node.submitheader(hexdata=super(CBlock, bad_block).serialize().hex())) block.nTime += 1 block.solve() def chain_tip(b_hash, *, status='headers-only', branchlen=1): return {'hash': b_hash, 'height': 202, 'branchlen': branchlen, 'status': status} assert chain_tip(block.hash) not in node.getchaintips() node.submitheader(hexdata=b2x(block.serialize())) assert chain_tip(block.hash) in node.getchaintips() node.submitheader(hexdata=b2x(CBlockHeader(block).serialize())) # Noop assert chain_tip(block.hash) in node.getchaintips() bad_block_root = copy.deepcopy(block) bad_block_root.hashMerkleRoot += 2 bad_block_root.solve() assert chain_tip(bad_block_root.hash) not in node.getchaintips() node.submitheader(hexdata=b2x(CBlockHeader(bad_block_root).serialize())) assert chain_tip(bad_block_root.hash) in node.getchaintips() # Should still reject invalid blocks, even if we have the header: assert_equal(node.submitblock(hexdata=b2x(bad_block_root.serialize())), 'bad-txnmrklroot') assert_equal(node.submitblock(hexdata=b2x(bad_block_root.serialize())), 'bad-txnmrklroot') assert chain_tip(bad_block_root.hash) in node.getchaintips() # We know the header for this invalid block, so should just return early without error: node.submitheader(hexdata=b2x(CBlockHeader(bad_block_root).serialize())) assert chain_tip(bad_block_root.hash) in node.getchaintips() bad_block_lock = copy.deepcopy(block) bad_block_lock.vtx[0].nLockTime = 2**32 - 1 bad_block_lock.vtx[0].rehash() bad_block_lock.hashMerkleRoot = bad_block_lock.calc_merkle_root() bad_block_lock.solve() assert_equal(node.submitblock(hexdata=b2x(bad_block_lock.serialize())), 'bad-txns-nonfinal') assert_equal(node.submitblock(hexdata=b2x(bad_block_lock.serialize())), 'duplicate-invalid') # Build a "good" block on top of the submitted bad block bad_block2 = copy.deepcopy(block) bad_block2.hashPrevBlock = bad_block_lock.sha256 bad_block2.solve() assert_raises_rpc_error(-25, 'bad-prevblk', lambda: node.submitheader(hexdata=b2x(CBlockHeader(bad_block2).serialize()))) # Should reject invalid header right away bad_block_time = copy.deepcopy(block) bad_block_time.nTime = 1 bad_block_time.solve() assert_raises_rpc_error(-25, 'time-too-old', lambda: node.submitheader(hexdata=b2x(CBlockHeader(bad_block_time).serialize()))) # Should ask for the block from a p2p node, if they announce the header as well: node.add_p2p_connection(P2PDataStore()) node.p2p.wait_for_getheaders(timeout=5) # Drop the first getheaders node.p2p.send_blocks_and_test(blocks=[block], node=node) # Must be active now: assert chain_tip(block.hash, status='active', branchlen=0) in node.getchaintips() # Building a few blocks should give the same results node.generate(10) assert_raises_rpc_error(-25, 'time-too-old', lambda: node.submitheader(hexdata=b2x(CBlockHeader(bad_block_time).serialize()))) assert_raises_rpc_error(-25, 'bad-prevblk', lambda: node.submitheader(hexdata=b2x(CBlockHeader(bad_block2).serialize()))) node.submitheader(hexdata=b2x(CBlockHeader(block).serialize())) node.submitheader(hexdata=b2x(CBlockHeader(bad_block_root).serialize())) assert_equal(node.submitblock(hexdata=b2x(block.serialize())), 'duplicate') # valid
def run_test(self): # Block will have 10 satoshi output, node 1 will ban addr = self.nodes[0].getnewaddress() sub_block = self.nodes[0].generatetoaddress(1, addr) raw_coinbase = self.nodes[0].getrawtransaction( self.nodes[0].getblock(sub_block[0])["tx"][0], False, sub_block[0]) decoded_coinbase = self.nodes[0].decoderawtransaction(raw_coinbase) found_ten = False for vout in decoded_coinbase["vout"]: if vout["value"] == Decimal('0.00000010') and found_ten == False: found_ten = True elif vout["value"] == 0: continue else: raise Exception("Invalid output amount in coinbase") assert (found_ten) # Block will have 0 satoshis outputs only at height 1 no_sub_block = self.nodes[1].generatetoaddress(1, addr) raw_coinbase = self.nodes[1].getrawtransaction( self.nodes[1].getblock(no_sub_block[0])["tx"][0], False, no_sub_block[0]) decoded_coinbase = self.nodes[1].decoderawtransaction(raw_coinbase) for vout in decoded_coinbase["vout"]: if vout["value"] != 0: raise Exception("Invalid output amount in coinbase") tmpl = self.nodes[0].getblocktemplate({"rules": ["segwit"]}) # Template with invalid amount(50*COIN) will be invalid in both coinbase_tx = create_coinbase(height=int(tmpl["height"])) block = CBlock() block.nVersion = tmpl["version"] block.hashPrevBlock = int(tmpl["previousblockhash"], 16) block.nTime = tmpl["curtime"] block.nBits = int(tmpl["bits"], 16) block.nNonce = 0 block.block_height = int(tmpl["height"]) block.proof = CProof(bytearray.fromhex('51')) block.vtx = [coinbase_tx] assert_template(self.nodes[0], block, "bad-cb-amount") # Set to proper value, resubmit block.vtx[0].vout[0].nValue = CTxOutValue(10) block.vtx[0].sha256 = None assert_template(self.nodes[0], block, None) # No subsidy also allowed block.vtx[0].vout[0].nValue = CTxOutValue(0) block.vtx[0].sha256 = None #assert_template(self.nodes[0], block, None) # ELEMENTS: 0-value outputs not allowed # Change previous blockhash to other nodes' genesis block and reward to 1, test again block.hashPrevBlock = int( self.nodes[1].getblockhash(self.nodes[1].getblockcount()), 16) block.vtx[0].vout[0].nValue = CTxOutValue(1) block.vtx[0].sha256 = None assert_template(self.nodes[1], block, "bad-cb-amount") block.vtx[0].vout[0].nValue = CTxOutValue(0) block.vtx[0].sha256 = None
def run_test(self): # Block will have 10 satoshi output, node 1 will ban addr = self.nodes[0].getnewaddress() sub_block = self.nodes[0].generatetoaddress(1, addr) raw_coinbase = self.nodes[0].getrawtransaction(self.nodes[0].getblock(sub_block[0])["tx"][0]) decoded_coinbase = self.nodes[0].decoderawtransaction(raw_coinbase) found_ten = False for vout in decoded_coinbase["vout"]: if vout["value"] == Decimal('0.00000010') and found_ten == False: found_ten = True elif vout["value"] == 0: continue else: raise Exception("Invalid output amount in coinbase") assert(found_ten) # Block will have 0 satoshis outputs only at height 1 no_sub_block = self.nodes[1].generatetoaddress(1, addr) raw_coinbase = self.nodes[1].getrawtransaction(self.nodes[1].getblock(no_sub_block[0])["tx"][0]) decoded_coinbase = self.nodes[1].decoderawtransaction(raw_coinbase) for vout in decoded_coinbase["vout"]: if vout["value"] != 0: raise Exception("Invalid output amount in coinbase") tmpl = self.nodes[0].getblocktemplate() # Template with invalid amount(50*COIN) will be invalid in both coinbase_tx = create_coinbase(height=int(tmpl["height"])) block = CBlock() block.nVersion = tmpl["version"] block.hashPrevBlock = int(tmpl["previousblockhash"], 16) block.nTime = tmpl["curtime"] block.nBits = int(tmpl["bits"], 16) block.nNonce = 0 block.block_height = int(tmpl["height"]) block.proof = CProof(bytearray.fromhex('51')) block.vtx = [coinbase_tx] assert_template(self.nodes[0], block, "bad-cb-amount") # Set to proper value, resubmit block.vtx[0].vout[0].nValue = CTxOutValue(10) block.vtx[0].sha256 = None assert_template(self.nodes[0], block, None) # No subsidy also allowed block.vtx[0].vout[0].nValue = CTxOutValue(0) block.vtx[0].sha256 = None #assert_template(self.nodes[0], block, None) # ELEMENTS: 0-value outputs not allowed # Change previous blockhash to other nodes' genesis block and reward to 1, test again block.hashPrevBlock = int(self.nodes[1].getblockhash(self.nodes[1].getblockcount()), 16) block.vtx[0].vout[0].nValue = CTxOutValue(1) block.vtx[0].sha256 = None assert_template(self.nodes[1], block, "bad-cb-amount") block.vtx[0].vout[0].nValue = CTxOutValue(0) block.vtx[0].sha256 = None