35
35
bip112txs_vary_OP_CSV - 16 txs with nSequence = 10 evaluated against varying {relative_locktimes of 10} OP_CSV OP_DROP
36
36
bip112txs_vary_OP_CSV_9 - 16 txs with nSequence = 9 evaluated against varying {relative_locktimes of 10} OP_CSV OP_DROP
37
37
bip112tx_special - test negative argument to OP_CSV
38
+ bip112tx_emptystack - test empty stack (= no argument) OP_CSV
38
39
"""
39
40
from decimal import Decimal
40
41
from itertools import product
56
57
softfork_active ,
57
58
)
58
59
60
+ TESTING_TX_COUNT = 83 # Number of testing transactions: 1 BIP113 tx, 16 BIP68 txs, 66 BIP112 txs (see comments above)
61
+ COINBASE_BLOCK_COUNT = TESTING_TX_COUNT # Number of coinbase blocks we need to generate as inputs for our txs
59
62
BASE_RELATIVE_LOCKTIME = 10
60
63
CSV_ACTIVATION_HEIGHT = 432
61
64
SEQ_DISABLE_FLAG = 1 << 31
@@ -95,6 +98,13 @@ def create_bip112special(node, input, txversion, address):
95
98
signtx .vin [0 ].scriptSig = CScript ([- 1 , OP_CHECKSEQUENCEVERIFY , OP_DROP ] + list (CScript (signtx .vin [0 ].scriptSig )))
96
99
return signtx
97
100
101
+ def create_bip112emptystack (node , input , txversion , address ):
102
+ tx = create_transaction (node , input , address , amount = Decimal ("49.98" ))
103
+ tx .nVersion = txversion
104
+ signtx = sign_transaction (node , tx )
105
+ signtx .vin [0 ].scriptSig = CScript ([OP_CHECKSEQUENCEVERIFY ] + list (CScript (signtx .vin [0 ].scriptSig )))
106
+ return signtx
107
+
98
108
def send_generic_input_tx (node , coinbases , address ):
99
109
return node .sendrawtransaction (ToHex (sign_transaction (node , create_transaction (node , node .getblock (coinbases .pop ())['tx' ][0 ], address , amount = Decimal ("49.99" )))))
100
110
@@ -142,6 +152,7 @@ def set_test_params(self):
142
152
143
153
'-blockversion=4' ,
144
154
'-addresstype=legacy' ,
155
+ '-par=1' , # Use only one script thread to get the exact reject reason for testing
145
156
]]
146
157
self .supports_cli = False
147
158
@@ -167,27 +178,28 @@ def create_test_block(self, txs):
167
178
block .solve ()
168
179
return block
169
180
170
- def send_blocks (self , blocks , success = True ):
181
+ def send_blocks (self , blocks , success = True , reject_reason = None ):
171
182
"""Sends blocks to test node. Syncs and verifies that tip has advanced to most recent block.
172
183
173
184
Call with success = False if the tip shouldn't advance to the most recent block."""
174
- self .nodes [0 ].p2p .send_blocks_and_test (blocks , self .nodes [0 ], success = success )
185
+ self .nodes [0 ].p2p .send_blocks_and_test (blocks , self .nodes [0 ], success = success , reject_reason = reject_reason )
175
186
176
187
def run_test (self ):
177
188
self .nodes [0 ].add_p2p_connection (P2PDataStore ())
178
189
179
190
self .log .info ("Generate blocks in the past for coinbase outputs." )
180
191
long_past_time = int (time .time ()) - 600 * 1000 # enough to build up to 1000 blocks 10 minutes apart without worrying about getting into the future
181
192
self .nodes [0 ].setmocktime (long_past_time - 100 ) # enough so that the generated blocks will still all be before long_past_time
182
- self .coinbase_blocks = self .nodes [0 ].generate (1 + 16 + 2 * 32 + 1 ) # 82 blocks generated for inputs
193
+ self .coinbase_blocks = self .nodes [0 ].generate (COINBASE_BLOCK_COUNT ) # blocks generated for inputs
183
194
self .nodes [0 ].setmocktime (0 ) # set time back to present so yielded blocks aren't in the future as we advance last_block_time
184
- self .tipheight = 82 # height of the next block to build
195
+ self .tipheight = COINBASE_BLOCK_COUNT # height of the next block to build
185
196
self .last_block_time = long_past_time
186
197
self .tip = int (self .nodes [0 ].getbestblockhash (), 16 )
187
198
self .nodeaddress = self .nodes [0 ].getnewaddress ()
188
199
189
200
# Activation height is hardcoded
190
- test_blocks = self .generate_blocks (345 )
201
+ # We advance to block height five below BIP112 activation for the following tests
202
+ test_blocks = self .generate_blocks (CSV_ACTIVATION_HEIGHT - 5 - COINBASE_BLOCK_COUNT )
191
203
self .send_blocks (test_blocks )
192
204
assert not softfork_active (self .nodes [0 ], 'csv' )
193
205
@@ -218,6 +230,8 @@ def run_test(self):
218
230
219
231
# 1 special input with -1 OP_CSV OP_DROP (actually will be prepended to spending scriptSig)
220
232
bip112specialinput = send_generic_input_tx (self .nodes [0 ], self .coinbase_blocks , self .nodeaddress )
233
+ # 1 special input with (empty stack) OP_CSV (actually will be prepended to spending scriptSig)
234
+ bip112emptystackinput = send_generic_input_tx (self .nodes [0 ],self .coinbase_blocks , self .nodeaddress )
221
235
222
236
# 1 normal input
223
237
bip113input = send_generic_input_tx (self .nodes [0 ], self .coinbase_blocks , self .nodeaddress )
@@ -228,7 +242,7 @@ def run_test(self):
228
242
self .tip = int (inputblockhash , 16 )
229
243
self .tipheight += 1
230
244
self .last_block_time += 600
231
- assert_equal (len (self .nodes [0 ].getblock (inputblockhash , True )["tx" ]), 82 + 1 )
245
+ assert_equal (len (self .nodes [0 ].getblock (inputblockhash , True )["tx" ]), TESTING_TX_COUNT + 1 )
232
246
233
247
# 2 more version 4 blocks
234
248
test_blocks = self .generate_blocks (2 )
@@ -267,18 +281,22 @@ def run_test(self):
267
281
# -1 OP_CSV OP_DROP input
268
282
bip112tx_special_v1 = create_bip112special (self .nodes [0 ], bip112specialinput , 1 , self .nodeaddress )
269
283
bip112tx_special_v2 = create_bip112special (self .nodes [0 ], bip112specialinput , 2 , self .nodeaddress )
284
+ # (empty stack) OP_CSV input
285
+ bip112tx_emptystack_v1 = create_bip112emptystack (self .nodes [0 ], bip112emptystackinput , 1 , self .nodeaddress )
286
+ bip112tx_emptystack_v2 = create_bip112emptystack (self .nodes [0 ], bip112emptystackinput , 2 , self .nodeaddress )
270
287
271
288
self .log .info ("TESTING" )
272
289
273
290
self .log .info ("Pre-Soft Fork Tests. All txs should pass." )
274
291
self .log .info ("Test version 1 txs" )
275
292
276
293
success_txs = []
277
- # add BIP113 tx and -1 CSV tx
294
+ # BIP113 tx, -1 CSV tx and empty stack CSV tx should succeed
278
295
bip113tx_v1 .nLockTime = self .last_block_time - 600 * 5 # = MTP of prior block (not <) but < time put on current block
279
296
bip113signed1 = sign_transaction (self .nodes [0 ], bip113tx_v1 )
280
297
success_txs .append (bip113signed1 )
281
298
success_txs .append (bip112tx_special_v1 )
299
+ success_txs .append (bip112tx_emptystack_v1 )
282
300
# add BIP 68 txs
283
301
success_txs .extend (all_rlt_txs (bip68txs_v1 ))
284
302
# add BIP 112 with seq=10 txs
@@ -293,11 +311,12 @@ def run_test(self):
293
311
self .log .info ("Test version 2 txs" )
294
312
295
313
success_txs = []
296
- # add BIP113 tx and -1 CSV tx
314
+ # BIP113 tx, -1 CSV tx and empty stack CSV tx should succeed
297
315
bip113tx_v2 .nLockTime = self .last_block_time - 600 * 5 # = MTP of prior block (not <) but < time put on current block
298
316
bip113signed2 = sign_transaction (self .nodes [0 ], bip113tx_v2 )
299
317
success_txs .append (bip113signed2 )
300
318
success_txs .append (bip112tx_special_v2 )
319
+ success_txs .append (bip112tx_emptystack_v2 )
301
320
# add BIP 68 txs
302
321
success_txs .extend (all_rlt_txs (bip68txs_v2 ))
303
322
# add BIP 112 with seq=10 txs
@@ -385,8 +404,10 @@ def run_test(self):
385
404
self .log .info ("BIP 112 tests" )
386
405
self .log .info ("Test version 1 txs" )
387
406
388
- # -1 OP_CSV tx should fail
407
+ # -1 OP_CSV tx and (empty stack) OP_CSV tx should fail
389
408
self .send_blocks ([self .create_test_block ([bip112tx_special_v1 ])], success = False )
409
+ self .send_blocks ([self .create_test_block ([bip112tx_emptystack_v1 ])], success = False ,
410
+ reject_reason = 'non-mandatory-script-verify-flag (Operation not valid with the current stack size)' )
390
411
# If SEQUENCE_LOCKTIME_DISABLE_FLAG is set in argument to OP_CSV, version 1 txs should still pass
391
412
392
413
success_txs = [tx ['tx' ] for tx in bip112txs_vary_OP_CSV_v1 if tx ['sdf' ]]
@@ -404,8 +425,10 @@ def run_test(self):
404
425
405
426
self .log .info ("Test version 2 txs" )
406
427
407
- # -1 OP_CSV tx should fail
428
+ # -1 OP_CSV tx and (empty stack) OP_CSV tx should fail
408
429
self .send_blocks ([self .create_test_block ([bip112tx_special_v2 ])], success = False )
430
+ self .send_blocks ([self .create_test_block ([bip112tx_emptystack_v2 ])], success = False ,
431
+ reject_reason = 'non-mandatory-script-verify-flag (Operation not valid with the current stack size)' )
409
432
410
433
# If SEQUENCE_LOCKTIME_DISABLE_FLAG is set in argument to OP_CSV, version 2 txs should pass (all sequence locks are met)
411
434
success_txs = [tx ['tx' ] for tx in bip112txs_vary_OP_CSV_v2 if tx ['sdf' ]]
@@ -449,7 +472,5 @@ def run_test(self):
449
472
self .send_blocks ([self .create_test_block (time_txs )])
450
473
self .nodes [0 ].invalidateblock (self .nodes [0 ].getbestblockhash ())
451
474
452
- # TODO: Test empty stack fails
453
-
454
475
if __name__ == '__main__' :
455
476
BIP68_112_113Test ().main ()
0 commit comments