diff --git a/test/functional/feature_nulldummy.py b/test/functional/feature_nulldummy.py --- a/test/functional/feature_nulldummy.py +++ b/test/functional/feature_nulldummy.py @@ -1,15 +1,16 @@ #!/usr/bin/env python3 # Copyright (c) 2016 The Bitcoin Core developers +# Copyright (c) 2019 The Bitcoin developers # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. from test_framework.test_framework import BitcoinTestFramework -from test_framework.util import * -from test_framework.mininode import CTransaction, network_thread_start -from test_framework.blocktools import create_coinbase, create_block +from test_framework.util import hex_str_to_bytes, bytes_to_hex_str, assert_equal, assert_raises_rpc_error +from test_framework.messages import ToHex +from test_framework.mininode import CTransaction +from test_framework.blocktools import create_coinbase, create_block, make_conform_to_ctor from test_framework.script import CScript from io import BytesIO -import time NULLDUMMY_ERROR = "64: non-mandatory-script-verify-flag (Dummy CHECKMULTISIG argument must be zero)" @@ -27,15 +28,23 @@ tx.rehash() +def fetch_best_header(node): + return BlockHeader(node.getblockheader(node.getbestblockhash())) + + +class BlockHeader: + def __init__(self, header): + self.header = header + + def __getattr__(self, name): + return self.header[name] + + def hash_as_int(self): + return int(self.hash, 16) + + ''' -This test is meant to exercise NULLDUMMY softfork. -Connect to a single node. -Generate 2 blocks (save the coinbases for later). -Generate 427 more blocks. -[Policy/Consensus] Check that NULLDUMMY compliant transactions are accepted in the 430th block. -[Policy] Check that non-NULLDUMMY transactions are rejected before activation. -[Consensus] Check that the new NULLDUMMY rules are not enforced on the 431st block. -[Policy/Consensus] Check that the new NULLDUMMY rules are enforced on the 432nd block. +This test is meant to exercise that NULLDUMMY exists as a standardness rule. ''' @@ -45,45 +54,43 @@ self.num_nodes = 1 self.setup_clean_chain = True self.extra_args = [['-whitelist=127.0.0.1']] + self.lastblock = None def run_test(self): - self.address = self.nodes[0].getnewaddress() - self.ms_address = self.nodes[0].addmultisigaddress(1, [self.address]) + node = self.nodes[0] + self.address = node.getnewaddress() + self.ms_address = node.addmultisigaddress(1, [self.address]) - network_thread_start() - self.coinbase_blocks = self.nodes[0].generate(2) # Block 2 + # Create and mature coinbases for spending coinbase_txid = [] - for i in self.coinbase_blocks: - coinbase_txid.append(self.nodes[0].getblock(i)['tx'][0]) - self.nodes[0].generate(427) # Block 429 - self.lastblockhash = self.nodes[0].getbestblockhash() - self.tip = int("0x" + self.lastblockhash, 0) - self.lastblockheight = 429 - self.lastblocktime = int(time.time()) + 429 + for block in node.generate(2): + coinbase_txid.append(node.getblock(block)['tx'][0]) + node.generate(101) + + self.lastblock = fetch_best_header(node) self.log.info( - "Test 1: NULLDUMMY compliant base transactions should be accepted to mempool and mined before activation [430]") - test1txs = [self.create_transaction( - self.nodes[0], coinbase_txid[0], self.ms_address, 49)] - txid1 = self.nodes[0].sendrawtransaction( - bytes_to_hex_str(test1txs[0].serialize()), True) + "Test 1: [Policy/Consensus] NULLDUMMY compliant base transactions should be accepted to mempool and mined") + test1txs = [] + test1txs.append(self.create_transaction( + node, coinbase_txid[0], self.ms_address, 49)) + txid1 = node.sendrawtransaction(ToHex(test1txs[0]), True) test1txs.append(self.create_transaction( - self.nodes[0], txid1, self.ms_address, 48)) - txid2 = self.nodes[0].sendrawtransaction( - bytes_to_hex_str(test1txs[1].serialize()), True) - self.block_submit(self.nodes[0], test1txs, True) + node, txid1, self.ms_address, 48)) + txid2 = node.sendrawtransaction(ToHex(test1txs[1]), True) + self.block_submit(node, test1txs, True) self.log.info( - "Test 2: Non-NULLDUMMY base multisig transaction should not be accepted to mempool before activation") + "Test 2: [Policy] Non-NULLDUMMY base multisig transaction should not be accepted to mempool") test2tx = self.create_transaction( - self.nodes[0], txid2, self.ms_address, 48) + node, txid2, self.ms_address, 48) trueDummy(test2tx) assert_raises_rpc_error(-26, NULLDUMMY_ERROR, - self.nodes[0].sendrawtransaction, bytes_to_hex_str(test2tx.serialize()), True) + node.sendrawtransaction, bytes_to_hex_str(test2tx.serialize()), True) self.log.info( - "Test 3: Non-NULLDUMMY base transactions should be accepted in a block before activation [431]") - self.block_submit(self.nodes[0], [test2tx], True) + "Test 3: [Consensus] Non-NULLDUMMY base transactions should be accepted in a block") + self.block_submit(node, [test2tx], True) def create_transaction(self, node, txid, to_address, amount): inputs = [{"txid": txid, "vout": 0}] @@ -96,26 +103,20 @@ return tx def block_submit(self, node, txs, accept=False): - block = create_block(self.tip, create_coinbase( - self.lastblockheight + 1), self.lastblocktime + 1) + block = create_block(self.lastblock.hash_as_int(), create_coinbase( + self.lastblock.height + 1), self.lastblock.time + 1) block.nVersion = 4 - for tx in txs: - tx.rehash() - block.vtx.append(tx) - block.vtx = [block.vtx[0]] + \ - sorted(block.vtx[1:], key=lambda tx: tx.get_id()) + block.vtx.extend(txs) + make_conform_to_ctor(block) block.hashMerkleRoot = block.calc_merkle_root() block.rehash() block.solve() node.submitblock(bytes_to_hex_str(block.serialize())) if (accept): assert_equal(node.getbestblockhash(), block.hash) - self.tip = block.sha256 - self.lastblockhash = block.hash - self.lastblocktime += 1 - self.lastblockheight += 1 + self.lastblock = fetch_best_header(node) else: - assert_equal(node.getbestblockhash(), self.lastblockhash) + assert_equal(node.getbestblockhash(), self.lastblock.hash) if __name__ == '__main__':