20
20
def txToHex (tx ):
21
21
return tx .serialize ().hex ()
22
22
23
+
23
24
def make_utxo (node , amount , confirmed = True , scriptPubKey = DUMMY_P2WPKH_SCRIPT ):
24
25
"""Create a txout with a given amount and scriptPubKey
25
26
@@ -28,12 +29,12 @@ def make_utxo(node, amount, confirmed=True, scriptPubKey=DUMMY_P2WPKH_SCRIPT):
28
29
confirmed - txouts created will be confirmed in the blockchain;
29
30
unconfirmed otherwise.
30
31
"""
31
- fee = 1 * COIN
32
- while node .getbalance () < satoshi_round ((amount + fee )/ COIN ):
32
+ fee = 1 * COIN
33
+ while node .getbalance () < satoshi_round ((amount + fee ) / COIN ):
33
34
node .generate (COINBASE_MATURITY )
34
35
35
36
new_addr = node .getnewaddress ()
36
- txid = node .sendtoaddress (new_addr , satoshi_round ((amount + fee )/ COIN ))
37
+ txid = node .sendtoaddress (new_addr , satoshi_round ((amount + fee ) / COIN ))
37
38
tx1 = node .getrawtransaction (txid , 1 )
38
39
txid = int (txid , 16 )
39
40
i , _ = next (filter (lambda vout : new_addr == vout [1 ]['scriptPubKey' ]['address' ], enumerate (tx1 ['vout' ])))
@@ -80,7 +81,7 @@ def skip_test_if_missing_module(self):
80
81
self .skip_if_no_wallet ()
81
82
82
83
def run_test (self ):
83
- make_utxo (self .nodes [0 ], 1 * COIN )
84
+ make_utxo (self .nodes [0 ], 1 * COIN )
84
85
85
86
# Ensure nodes are synced
86
87
self .sync_all ()
@@ -122,7 +123,7 @@ def run_test(self):
122
123
123
124
def test_simple_doublespend (self ):
124
125
"""Simple doublespend"""
125
- tx0_outpoint = make_utxo (self .nodes [0 ], int (1.1 * COIN ))
126
+ tx0_outpoint = make_utxo (self .nodes [0 ], int (1.1 * COIN ))
126
127
127
128
# make_utxo may have generated a bunch of blocks, so we need to sync
128
129
# before we can spend the coins generated, or else the resulting
@@ -164,14 +165,14 @@ def test_simple_doublespend(self):
164
165
def test_doublespend_chain (self ):
165
166
"""Doublespend of a long chain"""
166
167
167
- initial_nValue = 50 * COIN
168
+ initial_nValue = 50 * COIN
168
169
tx0_outpoint = make_utxo (self .nodes [0 ], initial_nValue )
169
170
170
171
prevout = tx0_outpoint
171
172
remaining_value = initial_nValue
172
173
chain_txids = []
173
- while remaining_value > 10 * COIN :
174
- remaining_value -= 1 * COIN
174
+ while remaining_value > 10 * COIN :
175
+ remaining_value -= 1 * COIN
175
176
tx = CTransaction ()
176
177
tx .vin = [CTxIn (prevout , nSequence = 0 )]
177
178
tx .vout = [CTxOut (remaining_value , CScript ([1 , OP_DROP ] * 15 + [1 ]))]
@@ -204,10 +205,10 @@ def test_doublespend_chain(self):
204
205
def test_doublespend_tree (self ):
205
206
"""Doublespend of a big tree of transactions"""
206
207
207
- initial_nValue = 50 * COIN
208
+ initial_nValue = 50 * COIN
208
209
tx0_outpoint = make_utxo (self .nodes [0 ], initial_nValue )
209
210
210
- def branch (prevout , initial_value , max_txs , tree_width = 5 , fee = 0.0001 * COIN , _total_txs = None ):
211
+ def branch (prevout , initial_value , max_txs , tree_width = 5 , fee = 0.0001 * COIN , _total_txs = None ):
211
212
if _total_txs is None :
212
213
_total_txs = [0 ]
213
214
if _total_txs [0 ] >= max_txs :
@@ -238,7 +239,7 @@ def branch(prevout, initial_value, max_txs, tree_width=5, fee=0.0001*COIN, _tota
238
239
_total_txs = _total_txs ):
239
240
yield x
240
241
241
- fee = int (0.0001 * COIN )
242
+ fee = int (0.0001 * COIN )
242
243
n = MAX_REPLACEMENT_LIMIT
243
244
tree_txs = list (branch (tx0_outpoint , initial_nValue , n , fee = fee ))
244
245
assert_equal (len (tree_txs ), n )
@@ -266,8 +267,8 @@ def branch(prevout, initial_value, max_txs, tree_width=5, fee=0.0001*COIN, _tota
266
267
267
268
# Try again, but with more total transactions than the "max txs
268
269
# double-spent at once" anti-DoS limit.
269
- for n in (MAX_REPLACEMENT_LIMIT + 1 , MAX_REPLACEMENT_LIMIT * 2 ):
270
- fee = int (0.0001 * COIN )
270
+ for n in (MAX_REPLACEMENT_LIMIT + 1 , MAX_REPLACEMENT_LIMIT * 2 ):
271
+ fee = int (0.0001 * COIN )
271
272
tx0_outpoint = make_utxo (self .nodes [0 ], initial_nValue )
272
273
tree_txs = list (branch (tx0_outpoint , initial_nValue , n , fee = fee ))
273
274
assert_equal (len (tree_txs ), n )
@@ -285,7 +286,7 @@ def branch(prevout, initial_value, max_txs, tree_width=5, fee=0.0001*COIN, _tota
285
286
286
287
def test_replacement_feeperkb (self ):
287
288
"""Replacement requires fee-per-KB to be higher"""
288
- tx0_outpoint = make_utxo (self .nodes [0 ], int (1.1 * COIN ))
289
+ tx0_outpoint = make_utxo (self .nodes [0 ], int (1.1 * COIN ))
289
290
290
291
tx1a = CTransaction ()
291
292
tx1a .vin = [CTxIn (tx0_outpoint , nSequence = 0 )]
@@ -297,16 +298,16 @@ def test_replacement_feeperkb(self):
297
298
# rejected.
298
299
tx1b = CTransaction ()
299
300
tx1b .vin = [CTxIn (tx0_outpoint , nSequence = 0 )]
300
- tx1b .vout = [CTxOut (int (0.001 * COIN ), CScript ([b'a' * 999000 ]))]
301
+ tx1b .vout = [CTxOut (int (0.001 * COIN ), CScript ([b'a' * 999000 ]))]
301
302
tx1b_hex = txToHex (tx1b )
302
303
303
304
# This will raise an exception due to insufficient fee
304
305
assert_raises_rpc_error (- 26 , "insufficient fee" , self .nodes [0 ].sendrawtransaction , tx1b_hex , 0 )
305
306
306
307
def test_spends_of_conflicting_outputs (self ):
307
308
"""Replacements that spend conflicting tx outputs are rejected"""
308
- utxo1 = make_utxo (self .nodes [0 ], int (1.2 * COIN ))
309
- utxo2 = make_utxo (self .nodes [0 ], 3 * COIN )
309
+ utxo1 = make_utxo (self .nodes [0 ], int (1.2 * COIN ))
310
+ utxo2 = make_utxo (self .nodes [0 ], 3 * COIN )
310
311
311
312
tx1a = CTransaction ()
312
313
tx1a .vin = [CTxIn (utxo1 , nSequence = 0 )]
@@ -345,8 +346,8 @@ def test_spends_of_conflicting_outputs(self):
345
346
346
347
def test_new_unconfirmed_inputs (self ):
347
348
"""Replacements that add new unconfirmed inputs are rejected"""
348
- confirmed_utxo = make_utxo (self .nodes [0 ], int (1.1 * COIN ))
349
- unconfirmed_utxo = make_utxo (self .nodes [0 ], int (0.1 * COIN ), False )
349
+ confirmed_utxo = make_utxo (self .nodes [0 ], int (1.1 * COIN ))
350
+ unconfirmed_utxo = make_utxo (self .nodes [0 ], int (0.1 * COIN ), False )
350
351
351
352
tx1 = CTransaction ()
352
353
tx1 .vin = [CTxIn (confirmed_utxo )]
@@ -368,13 +369,13 @@ def test_too_many_replacements(self):
368
369
# transactions
369
370
370
371
# Start by creating a single transaction with many outputs
371
- initial_nValue = 10 * COIN
372
+ initial_nValue = 10 * COIN
372
373
utxo = make_utxo (self .nodes [0 ], initial_nValue )
373
- fee = int (0.0001 * COIN )
374
- split_value = int ((initial_nValue - fee )/ (MAX_REPLACEMENT_LIMIT + 1 ))
374
+ fee = int (0.0001 * COIN )
375
+ split_value = int ((initial_nValue - fee ) / (MAX_REPLACEMENT_LIMIT + 1 ))
375
376
376
377
outputs = []
377
- for _ in range (MAX_REPLACEMENT_LIMIT + 1 ):
378
+ for _ in range (MAX_REPLACEMENT_LIMIT + 1 ):
378
379
outputs .append (CTxOut (split_value , CScript ([1 ])))
379
380
380
381
splitting_tx = CTransaction ()
@@ -386,7 +387,7 @@ def test_too_many_replacements(self):
386
387
txid = int (txid , 16 )
387
388
388
389
# Now spend each of those outputs individually
389
- for i in range (MAX_REPLACEMENT_LIMIT + 1 ):
390
+ for i in range (MAX_REPLACEMENT_LIMIT + 1 ):
390
391
tx_i = CTransaction ()
391
392
tx_i .vin = [CTxIn (COutPoint (txid , i ), nSequence = 0 )]
392
393
tx_i .vout = [CTxOut (split_value - fee , DUMMY_P2WPKH_SCRIPT )]
@@ -396,9 +397,9 @@ def test_too_many_replacements(self):
396
397
# Now create doublespend of the whole lot; should fail.
397
398
# Need a big enough fee to cover all spending transactions and have
398
399
# a higher fee rate
399
- double_spend_value = (split_value - 100 * fee )* (MAX_REPLACEMENT_LIMIT + 1 )
400
+ double_spend_value = (split_value - 100 * fee ) * (MAX_REPLACEMENT_LIMIT + 1 )
400
401
inputs = []
401
- for i in range (MAX_REPLACEMENT_LIMIT + 1 ):
402
+ for i in range (MAX_REPLACEMENT_LIMIT + 1 ):
402
403
inputs .append (CTxIn (COutPoint (txid , i ), nSequence = 0 ))
403
404
double_tx = CTransaction ()
404
405
double_tx .vin = inputs
@@ -417,7 +418,7 @@ def test_too_many_replacements(self):
417
418
418
419
def test_opt_in (self ):
419
420
"""Replacing should only work if orig tx opted in"""
420
- tx0_outpoint = make_utxo (self .nodes [0 ], int (1.1 * COIN ))
421
+ tx0_outpoint = make_utxo (self .nodes [0 ], int (1.1 * COIN ))
421
422
422
423
# Create a non-opting in transaction
423
424
tx1a = CTransaction ()
@@ -438,7 +439,7 @@ def test_opt_in(self):
438
439
# This will raise an exception
439
440
assert_raises_rpc_error (- 26 , "txn-mempool-conflict" , self .nodes [0 ].sendrawtransaction , tx1b_hex , 0 )
440
441
441
- tx1_outpoint = make_utxo (self .nodes [0 ], int (1.1 * COIN ))
442
+ tx1_outpoint = make_utxo (self .nodes [0 ], int (1.1 * COIN ))
442
443
443
444
# Create a different non-opting in transaction
444
445
tx2a = CTransaction ()
@@ -466,7 +467,7 @@ def test_opt_in(self):
466
467
tx3a = CTransaction ()
467
468
tx3a .vin = [CTxIn (COutPoint (tx1a_txid , 0 ), nSequence = 0xffffffff ),
468
469
CTxIn (COutPoint (tx2a_txid , 0 ), nSequence = 0xfffffffd )]
469
- tx3a .vout = [CTxOut (int (0.9 * COIN ), CScript ([b'c' ])), CTxOut (int (0.9 * COIN ), CScript ([b'd' ]))]
470
+ tx3a .vout = [CTxOut (int (0.9 * COIN ), CScript ([b'c' ])), CTxOut (int (0.9 * COIN ), CScript ([b'd' ]))]
470
471
tx3a_hex = txToHex (tx3a )
471
472
472
473
tx3a_txid = self .nodes [0 ].sendrawtransaction (tx3a_hex , 0 )
@@ -494,7 +495,7 @@ def test_prioritised_transactions(self):
494
495
# correctly used by replacement logic
495
496
496
497
# 1. Check that feeperkb uses modified fees
497
- tx0_outpoint = make_utxo (self .nodes [0 ], int (1.1 * COIN ))
498
+ tx0_outpoint = make_utxo (self .nodes [0 ], int (1.1 * COIN ))
498
499
499
500
tx1a = CTransaction ()
500
501
tx1a .vin = [CTxIn (tx0_outpoint , nSequence = 0 )]
@@ -505,22 +506,22 @@ def test_prioritised_transactions(self):
505
506
# Higher fee, but the actual fee per KB is much lower.
506
507
tx1b = CTransaction ()
507
508
tx1b .vin = [CTxIn (tx0_outpoint , nSequence = 0 )]
508
- tx1b .vout = [CTxOut (int (0.001 * COIN ), CScript ([b'a' * 740000 ]))]
509
+ tx1b .vout = [CTxOut (int (0.001 * COIN ), CScript ([b'a' * 740000 ]))]
509
510
tx1b_hex = txToHex (tx1b )
510
511
511
512
# Verify tx1b cannot replace tx1a.
512
513
assert_raises_rpc_error (- 26 , "insufficient fee" , self .nodes [0 ].sendrawtransaction , tx1b_hex , 0 )
513
514
514
515
# Use prioritisetransaction to set tx1a's fee to 0.
515
- self .nodes [0 ].prioritisetransaction (txid = tx1a_txid , fee_delta = int (- 0.1 * COIN ))
516
+ self .nodes [0 ].prioritisetransaction (txid = tx1a_txid , fee_delta = int (- 0.1 * COIN ))
516
517
517
518
# Now tx1b should be able to replace tx1a
518
519
tx1b_txid = self .nodes [0 ].sendrawtransaction (tx1b_hex , 0 )
519
520
520
521
assert tx1b_txid in self .nodes [0 ].getrawmempool ()
521
522
522
523
# 2. Check that absolute fee checks use modified fee.
523
- tx1_outpoint = make_utxo (self .nodes [0 ], int (1.1 * COIN ))
524
+ tx1_outpoint = make_utxo (self .nodes [0 ], int (1.1 * COIN ))
524
525
525
526
tx2a = CTransaction ()
526
527
tx2a .vin = [CTxIn (tx1_outpoint , nSequence = 0 )]
@@ -539,7 +540,7 @@ def test_prioritised_transactions(self):
539
540
assert_raises_rpc_error (- 26 , "insufficient fee" , self .nodes [0 ].sendrawtransaction , tx2b_hex , 0 )
540
541
541
542
# Now prioritise tx2b to have a higher modified fee
542
- self .nodes [0 ].prioritisetransaction (txid = tx2b .hash , fee_delta = int (0.1 * COIN ))
543
+ self .nodes [0 ].prioritisetransaction (txid = tx2b .hash , fee_delta = int (0.1 * COIN ))
543
544
544
545
# tx2b should now be accepted
545
546
tx2b_txid = self .nodes [0 ].sendrawtransaction (tx2b_hex , 0 )
@@ -549,20 +550,20 @@ def test_prioritised_transactions(self):
549
550
def test_rpc (self ):
550
551
us0 = self .nodes [0 ].listunspent ()[0 ]
551
552
ins = [us0 ]
552
- outs = {self .nodes [0 ].getnewaddress () : Decimal (1.0000000 )}
553
+ outs = {self .nodes [0 ].getnewaddress (): Decimal (1.0000000 )}
553
554
rawtx0 = self .nodes [0 ].createrawtransaction (ins , outs , 0 , True )
554
555
rawtx1 = self .nodes [0 ].createrawtransaction (ins , outs , 0 , False )
555
- json0 = self .nodes [0 ].decoderawtransaction (rawtx0 )
556
- json1 = self .nodes [0 ].decoderawtransaction (rawtx1 )
556
+ json0 = self .nodes [0 ].decoderawtransaction (rawtx0 )
557
+ json1 = self .nodes [0 ].decoderawtransaction (rawtx1 )
557
558
assert_equal (json0 ["vin" ][0 ]["sequence" ], 4294967293 )
558
559
assert_equal (json1 ["vin" ][0 ]["sequence" ], 4294967295 )
559
560
560
561
rawtx2 = self .nodes [0 ].createrawtransaction ([], outs )
561
562
frawtx2a = self .nodes [0 ].fundrawtransaction (rawtx2 , {"replaceable" : True })
562
563
frawtx2b = self .nodes [0 ].fundrawtransaction (rawtx2 , {"replaceable" : False })
563
564
564
- json0 = self .nodes [0 ].decoderawtransaction (frawtx2a ['hex' ])
565
- json1 = self .nodes [0 ].decoderawtransaction (frawtx2b ['hex' ])
565
+ json0 = self .nodes [0 ].decoderawtransaction (frawtx2a ['hex' ])
566
+ json1 = self .nodes [0 ].decoderawtransaction (frawtx2b ['hex' ])
566
567
assert_equal (json0 ["vin" ][0 ]["sequence" ], 4294967293 )
567
568
assert_equal (json1 ["vin" ][0 ]["sequence" ], 4294967294 )
568
569
@@ -623,5 +624,6 @@ def test_no_inherited_signaling(self):
623
624
assert_equal (True , self .nodes [0 ].getmempoolentry (optin_parent_tx ['txid' ])['bip125-replaceable' ])
624
625
assert_raises_rpc_error (- 26 , 'txn-mempool-conflict' , self .nodes [0 ].sendrawtransaction , replacement_child_tx ["hex" ], 0 )
625
626
627
+
626
628
if __name__ == '__main__' :
627
629
ReplaceByFeeTest ().main ()
0 commit comments