37
37
bip112tx_special - test negative argument to OP_CSV
38
38
bip112tx_emptystack - test empty stack (= no argument) OP_CSV
39
39
"""
40
- from decimal import Decimal
41
40
from itertools import product
42
- from io import BytesIO
43
41
import time
44
42
45
- from test_framework .blocktools import create_coinbase , create_block , create_transaction
46
- from test_framework .messages import ToHex , CTransaction
43
+ from test_framework .blocktools import (
44
+ create_block ,
45
+ create_coinbase ,
46
+ )
47
47
from test_framework .p2p import P2PDataStore
48
48
from test_framework .script import (
49
49
CScript ,
53
53
from test_framework .test_framework import BitcoinTestFramework
54
54
from test_framework .util import (
55
55
assert_equal ,
56
- hex_str_to_bytes ,
57
56
softfork_active ,
58
57
)
58
+ from test_framework .wallet import MiniWallet
59
59
60
60
TESTING_TX_COUNT = 83 # Number of testing transactions: 1 BIP113 tx, 16 BIP68 txs, 66 BIP112 txs (see comments above)
61
61
COINBASE_BLOCK_COUNT = TESTING_TX_COUNT # Number of coinbase blocks we need to generate as inputs for our txs
@@ -83,80 +83,73 @@ def relative_locktime(sdf, srhb, stf, srlb):
83
83
def all_rlt_txs (txs ):
84
84
return [tx ['tx' ] for tx in txs ]
85
85
86
- def sign_transaction (node , unsignedtx ):
87
- rawtx = ToHex (unsignedtx )
88
- signresult = node .signrawtransactionwithwallet (rawtx )
89
- tx = CTransaction ()
90
- f = BytesIO (hex_str_to_bytes (signresult ['hex' ]))
91
- tx .deserialize (f )
92
- return tx
93
-
94
- def create_bip112special (node , input , txversion , address ):
95
- tx = create_transaction (node , input , address , amount = Decimal ("49.98" ))
96
- tx .nVersion = txversion
97
- signtx = sign_transaction (node , tx )
98
- signtx .vin [0 ].scriptSig = CScript ([- 1 , OP_CHECKSEQUENCEVERIFY , OP_DROP ] + list (CScript (signtx .vin [0 ].scriptSig )))
99
- return signtx
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
-
108
- def send_generic_input_tx (node , coinbases , address ):
109
- return node .sendrawtransaction (ToHex (sign_transaction (node , create_transaction (node , node .getblock (coinbases .pop ())['tx' ][0 ], address , amount = Decimal ("49.99" )))))
110
-
111
- def create_bip68txs (node , bip68inputs , txversion , address , locktime_delta = 0 ):
112
- """Returns a list of bip68 transactions with different bits set."""
113
- txs = []
114
- assert len (bip68inputs ) >= 16
115
- for i , (sdf , srhb , stf , srlb ) in enumerate (product (* [[True , False ]] * 4 )):
116
- locktime = relative_locktime (sdf , srhb , stf , srlb )
117
- tx = create_transaction (node , bip68inputs [i ], address , amount = Decimal ("49.98" ))
118
- tx .nVersion = txversion
119
- tx .vin [0 ].nSequence = locktime + locktime_delta
120
- tx = sign_transaction (node , tx )
121
- tx .rehash ()
122
- txs .append ({'tx' : tx , 'sdf' : sdf , 'stf' : stf })
123
-
124
- return txs
125
-
126
- def create_bip112txs (node , bip112inputs , varyOP_CSV , txversion , address , locktime_delta = 0 ):
127
- """Returns a list of bip68 transactions with different bits set."""
128
- txs = []
129
- assert len (bip112inputs ) >= 16
130
- for i , (sdf , srhb , stf , srlb ) in enumerate (product (* [[True , False ]] * 4 )):
131
- locktime = relative_locktime (sdf , srhb , stf , srlb )
132
- tx = create_transaction (node , bip112inputs [i ], address , amount = Decimal ("49.98" ))
133
- if (varyOP_CSV ): # if varying OP_CSV, nSequence is fixed
134
- tx .vin [0 ].nSequence = BASE_RELATIVE_LOCKTIME + locktime_delta
135
- else : # vary nSequence instead, OP_CSV is fixed
136
- tx .vin [0 ].nSequence = locktime + locktime_delta
137
- tx .nVersion = txversion
138
- signtx = sign_transaction (node , tx )
139
- if (varyOP_CSV ):
140
- signtx .vin [0 ].scriptSig = CScript ([locktime , OP_CHECKSEQUENCEVERIFY , OP_DROP ] + list (CScript (signtx .vin [0 ].scriptSig )))
141
- else :
142
- signtx .vin [0 ].scriptSig = CScript ([BASE_RELATIVE_LOCKTIME , OP_CHECKSEQUENCEVERIFY , OP_DROP ] + list (CScript (signtx .vin [0 ].scriptSig )))
143
- tx .rehash ()
144
- txs .append ({'tx' : signtx , 'sdf' : sdf , 'stf' : stf })
145
- return txs
146
86
147
87
class BIP68_112_113Test (BitcoinTestFramework ):
148
88
def set_test_params (self ):
149
89
self .num_nodes = 1
150
90
self .setup_clean_chain = True
151
91
self .extra_args = [[
152
92
153
- '-addresstype=legacy ' ,
93
+ '-acceptnonstdtxn=1 ' ,
154
94
'-par=1' , # Use only one script thread to get the exact reject reason for testing
155
95
]]
156
96
self .supports_cli = False
157
97
158
- def skip_test_if_missing_module (self ):
159
- self .skip_if_no_wallet ()
98
+ def create_self_transfer_from_utxo (self , input_tx ):
99
+ utxo = self .miniwallet .get_utxo (txid = input_tx .rehash (), mark_as_spent = False )
100
+ tx = self .miniwallet .create_self_transfer (from_node = self .nodes [0 ], utxo_to_spend = utxo )['tx' ]
101
+ return tx
102
+
103
+ def create_bip112special (self , input , txversion ):
104
+ tx = self .create_self_transfer_from_utxo (input )
105
+ tx .nVersion = txversion
106
+ tx .vin [0 ].scriptSig = CScript ([- 1 , OP_CHECKSEQUENCEVERIFY , OP_DROP ] + list (CScript (tx .vin [0 ].scriptSig )))
107
+ return tx
108
+
109
+ def create_bip112emptystack (self , input , txversion ):
110
+ tx = self .create_self_transfer_from_utxo (input )
111
+ tx .nVersion = txversion
112
+ tx .vin [0 ].scriptSig = CScript ([OP_CHECKSEQUENCEVERIFY ] + list (CScript (tx .vin [0 ].scriptSig )))
113
+ return tx
114
+
115
+ def send_generic_input_tx (self , coinbases ):
116
+ input_txid = self .nodes [0 ].getblock (coinbases .pop (), 2 )['tx' ][0 ]['txid' ]
117
+ utxo_to_spend = self .miniwallet .get_utxo (txid = input_txid )
118
+ return self .miniwallet .send_self_transfer (from_node = self .nodes [0 ], utxo_to_spend = utxo_to_spend )['tx' ]
119
+
120
+ def create_bip68txs (self , bip68inputs , txversion , locktime_delta = 0 ):
121
+ """Returns a list of bip68 transactions with different bits set."""
122
+ txs = []
123
+ assert len (bip68inputs ) >= 16
124
+ for i , (sdf , srhb , stf , srlb ) in enumerate (product (* [[True , False ]] * 4 )):
125
+ locktime = relative_locktime (sdf , srhb , stf , srlb )
126
+ tx = self .create_self_transfer_from_utxo (bip68inputs [i ])
127
+ tx .nVersion = txversion
128
+ tx .vin [0 ].nSequence = locktime + locktime_delta
129
+ tx .rehash ()
130
+ txs .append ({'tx' : tx , 'sdf' : sdf , 'stf' : stf })
131
+
132
+ return txs
133
+
134
+ def create_bip112txs (self , bip112inputs , varyOP_CSV , txversion , locktime_delta = 0 ):
135
+ """Returns a list of bip68 transactions with different bits set."""
136
+ txs = []
137
+ assert len (bip112inputs ) >= 16
138
+ for i , (sdf , srhb , stf , srlb ) in enumerate (product (* [[True , False ]] * 4 )):
139
+ locktime = relative_locktime (sdf , srhb , stf , srlb )
140
+ tx = self .create_self_transfer_from_utxo (bip112inputs [i ])
141
+ if (varyOP_CSV ): # if varying OP_CSV, nSequence is fixed
142
+ tx .vin [0 ].nSequence = BASE_RELATIVE_LOCKTIME + locktime_delta
143
+ else : # vary nSequence instead, OP_CSV is fixed
144
+ tx .vin [0 ].nSequence = locktime + locktime_delta
145
+ tx .nVersion = txversion
146
+ if (varyOP_CSV ):
147
+ tx .vin [0 ].scriptSig = CScript ([locktime , OP_CHECKSEQUENCEVERIFY , OP_DROP ] + list (CScript (tx .vin [0 ].scriptSig )))
148
+ else :
149
+ tx .vin [0 ].scriptSig = CScript ([BASE_RELATIVE_LOCKTIME , OP_CHECKSEQUENCEVERIFY , OP_DROP ] + list (CScript (tx .vin [0 ].scriptSig )))
150
+ tx .rehash ()
151
+ txs .append ({'tx' : tx , 'sdf' : sdf , 'stf' : stf })
152
+ return txs
160
153
161
154
def generate_blocks (self , number ):
162
155
test_blocks = []
@@ -185,16 +178,16 @@ def send_blocks(self, blocks, success=True, reject_reason=None):
185
178
186
179
def run_test (self ):
187
180
self .helper_peer = self .nodes [0 ].add_p2p_connection (P2PDataStore ())
181
+ self .miniwallet = MiniWallet (self .nodes [0 ], raw_script = True )
188
182
189
183
self .log .info ("Generate blocks in the past for coinbase outputs." )
190
184
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
191
185
self .nodes [0 ].setmocktime (long_past_time - 100 ) # enough so that the generated blocks will still all be before long_past_time
192
- self .coinbase_blocks = self .nodes [ 0 ] .generate (COINBASE_BLOCK_COUNT ) # blocks generated for inputs
186
+ self .coinbase_blocks = self .miniwallet .generate (COINBASE_BLOCK_COUNT ) # blocks generated for inputs
193
187
self .nodes [0 ].setmocktime (0 ) # set time back to present so yielded blocks aren't in the future as we advance last_block_time
194
188
self .tipheight = COINBASE_BLOCK_COUNT # height of the next block to build
195
189
self .last_block_time = long_past_time
196
190
self .tip = int (self .nodes [0 ].getbestblockhash (), 16 )
197
- self .nodeaddress = self .nodes [0 ].getnewaddress ()
198
191
199
192
# Activation height is hardcoded
200
193
# We advance to block height five below BIP112 activation for the following tests
@@ -209,31 +202,31 @@ def run_test(self):
209
202
# 16 normal inputs
210
203
bip68inputs = []
211
204
for _ in range (16 ):
212
- bip68inputs .append (send_generic_input_tx (self .nodes [ 0 ], self . coinbase_blocks , self . nodeaddress ))
205
+ bip68inputs .append (self . send_generic_input_tx (self .coinbase_blocks ))
213
206
214
207
# 2 sets of 16 inputs with 10 OP_CSV OP_DROP (actually will be prepended to spending scriptSig)
215
208
bip112basicinputs = []
216
209
for _ in range (2 ):
217
210
inputs = []
218
211
for _ in range (16 ):
219
- inputs .append (send_generic_input_tx (self .nodes [ 0 ], self . coinbase_blocks , self . nodeaddress ))
212
+ inputs .append (self . send_generic_input_tx (self .coinbase_blocks ))
220
213
bip112basicinputs .append (inputs )
221
214
222
215
# 2 sets of 16 varied inputs with (relative_lock_time) OP_CSV OP_DROP (actually will be prepended to spending scriptSig)
223
216
bip112diverseinputs = []
224
217
for _ in range (2 ):
225
218
inputs = []
226
219
for _ in range (16 ):
227
- inputs .append (send_generic_input_tx (self .nodes [ 0 ], self . coinbase_blocks , self . nodeaddress ))
220
+ inputs .append (self . send_generic_input_tx (self .coinbase_blocks ))
228
221
bip112diverseinputs .append (inputs )
229
222
230
223
# 1 special input with -1 OP_CSV OP_DROP (actually will be prepended to spending scriptSig)
231
- bip112specialinput = send_generic_input_tx (self .nodes [ 0 ], self . coinbase_blocks , self . nodeaddress )
224
+ bip112specialinput = self . send_generic_input_tx (self .coinbase_blocks )
232
225
# 1 special input with (empty stack) OP_CSV (actually will be prepended to spending scriptSig)
233
- bip112emptystackinput = send_generic_input_tx (self .nodes [ 0 ], self . coinbase_blocks , self . nodeaddress )
226
+ bip112emptystackinput = self . send_generic_input_tx (self .coinbase_blocks )
234
227
235
228
# 1 normal input
236
- bip113input = send_generic_input_tx (self .nodes [ 0 ], self . coinbase_blocks , self . nodeaddress )
229
+ bip113input = self . send_generic_input_tx (self .coinbase_blocks )
237
230
238
231
self .nodes [0 ].setmocktime (self .last_block_time + 600 )
239
232
inputblockhash = self .nodes [0 ].generate (1 )[0 ] # 1 block generated for inputs to be in chain at height 431
@@ -253,36 +246,36 @@ def run_test(self):
253
246
254
247
# Test both version 1 and version 2 transactions for all tests
255
248
# BIP113 test transaction will be modified before each use to put in appropriate block time
256
- bip113tx_v1 = create_transaction ( self .nodes [ 0 ], bip113input , self . nodeaddress , amount = Decimal ( "49.98" ) )
249
+ bip113tx_v1 = self .create_self_transfer_from_utxo ( bip113input )
257
250
bip113tx_v1 .vin [0 ].nSequence = 0xFFFFFFFE
258
251
bip113tx_v1 .nVersion = 1
259
- bip113tx_v2 = create_transaction ( self .nodes [ 0 ], bip113input , self . nodeaddress , amount = Decimal ( "49.98" ) )
252
+ bip113tx_v2 = self .create_self_transfer_from_utxo ( bip113input )
260
253
bip113tx_v2 .vin [0 ].nSequence = 0xFFFFFFFE
261
254
bip113tx_v2 .nVersion = 2
262
255
263
256
# For BIP68 test all 16 relative sequence locktimes
264
- bip68txs_v1 = create_bip68txs ( self .nodes [ 0 ], bip68inputs , 1 , self . nodeaddress )
265
- bip68txs_v2 = create_bip68txs ( self .nodes [ 0 ], bip68inputs , 2 , self . nodeaddress )
257
+ bip68txs_v1 = self .create_bip68txs ( bip68inputs , 1 )
258
+ bip68txs_v2 = self .create_bip68txs ( bip68inputs , 2 )
266
259
267
260
# For BIP112 test:
268
261
# 16 relative sequence locktimes of 10 against 10 OP_CSV OP_DROP inputs
269
- bip112txs_vary_nSequence_v1 = create_bip112txs ( self .nodes [ 0 ], bip112basicinputs [0 ], False , 1 , self . nodeaddress )
270
- bip112txs_vary_nSequence_v2 = create_bip112txs ( self .nodes [ 0 ], bip112basicinputs [0 ], False , 2 , self . nodeaddress )
262
+ bip112txs_vary_nSequence_v1 = self .create_bip112txs ( bip112basicinputs [0 ], False , 1 )
263
+ bip112txs_vary_nSequence_v2 = self .create_bip112txs ( bip112basicinputs [0 ], False , 2 )
271
264
# 16 relative sequence locktimes of 9 against 10 OP_CSV OP_DROP inputs
272
- bip112txs_vary_nSequence_9_v1 = create_bip112txs ( self .nodes [ 0 ], bip112basicinputs [1 ], False , 1 , self . nodeaddress , - 1 )
273
- bip112txs_vary_nSequence_9_v2 = create_bip112txs ( self .nodes [ 0 ], bip112basicinputs [1 ], False , 2 , self . nodeaddress , - 1 )
265
+ bip112txs_vary_nSequence_9_v1 = self .create_bip112txs ( bip112basicinputs [1 ], False , 1 , - 1 )
266
+ bip112txs_vary_nSequence_9_v2 = self .create_bip112txs ( bip112basicinputs [1 ], False , 2 , - 1 )
274
267
# sequence lock time of 10 against 16 (relative_lock_time) OP_CSV OP_DROP inputs
275
- bip112txs_vary_OP_CSV_v1 = create_bip112txs ( self .nodes [ 0 ], bip112diverseinputs [0 ], True , 1 , self . nodeaddress )
276
- bip112txs_vary_OP_CSV_v2 = create_bip112txs ( self .nodes [ 0 ], bip112diverseinputs [0 ], True , 2 , self . nodeaddress )
268
+ bip112txs_vary_OP_CSV_v1 = self .create_bip112txs ( bip112diverseinputs [0 ], True , 1 )
269
+ bip112txs_vary_OP_CSV_v2 = self .create_bip112txs ( bip112diverseinputs [0 ], True , 2 )
277
270
# sequence lock time of 9 against 16 (relative_lock_time) OP_CSV OP_DROP inputs
278
- bip112txs_vary_OP_CSV_9_v1 = create_bip112txs ( self .nodes [ 0 ], bip112diverseinputs [1 ], True , 1 , self . nodeaddress , - 1 )
279
- bip112txs_vary_OP_CSV_9_v2 = create_bip112txs ( self .nodes [ 0 ], bip112diverseinputs [1 ], True , 2 , self . nodeaddress , - 1 )
271
+ bip112txs_vary_OP_CSV_9_v1 = self .create_bip112txs ( bip112diverseinputs [1 ], True , 1 , - 1 )
272
+ bip112txs_vary_OP_CSV_9_v2 = self .create_bip112txs ( bip112diverseinputs [1 ], True , 2 , - 1 )
280
273
# -1 OP_CSV OP_DROP input
281
- bip112tx_special_v1 = create_bip112special ( self .nodes [ 0 ], bip112specialinput , 1 , self . nodeaddress )
282
- bip112tx_special_v2 = create_bip112special ( self .nodes [ 0 ], bip112specialinput , 2 , self . nodeaddress )
274
+ bip112tx_special_v1 = self .create_bip112special ( bip112specialinput , 1 )
275
+ bip112tx_special_v2 = self .create_bip112special ( bip112specialinput , 2 )
283
276
# (empty stack) OP_CSV input
284
- bip112tx_emptystack_v1 = create_bip112emptystack ( self .nodes [ 0 ], bip112emptystackinput , 1 , self . nodeaddress )
285
- bip112tx_emptystack_v2 = create_bip112emptystack ( self .nodes [ 0 ], bip112emptystackinput , 2 , self . nodeaddress )
277
+ bip112tx_emptystack_v1 = self .create_bip112emptystack ( bip112emptystackinput , 1 )
278
+ bip112tx_emptystack_v2 = self .create_bip112emptystack ( bip112emptystackinput , 2 )
286
279
287
280
self .log .info ("TESTING" )
288
281
@@ -292,8 +285,8 @@ def run_test(self):
292
285
success_txs = []
293
286
# BIP113 tx, -1 CSV tx and empty stack CSV tx should succeed
294
287
bip113tx_v1 .nLockTime = self .last_block_time - 600 * 5 # = MTP of prior block (not <) but < time put on current block
295
- bip113signed1 = sign_transaction ( self . nodes [ 0 ], bip113tx_v1 )
296
- success_txs .append (bip113signed1 )
288
+ bip113tx_v1 . rehash ( )
289
+ success_txs .append (bip113tx_v1 )
297
290
success_txs .append (bip112tx_special_v1 )
298
291
success_txs .append (bip112tx_emptystack_v1 )
299
292
# add BIP 68 txs
@@ -312,8 +305,8 @@ def run_test(self):
312
305
success_txs = []
313
306
# BIP113 tx, -1 CSV tx and empty stack CSV tx should succeed
314
307
bip113tx_v2 .nLockTime = self .last_block_time - 600 * 5 # = MTP of prior block (not <) but < time put on current block
315
- bip113signed2 = sign_transaction ( self . nodes [ 0 ], bip113tx_v2 )
316
- success_txs .append (bip113signed2 )
308
+ bip113tx_v2 . rehash ( )
309
+ success_txs .append (bip113tx_v2 )
317
310
success_txs .append (bip112tx_special_v2 )
318
311
success_txs .append (bip112tx_emptystack_v2 )
319
312
# add BIP 68 txs
@@ -338,17 +331,18 @@ def run_test(self):
338
331
self .log .info ("BIP 113 tests" )
339
332
# BIP 113 tests should now fail regardless of version number if nLockTime isn't satisfied by new rules
340
333
bip113tx_v1 .nLockTime = self .last_block_time - 600 * 5 # = MTP of prior block (not <) but < time put on current block
341
- bip113signed1 = sign_transaction ( self . nodes [ 0 ], bip113tx_v1 )
334
+ bip113tx_v1 . rehash ( )
342
335
bip113tx_v2 .nLockTime = self .last_block_time - 600 * 5 # = MTP of prior block (not <) but < time put on current block
343
- bip113signed2 = sign_transaction ( self . nodes [ 0 ], bip113tx_v2 )
344
- for bip113tx in [bip113signed1 , bip113signed2 ]:
336
+ bip113tx_v2 . rehash ( )
337
+ for bip113tx in [bip113tx_v1 , bip113tx_v2 ]:
345
338
self .send_blocks ([self .create_test_block ([bip113tx ])], success = False , reject_reason = 'bad-txns-nonfinal' )
339
+
346
340
# BIP 113 tests should now pass if the locktime is < MTP
347
341
bip113tx_v1 .nLockTime = self .last_block_time - 600 * 5 - 1 # < MTP of prior block
348
- bip113signed1 = sign_transaction ( self . nodes [ 0 ], bip113tx_v1 )
342
+ bip113tx_v1 . rehash ( )
349
343
bip113tx_v2 .nLockTime = self .last_block_time - 600 * 5 - 1 # < MTP of prior block
350
- bip113signed2 = sign_transaction ( self . nodes [ 0 ], bip113tx_v2 )
351
- for bip113tx in [bip113signed1 , bip113signed2 ]:
344
+ bip113tx_v2 . rehash ( )
345
+ for bip113tx in [bip113tx_v1 , bip113tx_v2 ]:
352
346
self .send_blocks ([self .create_test_block ([bip113tx ])])
353
347
self .nodes [0 ].invalidateblock (self .nodes [0 ].getbestblockhash ())
354
348
@@ -471,8 +465,8 @@ def run_test(self):
471
465
time_txs = []
472
466
for tx in [tx ['tx' ] for tx in bip112txs_vary_OP_CSV_v2 if not tx ['sdf' ] and tx ['stf' ]]:
473
467
tx .vin [0 ].nSequence = BASE_RELATIVE_LOCKTIME | SEQ_TYPE_FLAG
474
- signtx = sign_transaction ( self . nodes [ 0 ], tx )
475
- time_txs .append (signtx )
468
+ tx . rehash ( )
469
+ time_txs .append (tx )
476
470
477
471
self .send_blocks ([self .create_test_block (time_txs )])
478
472
self .nodes [0 ].invalidateblock (self .nodes [0 ].getbestblockhash ())
0 commit comments