Skip to content

Commit 0842edf

Browse files
committed
[tests] Remove nested loops from feature_csv_activation.py
Makes the test a lot clearer.
1 parent 2e511d5 commit 0842edf

File tree

1 file changed

+75
-140
lines changed

1 file changed

+75
-140
lines changed

test/functional/feature_csv_activation.py

Lines changed: 75 additions & 140 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
bip112tx_special - test negative argument to OP_CSV
4444
"""
4545
from decimal import Decimal
46+
from itertools import product
4647
from io import BytesIO
4748
import time
4849

@@ -61,44 +62,28 @@
6162
hex_str_to_bytes,
6263
)
6364

64-
base_relative_locktime = 10
65-
seq_disable_flag = 1 << 31
66-
seq_random_high_bit = 1 << 25
67-
seq_type_flag = 1 << 22
68-
seq_random_low_bit = 1 << 18
69-
70-
# b31,b25,b22,b18 represent the 31st, 25th, 22nd and 18th bits respectively in the nSequence field
71-
# relative_locktimes[b31][b25][b22][b18] is a base_relative_locktime with the indicated bits set if their indices are 1
72-
relative_locktimes = []
73-
for b31 in range(2):
74-
b25times = []
75-
for b25 in range(2):
76-
b22times = []
77-
for b22 in range(2):
78-
b18times = []
79-
for b18 in range(2):
80-
rlt = base_relative_locktime
81-
if (b31):
82-
rlt = rlt | seq_disable_flag
83-
if (b25):
84-
rlt = rlt | seq_random_high_bit
85-
if (b22):
86-
rlt = rlt | seq_type_flag
87-
if (b18):
88-
rlt = rlt | seq_random_low_bit
89-
b18times.append(rlt)
90-
b22times.append(b18times)
91-
b25times.append(b22times)
92-
relative_locktimes.append(b25times)
93-
94-
def all_rlt_txs(txarray):
95-
txs = []
96-
for b31 in range(2):
97-
for b25 in range(2):
98-
for b22 in range(2):
99-
for b18 in range(2):
100-
txs.append(txarray[b31][b25][b22][b18])
101-
return txs
65+
BASE_RELATIVE_LOCKTIME = 10
66+
SEQ_DISABLE_FLAG = 1 << 31
67+
SEQ_RANDOM_HIGH_BIT = 1 << 25
68+
SEQ_TYPE_FLAG = 1 << 22
69+
SEQ_RANDOM_LOW_BIT = 1 << 18
70+
71+
def relative_locktime(sdf, srhb, stf, srlb):
72+
"""Returns a locktime with certain bits set."""
73+
74+
locktime = BASE_RELATIVE_LOCKTIME
75+
if sdf:
76+
locktime |= SEQ_DISABLE_FLAG
77+
if srhb:
78+
locktime |= SEQ_RANDOM_HIGH_BIT
79+
if stf:
80+
locktime |= SEQ_TYPE_FLAG
81+
if srlb:
82+
locktime |= SEQ_RANDOM_LOW_BIT
83+
return locktime
84+
85+
def all_rlt_txs(txs):
86+
return [tx['tx'] for tx in txs]
10287

10388
class BIP68_112_113Test(ComparisonTestFramework):
10489
def set_test_params(self):
@@ -152,24 +137,18 @@ def create_test_block(self, txs, version=536870912):
152137
return block
153138

154139
def create_bip68txs(self, bip68inputs, txversion, locktime_delta=0):
140+
"""Returns a list of bip68 transactions with different bits set."""
155141
txs = []
156142
assert(len(bip68inputs) >= 16)
157-
i = 0
158-
for b31 in range(2):
159-
b25txs = []
160-
for b25 in range(2):
161-
b22txs = []
162-
for b22 in range(2):
163-
b18txs = []
164-
for b18 in range(2):
165-
tx = self.create_transaction(self.nodes[0], bip68inputs[i], self.nodeaddress, Decimal("49.98"))
166-
i += 1
167-
tx.nVersion = txversion
168-
tx.vin[0].nSequence = relative_locktimes[b31][b25][b22][b18] + locktime_delta
169-
b18txs.append(self.sign_transaction(self.nodes[0], tx))
170-
b22txs.append(b18txs)
171-
b25txs.append(b22txs)
172-
txs.append(b25txs)
143+
for i, (sdf, srhb, stf, srlb) in enumerate(product(*[[True, False]] * 4)):
144+
locktime = relative_locktime(sdf, srhb, stf, srlb)
145+
tx = self.create_transaction(self.nodes[0], bip68inputs[i], self.nodeaddress, Decimal("49.98"))
146+
tx.nVersion = txversion
147+
tx.vin[0].nSequence = locktime + locktime_delta
148+
tx = self.sign_transaction(self.nodes[0], tx)
149+
tx.rehash()
150+
txs.append({'tx': tx, 'sdf': sdf, 'stf': stf})
151+
173152
return txs
174153

175154
def create_bip112special(self, input, txversion):
@@ -180,32 +159,24 @@ def create_bip112special(self, input, txversion):
180159
return signtx
181160

182161
def create_bip112txs(self, bip112inputs, varyOP_CSV, txversion, locktime_delta=0):
162+
"""Returns a list of bip68 transactions with different bits set."""
183163
txs = []
184164
assert(len(bip112inputs) >= 16)
185-
i = 0
186-
for b31 in range(2):
187-
b25txs = []
188-
for b25 in range(2):
189-
b22txs = []
190-
for b22 in range(2):
191-
b18txs = []
192-
for b18 in range(2):
193-
tx = self.create_transaction(self.nodes[0], bip112inputs[i], self.nodeaddress, Decimal("49.98"))
194-
i += 1
195-
if (varyOP_CSV): # if varying OP_CSV, nSequence is fixed
196-
tx.vin[0].nSequence = base_relative_locktime + locktime_delta
197-
else: # vary nSequence instead, OP_CSV is fixed
198-
tx.vin[0].nSequence = relative_locktimes[b31][b25][b22][b18] + locktime_delta
199-
tx.nVersion = txversion
200-
signtx = self.sign_transaction(self.nodes[0], tx)
201-
if (varyOP_CSV):
202-
signtx.vin[0].scriptSig = CScript([relative_locktimes[b31][b25][b22][b18], OP_CHECKSEQUENCEVERIFY, OP_DROP] + list(CScript(signtx.vin[0].scriptSig)))
203-
else:
204-
signtx.vin[0].scriptSig = CScript([base_relative_locktime, OP_CHECKSEQUENCEVERIFY, OP_DROP] + list(CScript(signtx.vin[0].scriptSig)))
205-
b18txs.append(signtx)
206-
b22txs.append(b18txs)
207-
b25txs.append(b22txs)
208-
txs.append(b25txs)
165+
for i, (sdf, srhb, stf, srlb) in enumerate(product(*[[True, False]] * 4)):
166+
locktime = relative_locktime(sdf, srhb, stf, srlb)
167+
tx = self.create_transaction(self.nodes[0], bip112inputs[i], self.nodeaddress, Decimal("49.98"))
168+
if (varyOP_CSV): # if varying OP_CSV, nSequence is fixed
169+
tx.vin[0].nSequence = BASE_RELATIVE_LOCKTIME + locktime_delta
170+
else: # vary nSequence instead, OP_CSV is fixed
171+
tx.vin[0].nSequence = locktime + locktime_delta
172+
tx.nVersion = txversion
173+
signtx = self.sign_transaction(self.nodes[0], tx)
174+
if (varyOP_CSV):
175+
signtx.vin[0].scriptSig = CScript([locktime, OP_CHECKSEQUENCEVERIFY, OP_DROP] + list(CScript(signtx.vin[0].scriptSig)))
176+
else:
177+
signtx.vin[0].scriptSig = CScript([BASE_RELATIVE_LOCKTIME, OP_CHECKSEQUENCEVERIFY, OP_DROP] + list(CScript(signtx.vin[0].scriptSig)))
178+
tx.rehash()
179+
txs.append({'tx': signtx, 'sdf': sdf, 'stf': stf})
209180
return txs
210181

211182
def get_tests(self):
@@ -410,25 +381,17 @@ def get_tests(self):
410381

411382
self.log.info("Test version 2 txs")
412383

413-
bip68success_txs = []
414384
# All txs with SEQUENCE_LOCKTIME_DISABLE_FLAG set pass
415-
for b25 in range(2):
416-
for b22 in range(2):
417-
for b18 in range(2):
418-
bip68success_txs.append(bip68txs_v2[1][b25][b22][b18])
385+
bip68success_txs = [tx['tx'] for tx in bip68txs_v2 if tx['sdf']]
419386
yield TestInstance([[self.create_test_block(bip68success_txs), True]])
420387
self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash())
388+
421389
# All txs without flag fail as we are at delta height = 8 < 10 and delta time = 8 * 600 < 10 * 512
422-
bip68timetxs = []
423-
for b25 in range(2):
424-
for b18 in range(2):
425-
bip68timetxs.append(bip68txs_v2[0][b25][1][b18])
390+
bip68timetxs = [tx['tx'] for tx in bip68txs_v2 if not tx['sdf'] and tx['stf']]
426391
for tx in bip68timetxs:
427392
yield TestInstance([[self.create_test_block([tx]), False]])
428-
bip68heighttxs = []
429-
for b25 in range(2):
430-
for b18 in range(2):
431-
bip68heighttxs.append(bip68txs_v2[0][b25][0][b18])
393+
394+
bip68heighttxs = [tx['tx'] for tx in bip68txs_v2 if not tx['sdf'] and not tx['stf']]
432395
for tx in bip68heighttxs:
433396
yield TestInstance([[self.create_test_block([tx]), False]])
434397

@@ -458,25 +421,17 @@ def get_tests(self):
458421
# -1 OP_CSV tx should fail
459422
yield TestInstance([[self.create_test_block([bip112tx_special_v1]), False]])
460423
# If SEQUENCE_LOCKTIME_DISABLE_FLAG is set in argument to OP_CSV, version 1 txs should still pass
461-
success_txs = []
462-
for b25 in range(2):
463-
for b22 in range(2):
464-
for b18 in range(2):
465-
success_txs.append(bip112txs_vary_OP_CSV_v1[1][b25][b22][b18])
466-
success_txs.append(bip112txs_vary_OP_CSV_9_v1[1][b25][b22][b18])
424+
425+
success_txs = [tx['tx'] for tx in bip112txs_vary_OP_CSV_v1 if tx['sdf']]
426+
success_txs += [tx['tx'] for tx in bip112txs_vary_OP_CSV_9_v1 if tx['sdf']]
467427
yield TestInstance([[self.create_test_block(success_txs), True]])
468428
self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash())
469429

470430
# If SEQUENCE_LOCKTIME_DISABLE_FLAG is unset in argument to OP_CSV, version 1 txs should now fail
471-
fail_txs = []
472-
fail_txs.extend(all_rlt_txs(bip112txs_vary_nSequence_v1))
473-
fail_txs.extend(all_rlt_txs(bip112txs_vary_nSequence_9_v1))
474-
for b25 in range(2):
475-
for b22 in range(2):
476-
for b18 in range(2):
477-
fail_txs.append(bip112txs_vary_OP_CSV_v1[0][b25][b22][b18])
478-
fail_txs.append(bip112txs_vary_OP_CSV_9_v1[0][b25][b22][b18])
479-
431+
fail_txs = all_rlt_txs(bip112txs_vary_nSequence_v1)
432+
fail_txs += all_rlt_txs(bip112txs_vary_nSequence_9_v1)
433+
fail_txs += [tx['tx'] for tx in bip112txs_vary_OP_CSV_9_v1 if not tx['sdf']]
434+
fail_txs += [tx['tx'] for tx in bip112txs_vary_OP_CSV_9_v1 if not tx['sdf']]
480435
for tx in fail_txs:
481436
yield TestInstance([[self.create_test_block([tx]), False]])
482437

@@ -486,64 +441,44 @@ def get_tests(self):
486441
yield TestInstance([[self.create_test_block([bip112tx_special_v2]), False]])
487442

488443
# If SEQUENCE_LOCKTIME_DISABLE_FLAG is set in argument to OP_CSV, version 2 txs should pass (all sequence locks are met)
489-
success_txs = []
490-
for b25 in range(2):
491-
for b22 in range(2):
492-
for b18 in range(2):
493-
success_txs.append(bip112txs_vary_OP_CSV_v2[1][b25][b22][b18]) # 8/16 of vary_OP_CSV
494-
success_txs.append(bip112txs_vary_OP_CSV_9_v2[1][b25][b22][b18]) # 8/16 of vary_OP_CSV_9
444+
success_txs = [tx['tx'] for tx in bip112txs_vary_OP_CSV_v2 if tx['sdf']]
445+
success_txs += [tx['tx'] for tx in bip112txs_vary_OP_CSV_9_v2 if tx['sdf']]
495446

496447
yield TestInstance([[self.create_test_block(success_txs), True]])
497448
self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash())
498449

499450
# SEQUENCE_LOCKTIME_DISABLE_FLAG is unset in argument to OP_CSV for all remaining txs ##
500451

501452
# All txs with nSequence 9 should fail either due to earlier mismatch or failing the CSV check
502-
fail_txs = []
503-
fail_txs.extend(all_rlt_txs(bip112txs_vary_nSequence_9_v2)) # 16/16 of vary_nSequence_9
504-
for b25 in range(2):
505-
for b22 in range(2):
506-
for b18 in range(2):
507-
fail_txs.append(bip112txs_vary_OP_CSV_9_v2[0][b25][b22][b18]) # 16/16 of vary_OP_CSV_9
508-
453+
fail_txs = all_rlt_txs(bip112txs_vary_nSequence_9_v2)
454+
fail_txs += [tx['tx'] for tx in bip112txs_vary_OP_CSV_9_v2 if not tx['sdf']]
509455
for tx in fail_txs:
510456
yield TestInstance([[self.create_test_block([tx]), False]])
511457

512458
# If SEQUENCE_LOCKTIME_DISABLE_FLAG is set in nSequence, tx should fail
513-
fail_txs = []
514-
for b25 in range(2):
515-
for b22 in range(2):
516-
for b18 in range(2):
517-
fail_txs.append(bip112txs_vary_nSequence_v2[1][b25][b22][b18]) # 8/16 of vary_nSequence
459+
fail_txs = [tx['tx'] for tx in bip112txs_vary_nSequence_v2 if tx['sdf']]
518460
for tx in fail_txs:
519461
yield TestInstance([[self.create_test_block([tx]), False]])
520462

521463
# If sequencelock types mismatch, tx should fail
522-
fail_txs = []
523-
for b25 in range(2):
524-
for b18 in range(2):
525-
fail_txs.append(bip112txs_vary_nSequence_v2[0][b25][1][b18]) # 12/16 of vary_nSequence
526-
fail_txs.append(bip112txs_vary_OP_CSV_v2[0][b25][1][b18]) # 12/16 of vary_OP_CSV
464+
fail_txs = [tx['tx'] for tx in bip112txs_vary_nSequence_v2 if not tx['sdf'] and tx['stf']]
465+
fail_txs += [tx['tx'] for tx in bip112txs_vary_OP_CSV_v2 if not tx['sdf'] and tx['stf']]
527466
for tx in fail_txs:
528467
yield TestInstance([[self.create_test_block([tx]), False]])
529468

530469
# Remaining txs should pass, just test masking works properly
531-
success_txs = []
532-
for b25 in range(2):
533-
for b18 in range(2):
534-
success_txs.append(bip112txs_vary_nSequence_v2[0][b25][0][b18]) # 16/16 of vary_nSequence
535-
success_txs.append(bip112txs_vary_OP_CSV_v2[0][b25][0][b18]) # 16/16 of vary_OP_CSV
470+
success_txs = [tx['tx'] for tx in bip112txs_vary_nSequence_v2 if not tx['sdf'] and not tx['stf']]
471+
success_txs += [tx['tx'] for tx in bip112txs_vary_OP_CSV_v2 if not tx['sdf'] and not tx['stf']]
536472
yield TestInstance([[self.create_test_block(success_txs), True]]) # 124
537473
self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash())
538474

539475
# Additional test, of checking that comparison of two time types works properly
540476
time_txs = []
541-
for b25 in range(2):
542-
for b18 in range(2):
543-
tx = bip112txs_vary_OP_CSV_v2[0][b25][1][b18]
544-
tx.vin[0].nSequence = base_relative_locktime | seq_type_flag
545-
signtx = self.sign_transaction(self.nodes[0], tx)
546-
time_txs.append(signtx)
477+
for tx in [tx['tx'] for tx in bip112txs_vary_OP_CSV_v2 if not tx['sdf'] and tx['stf']]:
478+
tx.vin[0].nSequence = BASE_RELATIVE_LOCKTIME | SEQ_TYPE_FLAG
479+
signtx = self.sign_transaction(self.nodes[0], tx)
480+
time_txs.append(signtx)
481+
547482
yield TestInstance([[self.create_test_block(time_txs), True]])
548483
self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash())
549484

0 commit comments

Comments
 (0)