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