Skip to content

Commit 04b5db9

Browse files
committed
test: extend and refactor DIP0020 activation test
1 parent 3b9f935 commit 04b5db9

File tree

1 file changed

+75
-25
lines changed

1 file changed

+75
-25
lines changed

test/functional/feature_dip0020_activation.py

Lines changed: 75 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@
22
# Copyright (c) 2015-2023 The Dash Core developers
33
# Distributed under the MIT software license, see the accompanying
44
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
5+
from test_framework.blocktools import create_block, create_coinbase
56
from test_framework.messages import COIN, COutPoint, CTransaction, CTxIn, CTxOut
7+
from test_framework.p2p import P2PDataStore
68
from test_framework.script import CScript, OP_CAT, OP_DROP, OP_TRUE
79
from test_framework.test_framework import BitcoinTestFramework
810
from test_framework.util import assert_raises_rpc_error, softfork_active, satoshi_round
@@ -28,51 +30,99 @@ def set_test_params(self):
2830
def skip_test_if_missing_module(self):
2931
self.skip_if_no_wallet()
3032

33+
def create_test_block(self, txs, tip_hash, tip_height, tip_time):
34+
block = create_block(int(tip_hash, 16), create_coinbase(tip_height + 1), tip_time + 1)
35+
block.nVersion = 4
36+
block.vtx.extend(txs)
37+
block.hashMerkleRoot = block.calc_merkle_root()
38+
block.rehash()
39+
block.solve()
40+
return block
41+
3142
def run_test(self):
32-
self.node = self.nodes[0]
33-
self.relayfee = satoshi_round(self.nodes[0].getnetworkinfo()["relayfee"])
43+
node = self.nodes[0]
44+
relayfee = satoshi_round(node.getnetworkinfo()["relayfee"])
3445

3546
# We should have some coins already
36-
utxos = self.node.listunspent()
47+
utxos = node.listunspent()
3748
assert len(utxos) > 0
3849

3950
# Lock some coins using disabled opcodes
4051
utxo = utxos[len(utxos) - 1]
41-
value = int(satoshi_round(utxo["amount"] - self.relayfee) * COIN)
52+
value = int(satoshi_round(utxo["amount"] - relayfee) * COIN)
4253
tx = CTransaction()
4354
tx.vin.append(CTxIn(COutPoint(int(utxo["txid"], 16), utxo["vout"])))
4455
tx.vout.append(CTxOut(value, CScript([b'1', b'2', OP_CAT])))
45-
tx_signed_hex = self.node.signrawtransactionwithwallet(tx.serialize().hex())["hex"]
46-
txid = self.node.sendrawtransaction(tx_signed_hex)
56+
tx_signed_hex = node.signrawtransactionwithwallet(tx.serialize().hex())["hex"]
57+
txid = node.sendrawtransaction(tx_signed_hex)
4758

4859
# This tx should be completely valid, should be included in mempool and mined in the next block
49-
assert txid in set(self.node.getrawmempool())
50-
self.node.generate(1)
51-
assert txid not in set(self.node.getrawmempool())
60+
assert txid in set(node.getrawmempool())
61+
node.generate(1)
62+
assert txid not in set(node.getrawmempool())
5263

5364
# Create spending tx
54-
value = int(value - self.relayfee * COIN)
65+
value = int(value - relayfee * COIN)
5566
tx0 = CTransaction()
5667
tx0.vin.append(CTxIn(COutPoint(int(txid, 16), 0)))
5768
tx0.vout.append(CTxOut(value, CScript([OP_TRUE, OP_DROP] * 15 + [OP_TRUE])))
5869
tx0.rehash()
5970
tx0_hex = tx0.serialize().hex()
6071

61-
# This tx isn't valid yet
62-
assert not softfork_active(self.nodes[0], 'dip0020')
63-
assert_raises_rpc_error(-26, DISABLED_OPCODE_ERROR, self.node.sendrawtransaction, tx0_hex)
64-
65-
# Generate enough blocks to activate DIP0020 opcodes
66-
self.node.generate(98)
67-
assert softfork_active(self.nodes[0], 'dip0020')
68-
69-
# Still need 1 more block for mempool to accept new opcodes
70-
assert_raises_rpc_error(-26, DISABLED_OPCODE_ERROR, self.node.sendrawtransaction, tx0_hex)
71-
self.node.generate(1)
72-
73-
# Should be spendable now
74-
tx0id = self.node.sendrawtransaction(tx0_hex)
75-
assert tx0id in set(self.node.getrawmempool())
72+
# flush state to disk before potential crashes below
73+
self.nodes[0].gettxoutsetinfo()
74+
75+
self.log.info("Transactions spending coins with new opcodes aren't accepted before DIP0020 activation")
76+
assert not softfork_active(node, 'dip0020')
77+
try:
78+
assert_raises_rpc_error(-26, DISABLED_OPCODE_ERROR, node.sendrawtransaction, tx0_hex)
79+
except:
80+
self.start_node(0)
81+
try:
82+
helper_peer = node.add_p2p_connection(P2PDataStore())
83+
helper_peer.send_txs_and_test([tx0], node, success=False, reject_reason=DISABLED_OPCODE_ERROR)
84+
except:
85+
self.start_node(0)
86+
helper_peer = node.add_p2p_connection(P2PDataStore())
87+
tip = node.getblock(node.getbestblockhash(), 1)
88+
test_block = self.create_test_block([tx0], tip["hash"], tip["height"], tip["time"])
89+
helper_peer.send_blocks_and_test([test_block], node, success=False, reject_reason='block-validation-failed', expect_disconnect=True)
90+
91+
self.log.info("Generate enough blocks to activate DIP0020 opcodes")
92+
node.generate(97)
93+
assert not softfork_active(node, 'dip0020')
94+
node.generate(1)
95+
assert softfork_active(node, 'dip0020')
96+
97+
# flush state to disk before potential crashes below
98+
self.nodes[0].gettxoutsetinfo()
99+
100+
# Still need 1 more block for mempool to accept txes spending new opcodes
101+
self.log.info("Transactions spending coins with new opcodes aren't accepted at DIP0020 activation block")
102+
try:
103+
assert_raises_rpc_error(-26, DISABLED_OPCODE_ERROR, node.sendrawtransaction, tx0_hex)
104+
except:
105+
self.start_node(0)
106+
try:
107+
helper_peer = node.add_p2p_connection(P2PDataStore())
108+
helper_peer.send_txs_and_test([tx0], node, success=False, reject_reason=DISABLED_OPCODE_ERROR)
109+
except:
110+
self.start_node(0)
111+
helper_peer = node.add_p2p_connection(P2PDataStore())
112+
# A block containing new opcodes is accepted however
113+
tip = node.getblock(node.getbestblockhash(), 1)
114+
test_block = self.create_test_block([tx0], tip["hash"], tip["height"], tip["time"])
115+
helper_peer.send_blocks_and_test([test_block], node, success=True)
116+
try:
117+
# txes spending new opcodes still won't be accepted into mempool if we roll back to the previous tip
118+
node.invalidateblock(node.getbestblockhash())
119+
except:
120+
self.start_node(0)
121+
node.generate(1)
122+
123+
self.log.info("Transactions spending coins with new opcodes are accepted one block after DIP0020 activation block")
124+
tx0id = node.sendrawtransaction(tx0_hex)
125+
assert tx0id in set(node.getrawmempool())
76126

77127

78128
if __name__ == '__main__':

0 commit comments

Comments
 (0)