1+ #!/usr/bin/env python3
2+ # Copyright (c) 2016 The Bitcoin Core developers
3+ # Distributed under the MIT software license, see the accompanying
4+ # file COPYING or http://www.opensource.org/licenses/mit-license.php.
5+
6+ from test_framework .test_framework import ComparisonTestFramework
7+ from test_framework .util import *
8+ from test_framework .mininode import CTransaction , NetworkThread
9+ from test_framework .blocktools import create_coinbase , create_block , add_witness_commitment
10+ from test_framework .comptool import TestManager
11+ from test_framework .script import CScript
12+ from io import BytesIO
13+ import time
14+
15+ NULLDUMMY_ERROR = "64: non-mandatory-script-verify-flag (Dummy CHECKMULTISIG argument must be zero)"
16+
17+ def trueDummy (tx ):
18+ scriptSig = CScript (tx .vin [0 ].scriptSig )
19+ newscript = []
20+ for i in scriptSig :
21+ if (len (newscript ) == 0 ):
22+ assert (len (i ) == 0 )
23+ newscript .append (b'\x51 ' )
24+ else :
25+ newscript .append (i )
26+ tx .vin [0 ].scriptSig = CScript (newscript )
27+ tx .rehash ()
28+
29+ '''
30+ This test is meant to exercise NULLDUMMY softfork.
31+ Connect to a single node.
32+ Generate 2 blocks (save the coinbases for later).
33+ Generate 427 more blocks.
34+ [Policy/Consensus] Check that NULLDUMMY compliant transactions are accepted in the 430th block.
35+ [Policy] Check that non-NULLDUMMY transactions are rejected before activation.
36+ [Consensus] Check that the new NULLDUMMY rules are not enforced on the 431st block.
37+ [Policy/Consensus] Check that the new NULLDUMMY rules are enforced on the 432nd block.
38+ '''
39+
40+ class NULLDUMMYTest (ComparisonTestFramework ):
41+
42+ def __init__ (self ):
43+ super ().__init__ ()
44+ self .num_nodes = 1
45+
46+ def setup_network (self ):
47+ # Must set the blockversion for this test
48+ self .nodes = start_nodes (self .num_nodes , self .options .tmpdir ,
49+ extra_args = [['-debug' , '-whitelist=127.0.0.1' , '-walletprematurewitness' ]])
50+
51+ def run_test (self ):
52+ self .address = self .nodes [0 ].getnewaddress ()
53+ self .ms_address = self .nodes [0 ].addmultisigaddress (1 ,[self .address ])
54+ self .wit_address = self .nodes [0 ].addwitnessaddress (self .address )
55+ self .wit_ms_address = self .nodes [0 ].addwitnessaddress (self .ms_address )
56+
57+ test = TestManager (self , self .options .tmpdir )
58+ test .add_all_connections (self .nodes )
59+ NetworkThread ().start () # Start up network handling in another thread
60+ self .coinbase_blocks = self .nodes [0 ].generate (2 ) # Block 2
61+ coinbase_txid = []
62+ for i in self .coinbase_blocks :
63+ coinbase_txid .append (self .nodes [0 ].getblock (i )['tx' ][0 ])
64+ self .nodes [0 ].generate (427 ) # Block 429
65+ self .lastblockhash = self .nodes [0 ].getbestblockhash ()
66+ self .tip = int ("0x" + self .lastblockhash , 0 )
67+ self .lastblockheight = 429
68+ self .lastblocktime = int (time .time ()) + 429
69+
70+ print ("Test 1: NULLDUMMY compliant base transactions should be accepted to mempool and mined before activation [430]" )
71+ test1txs = [self .create_transaction (self .nodes [0 ], coinbase_txid [0 ], self .ms_address , 49 )]
72+ txid1 = self .tx_submit (self .nodes [0 ], test1txs [0 ])
73+ test1txs .append (self .create_transaction (self .nodes [0 ], txid1 , self .ms_address , 48 ))
74+ txid2 = self .tx_submit (self .nodes [0 ], test1txs [1 ])
75+ test1txs .append (self .create_transaction (self .nodes [0 ], coinbase_txid [1 ], self .wit_ms_address , 49 ))
76+ txid3 = self .tx_submit (self .nodes [0 ], test1txs [2 ])
77+ self .block_submit (self .nodes [0 ], test1txs , False , True )
78+
79+ print ("Test 2: Non-NULLDUMMY base multisig transaction should not be accepted to mempool before activation" )
80+ test2tx = self .create_transaction (self .nodes [0 ], txid2 , self .ms_address , 48 )
81+ trueDummy (test2tx )
82+ txid4 = self .tx_submit (self .nodes [0 ], test2tx , NULLDUMMY_ERROR )
83+
84+ print ("Test 3: Non-NULLDUMMY base transactions should be accepted in a block before activation [431]" )
85+ self .block_submit (self .nodes [0 ], [test2tx ], False , True )
86+
87+ print ("Test 4: Non-NULLDUMMY base multisig transaction is invalid after activation" )
88+ test4tx = self .create_transaction (self .nodes [0 ], txid4 , self .address , 47 )
89+ test6txs = [CTransaction (test4tx )]
90+ trueDummy (test4tx )
91+ self .tx_submit (self .nodes [0 ], test4tx , NULLDUMMY_ERROR )
92+ self .block_submit (self .nodes [0 ], [test4tx ])
93+
94+ print ("Test 5: Non-NULLDUMMY P2WSH multisig transaction invalid after activation" )
95+ test5tx = self .create_transaction (self .nodes [0 ], txid3 , self .wit_address , 48 )
96+ test6txs .append (CTransaction (test5tx ))
97+ test5tx .wit .vtxinwit [0 ].scriptWitness .stack [0 ] = b'\x01 '
98+ self .tx_submit (self .nodes [0 ], test5tx , NULLDUMMY_ERROR )
99+ self .block_submit (self .nodes [0 ], [test5tx ], True )
100+
101+ print ("Test 6: NULLDUMMY compliant base/witness transactions should be accepted to mempool and in block after activation [432]" )
102+ for i in test6txs :
103+ self .tx_submit (self .nodes [0 ], i )
104+ self .block_submit (self .nodes [0 ], test6txs , True , True )
105+
106+
107+ def create_transaction (self , node , txid , to_address , amount ):
108+ inputs = [{ "txid" : txid , "vout" : 0 }]
109+ outputs = { to_address : amount }
110+ rawtx = node .createrawtransaction (inputs , outputs )
111+ signresult = node .signrawtransaction (rawtx )
112+ tx = CTransaction ()
113+ f = BytesIO (hex_str_to_bytes (signresult ['hex' ]))
114+ tx .deserialize (f )
115+ return tx
116+
117+
118+ def tx_submit (self , node , tx , msg = "" ):
119+ tx .rehash ()
120+ try :
121+ node .sendrawtransaction (bytes_to_hex_str (tx .serialize_with_witness ()), True )
122+ except JSONRPCException as exp :
123+ assert_equal (exp .error ["message" ], msg )
124+ return tx .hash
125+
126+
127+ def block_submit (self , node , txs , witness = False , accept = False ):
128+ block = create_block (self .tip , create_coinbase (self .lastblockheight + 1 ), self .lastblocktime + 1 )
129+ block .nVersion = 4
130+ for tx in txs :
131+ tx .rehash ()
132+ block .vtx .append (tx )
133+ block .hashMerkleRoot = block .calc_merkle_root ()
134+ witness and add_witness_commitment (block )
135+ block .rehash ()
136+ block .solve ()
137+ node .submitblock (bytes_to_hex_str (block .serialize (True )))
138+ if (accept ):
139+ assert_equal (node .getbestblockhash (), block .hash )
140+ self .tip = block .sha256
141+ self .lastblockhash = block .hash
142+ self .lastblocktime += 1
143+ self .lastblockheight += 1
144+ else :
145+ assert_equal (node .getbestblockhash (), self .lastblockhash )
146+
147+ if __name__ == '__main__' :
148+ NULLDUMMYTest ().main ()
0 commit comments