Changeset View
Changeset View
Standalone View
Standalone View
test/functional/feature_tx_version.py
Show All 18 Lines | |||||
) | ) | ||||
from test_framework.messages import CBlock, FromHex | from test_framework.messages import CBlock, FromHex | ||||
from test_framework.p2p import P2PDataStore | from test_framework.p2p import P2PDataStore | ||||
from test_framework.test_framework import BitcoinTestFramework | from test_framework.test_framework import BitcoinTestFramework | ||||
from test_framework.txtools import pad_tx | from test_framework.txtools import pad_tx | ||||
from test_framework.util import assert_equal, assert_greater_than_or_equal | from test_framework.util import assert_equal, assert_greater_than_or_equal | ||||
OK_VERSIONS = [1, 2] | OK_VERSIONS = [1, 2] | ||||
BAD_VERSIONS = [-0x80000000, -0x7fffffff, -2, -1, 0, 3, 7, 0x100, 0x7fffffff] | BAD_VERSIONS = [-0x80000000, -0x7FFFFFFF, -2, -1, 0, 3, 7, 0x100, 0x7FFFFFFF] | ||||
START_TIME = 1_900_000_000 | START_TIME = 1_900_000_000 | ||||
ACTIVATION_TIME = 2_000_000_000 | ACTIVATION_TIME = 2_000_000_000 | ||||
class TxVersionTest(BitcoinTestFramework): | class TxVersionTest(BitcoinTestFramework): | ||||
def set_test_params(self): | def set_test_params(self): | ||||
self.num_nodes = 1 | self.num_nodes = 1 | ||||
self.setup_clean_chain = True | self.setup_clean_chain = True | ||||
self.extra_args = [[f'-wellingtonactivationtime={ACTIVATION_TIME}', | self.extra_args = [ | ||||
'-acceptnonstdtxn=0', | [ | ||||
'-whitelist=127.0.0.1']] | f"-wellingtonactivationtime={ACTIVATION_TIME}", | ||||
"-acceptnonstdtxn=0", | |||||
"-whitelist=127.0.0.1", | |||||
] | |||||
] | |||||
def run_test(self): | def run_test(self): | ||||
self.block_heights = {} | self.block_heights = {} | ||||
node = self.nodes[0] | node = self.nodes[0] | ||||
node.setmocktime(START_TIME) | node.setmocktime(START_TIME) | ||||
peer = node.add_p2p_connection(P2PDataStore()) | peer = node.add_p2p_connection(P2PDataStore()) | ||||
Show All 18 Lines | def run_test(self): | ||||
def test_mempool_rejects_bad_versions(): | def test_mempool_rejects_bad_versions(): | ||||
bad_version_txs = [] | bad_version_txs = [] | ||||
for bad_version in BAD_VERSIONS: | for bad_version in BAD_VERSIONS: | ||||
spendable_tx = spendable_txs.pop(0) | spendable_tx = spendable_txs.pop(0) | ||||
tx = self.make_tx(spendable_tx, nVersion=bad_version) | tx = self.make_tx(spendable_tx, nVersion=bad_version) | ||||
bad_version_txs.append(tx) | bad_version_txs.append(tx) | ||||
peer.send_txs_and_test( | peer.send_txs_and_test( | ||||
[tx], | [tx], node, success=False, reject_reason="was not accepted: version" | ||||
node, | ) | ||||
success=False, | |||||
reject_reason="was not accepted: version") | |||||
return bad_version_txs | return bad_version_txs | ||||
self.log.info("These are always OK for the mempool") | self.log.info("These are always OK for the mempool") | ||||
test_mempool_accepts_ok_versions() | test_mempool_accepts_ok_versions() | ||||
self.log.info("Bad versions always rejected from mempool") | self.log.info("Bad versions always rejected from mempool") | ||||
bad_version_txs = test_mempool_rejects_bad_versions() | bad_version_txs = test_mempool_rejects_bad_versions() | ||||
self.log.info( | self.log.info( | ||||
"Before Wellington, we CAN mine blocks with txs with bad versions") | "Before Wellington, we CAN mine blocks with txs with bad versions" | ||||
) | |||||
block = self.make_block(blocks[-1], txs=bad_version_txs) | block = self.make_block(blocks[-1], txs=bad_version_txs) | ||||
peer.send_blocks_and_test([block], node, success=True) | peer.send_blocks_and_test([block], node, success=True) | ||||
blocks.append(block) | blocks.append(block) | ||||
self.log.info( | self.log.info( | ||||
"Before Wellington, we CAN mine blocks with a coinbase with a bad " | "Before Wellington, we CAN mine blocks with a coinbase with a bad version" | ||||
"version") | ) | ||||
for bad_version in BAD_VERSIONS: | for bad_version in BAD_VERSIONS: | ||||
block = self.make_block(blocks[-1], coinbase_version=bad_version) | block = self.make_block(blocks[-1], coinbase_version=bad_version) | ||||
peer.send_blocks_and_test([block], node, success=True) | peer.send_blocks_and_test([block], node, success=True) | ||||
blocks.append(block) | blocks.append(block) | ||||
self.log.info( | self.log.info("Activate Wellington, mine 6 blocks starting at ACTIVATION_TIME") | ||||
"Activate Wellington, mine 6 blocks starting at ACTIVATION_TIME") | |||||
node.setmocktime(ACTIVATION_TIME) | node.setmocktime(ACTIVATION_TIME) | ||||
for offset in range(0, 6): | for offset in range(0, 6): | ||||
block = self.make_block( | block = self.make_block(blocks[-1], nTime=ACTIVATION_TIME + offset) | ||||
blocks[-1], nTime=ACTIVATION_TIME + offset) | |||||
peer.send_blocks_and_test([block], node, success=True) | peer.send_blocks_and_test([block], node, success=True) | ||||
blocks.append(block) | blocks.append(block) | ||||
assert_equal(node.getblockchaininfo()["mediantime"], ACTIVATION_TIME) | assert_equal(node.getblockchaininfo()["mediantime"], ACTIVATION_TIME) | ||||
self.log.info("Wellington activated!") | self.log.info("Wellington activated!") | ||||
self.log.info("Mempool still accepts OK versions") | self.log.info("Mempool still accepts OK versions") | ||||
test_mempool_accepts_ok_versions() | test_mempool_accepts_ok_versions() | ||||
self.log.info("Bad version still rejected from mempool") | self.log.info("Bad version still rejected from mempool") | ||||
bad_version_txs = test_mempool_rejects_bad_versions() | bad_version_txs = test_mempool_rejects_bad_versions() | ||||
self.log.info( | self.log.info( | ||||
"After activation, we CANNOT mine blocks with txs with bad " | "After activation, we CANNOT mine blocks with txs with bad versions anymore" | ||||
"versions anymore") | ) | ||||
for bad_tx in bad_version_txs: | for bad_tx in bad_version_txs: | ||||
block = self.make_block(blocks[-1], txs=[bad_tx]) | block = self.make_block(blocks[-1], txs=[bad_tx]) | ||||
peer.send_blocks_and_test( | peer.send_blocks_and_test( | ||||
[block], | [block], node, success=False, reject_reason="bad-txns-version" | ||||
node, | ) | ||||
success=False, | |||||
reject_reason="bad-txns-version") | |||||
self.log.info( | self.log.info( | ||||
"After activation, we CANNOT mine blocks with a coinbase with a " | "After activation, we CANNOT mine blocks with a coinbase with a " | ||||
"bad version anymore") | "bad version anymore" | ||||
) | |||||
for bad_version in BAD_VERSIONS: | for bad_version in BAD_VERSIONS: | ||||
block = self.make_block(blocks[-1], coinbase_version=bad_version) | block = self.make_block(blocks[-1], coinbase_version=bad_version) | ||||
peer.send_blocks_and_test( | peer.send_blocks_and_test( | ||||
[block], | [block], node, success=False, reject_reason="bad-txns-version" | ||||
node, | ) | ||||
success=False, | |||||
reject_reason="bad-txns-version") | |||||
def make_tx(self, spend_tx, nVersion): | def make_tx(self, spend_tx, nVersion): | ||||
value = spend_tx.vout[0].nValue - 1000 | value = spend_tx.vout[0].nValue - 1000 | ||||
assert_greater_than_or_equal(value, 546) | assert_greater_than_or_equal(value, 546) | ||||
tx = create_tx_with_script( | tx = create_tx_with_script( | ||||
spend_tx, 0, amount=value, script_pub_key=P2SH_OP_TRUE) | spend_tx, 0, amount=value, script_pub_key=P2SH_OP_TRUE | ||||
) | |||||
tx.nVersion = nVersion | tx.nVersion = nVersion | ||||
tx.vin[0].scriptSig = SCRIPTSIG_OP_TRUE | tx.vin[0].scriptSig = SCRIPTSIG_OP_TRUE | ||||
pad_tx(tx) | pad_tx(tx) | ||||
tx.rehash() | tx.rehash() | ||||
return tx | return tx | ||||
def make_block(self, prev_block: CBlock, *, nTime: Optional[int] = None, | def make_block( | ||||
coinbase_version=None, txs=None) -> CBlock: | self, | ||||
prev_block: CBlock, | |||||
*, | |||||
nTime: Optional[int] = None, | |||||
coinbase_version=None, | |||||
txs=None, | |||||
) -> CBlock: | |||||
if prev_block.sha256 is None: | if prev_block.sha256 is None: | ||||
prev_block.rehash() | prev_block.rehash() | ||||
assert prev_block.sha256 is not None | assert prev_block.sha256 is not None | ||||
block_time = prev_block.nTime + 1 if nTime is None else nTime | block_time = prev_block.nTime + 1 if nTime is None else nTime | ||||
height = self.block_heights.get(prev_block.sha256, 0) + 1 | height = self.block_heights.get(prev_block.sha256, 0) + 1 | ||||
coinbase = create_coinbase(height) | coinbase = create_coinbase(height) | ||||
coinbase.vout[0].scriptPubKey = P2SH_OP_TRUE | coinbase.vout[0].scriptPubKey = P2SH_OP_TRUE | ||||
if coinbase_version is not None: | if coinbase_version is not None: | ||||
coinbase.nVersion = coinbase_version | coinbase.nVersion = coinbase_version | ||||
coinbase.rehash() | coinbase.rehash() | ||||
block = create_block(prev_block.sha256, coinbase, block_time) | block = create_block(prev_block.sha256, coinbase, block_time) | ||||
if txs: | if txs: | ||||
block.vtx += txs | block.vtx += txs | ||||
make_conform_to_ctor(block) | make_conform_to_ctor(block) | ||||
block.hashMerkleRoot = block.calc_merkle_root() | block.hashMerkleRoot = block.calc_merkle_root() | ||||
block.solve() | block.solve() | ||||
self.block_heights[block.sha256] = height | self.block_heights[block.sha256] = height | ||||
return block | return block | ||||
if __name__ == '__main__': | if __name__ == "__main__": | ||||
TxVersionTest().main() | TxVersionTest().main() |