test: extend and refactor DIP0020 activation test

This commit is contained in:
UdjinM6 2024-10-01 17:10:04 +03:00
parent 3b9f9352a1
commit 04b5db9417
No known key found for this signature in database
GPG Key ID: 83592BD1400D58D9

View File

@ -2,7 +2,9 @@
# Copyright (c) 2015-2023 The Dash Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
from test_framework.blocktools import create_block, create_coinbase
from test_framework.messages import COIN, COutPoint, CTransaction, CTxIn, CTxOut
from test_framework.p2p import P2PDataStore
from test_framework.script import CScript, OP_CAT, OP_DROP, OP_TRUE
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import assert_raises_rpc_error, softfork_active, satoshi_round
@ -28,51 +30,99 @@ class DIP0020ActivationTest(BitcoinTestFramework):
def skip_test_if_missing_module(self):
self.skip_if_no_wallet()
def create_test_block(self, txs, tip_hash, tip_height, tip_time):
block = create_block(int(tip_hash, 16), create_coinbase(tip_height + 1), tip_time + 1)
block.nVersion = 4
block.vtx.extend(txs)
block.hashMerkleRoot = block.calc_merkle_root()
block.rehash()
block.solve()
return block
def run_test(self):
self.node = self.nodes[0]
self.relayfee = satoshi_round(self.nodes[0].getnetworkinfo()["relayfee"])
node = self.nodes[0]
relayfee = satoshi_round(node.getnetworkinfo()["relayfee"])
# We should have some coins already
utxos = self.node.listunspent()
utxos = node.listunspent()
assert len(utxos) > 0
# Lock some coins using disabled opcodes
utxo = utxos[len(utxos) - 1]
value = int(satoshi_round(utxo["amount"] - self.relayfee) * COIN)
value = int(satoshi_round(utxo["amount"] - relayfee) * COIN)
tx = CTransaction()
tx.vin.append(CTxIn(COutPoint(int(utxo["txid"], 16), utxo["vout"])))
tx.vout.append(CTxOut(value, CScript([b'1', b'2', OP_CAT])))
tx_signed_hex = self.node.signrawtransactionwithwallet(tx.serialize().hex())["hex"]
txid = self.node.sendrawtransaction(tx_signed_hex)
tx_signed_hex = node.signrawtransactionwithwallet(tx.serialize().hex())["hex"]
txid = node.sendrawtransaction(tx_signed_hex)
# This tx should be completely valid, should be included in mempool and mined in the next block
assert txid in set(self.node.getrawmempool())
self.node.generate(1)
assert txid not in set(self.node.getrawmempool())
assert txid in set(node.getrawmempool())
node.generate(1)
assert txid not in set(node.getrawmempool())
# Create spending tx
value = int(value - self.relayfee * COIN)
value = int(value - relayfee * COIN)
tx0 = CTransaction()
tx0.vin.append(CTxIn(COutPoint(int(txid, 16), 0)))
tx0.vout.append(CTxOut(value, CScript([OP_TRUE, OP_DROP] * 15 + [OP_TRUE])))
tx0.rehash()
tx0_hex = tx0.serialize().hex()
# This tx isn't valid yet
assert not softfork_active(self.nodes[0], 'dip0020')
assert_raises_rpc_error(-26, DISABLED_OPCODE_ERROR, self.node.sendrawtransaction, tx0_hex)
# flush state to disk before potential crashes below
self.nodes[0].gettxoutsetinfo()
# Generate enough blocks to activate DIP0020 opcodes
self.node.generate(98)
assert softfork_active(self.nodes[0], 'dip0020')
self.log.info("Transactions spending coins with new opcodes aren't accepted before DIP0020 activation")
assert not softfork_active(node, 'dip0020')
try:
assert_raises_rpc_error(-26, DISABLED_OPCODE_ERROR, node.sendrawtransaction, tx0_hex)
except:
self.start_node(0)
try:
helper_peer = node.add_p2p_connection(P2PDataStore())
helper_peer.send_txs_and_test([tx0], node, success=False, reject_reason=DISABLED_OPCODE_ERROR)
except:
self.start_node(0)
helper_peer = node.add_p2p_connection(P2PDataStore())
tip = node.getblock(node.getbestblockhash(), 1)
test_block = self.create_test_block([tx0], tip["hash"], tip["height"], tip["time"])
helper_peer.send_blocks_and_test([test_block], node, success=False, reject_reason='block-validation-failed', expect_disconnect=True)
# Still need 1 more block for mempool to accept new opcodes
assert_raises_rpc_error(-26, DISABLED_OPCODE_ERROR, self.node.sendrawtransaction, tx0_hex)
self.node.generate(1)
self.log.info("Generate enough blocks to activate DIP0020 opcodes")
node.generate(97)
assert not softfork_active(node, 'dip0020')
node.generate(1)
assert softfork_active(node, 'dip0020')
# Should be spendable now
tx0id = self.node.sendrawtransaction(tx0_hex)
assert tx0id in set(self.node.getrawmempool())
# flush state to disk before potential crashes below
self.nodes[0].gettxoutsetinfo()
# Still need 1 more block for mempool to accept txes spending new opcodes
self.log.info("Transactions spending coins with new opcodes aren't accepted at DIP0020 activation block")
try:
assert_raises_rpc_error(-26, DISABLED_OPCODE_ERROR, node.sendrawtransaction, tx0_hex)
except:
self.start_node(0)
try:
helper_peer = node.add_p2p_connection(P2PDataStore())
helper_peer.send_txs_and_test([tx0], node, success=False, reject_reason=DISABLED_OPCODE_ERROR)
except:
self.start_node(0)
helper_peer = node.add_p2p_connection(P2PDataStore())
# A block containing new opcodes is accepted however
tip = node.getblock(node.getbestblockhash(), 1)
test_block = self.create_test_block([tx0], tip["hash"], tip["height"], tip["time"])
helper_peer.send_blocks_and_test([test_block], node, success=True)
try:
# txes spending new opcodes still won't be accepted into mempool if we roll back to the previous tip
node.invalidateblock(node.getbestblockhash())
except:
self.start_node(0)
node.generate(1)
self.log.info("Transactions spending coins with new opcodes are accepted one block after DIP0020 activation block")
tx0id = node.sendrawtransaction(tx0_hex)
assert tx0id in set(node.getrawmempool())
if __name__ == '__main__':