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
56from test_framework .messages import COIN , COutPoint , CTransaction , CTxIn , CTxOut
7+ from test_framework .p2p import P2PDataStore
68from test_framework .script import CScript , OP_CAT , OP_DROP , OP_TRUE
79from test_framework .test_framework import BitcoinTestFramework
810from 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
78128if __name__ == '__main__' :
0 commit comments