@@ -103,14 +103,22 @@ def test_simple_doublespend(self):
103
103
"""Simple doublespend"""
104
104
# we use MiniWallet to create a transaction template with inputs correctly set,
105
105
# and modify the output (amount, scriptPubKey) according to our needs
106
- tx = self .wallet .create_self_transfer ()["tx" ]
106
+ tx = self .wallet .create_self_transfer (fee_rate = Decimal ( "0.003" ) )["tx" ]
107
107
tx1a_txid = self .nodes [0 ].sendrawtransaction (tx .serialize ().hex ())
108
108
109
109
# Should fail because we haven't changed the fee
110
110
tx .vout [0 ].scriptPubKey [- 1 ] ^= 1
111
+ tx .rehash ()
112
+ tx_hex = tx .serialize ().hex ()
111
113
112
114
# This will raise an exception due to insufficient fee
113
- assert_raises_rpc_error (- 26 , "insufficient fee" , self .nodes [0 ].sendrawtransaction , tx .serialize ().hex (), 0 )
115
+ reject_reason = "insufficient fee"
116
+ reject_details = f"{ reject_reason } , rejecting replacement { tx .hash } ; new feerate 0.00300000 BTC/kvB <= old feerate 0.00300000 BTC/kvB"
117
+ res = self .nodes [0 ].testmempoolaccept (rawtxs = [tx_hex ])[0 ]
118
+ assert_equal (res ["reject-reason" ], reject_reason )
119
+ assert_equal (res ["reject-details" ], reject_details )
120
+ assert_raises_rpc_error (- 26 , f"{ reject_details } " , self .nodes [0 ].sendrawtransaction , tx_hex , 0 )
121
+
114
122
115
123
# Extra 0.1 BTC fee
116
124
tx .vout [0 ].nValue -= int (0.1 * COIN )
@@ -154,7 +162,14 @@ def test_doublespend_chain(self):
154
162
dbl_tx_hex = dbl_tx .serialize ().hex ()
155
163
156
164
# This will raise an exception due to insufficient fee
157
- assert_raises_rpc_error (- 26 , "insufficient fee" , self .nodes [0 ].sendrawtransaction , dbl_tx_hex , 0 )
165
+ reject_reason = "insufficient fee"
166
+ reject_details = f"{ reject_reason } , rejecting replacement { dbl_tx .hash } , less fees than conflicting txs; 3.00 < 4.00"
167
+ res = self .nodes [0 ].testmempoolaccept (rawtxs = [dbl_tx_hex ])[0 ]
168
+ assert_equal (res ["reject-reason" ], reject_reason )
169
+ assert_equal (res ["reject-details" ], reject_details )
170
+ assert_raises_rpc_error (- 26 , f"{ reject_details } " , self .nodes [0 ].sendrawtransaction , dbl_tx_hex , 0 )
171
+
172
+
158
173
159
174
# Accepted with sufficient fee
160
175
dbl_tx .vout [0 ].nValue = int (0.1 * COIN )
@@ -273,22 +288,30 @@ def test_spends_of_conflicting_outputs(self):
273
288
utxo1 = self .make_utxo (self .nodes [0 ], int (1.2 * COIN ))
274
289
utxo2 = self .make_utxo (self .nodes [0 ], 3 * COIN )
275
290
276
- tx1a_utxo = self .wallet .send_self_transfer (
291
+ tx1a = self .wallet .send_self_transfer (
277
292
from_node = self .nodes [0 ],
278
293
utxo_to_spend = utxo1 ,
279
294
sequence = 0 ,
280
295
fee = Decimal ("0.1" ),
281
- )["new_utxo" ]
296
+ )
297
+ tx1a_utxo = tx1a ["new_utxo" ]
282
298
283
299
# Direct spend an output of the transaction we're replacing.
284
- tx2_hex = self .wallet .create_self_transfer_multi (
300
+ tx2 = self .wallet .create_self_transfer_multi (
285
301
utxos_to_spend = [utxo1 , utxo2 , tx1a_utxo ],
286
302
sequence = 0 ,
287
303
amount_per_output = int (COIN * tx1a_utxo ["value" ]),
288
- )["hex" ]
304
+ )["tx" ]
305
+ tx2_hex = tx2 .serialize ().hex ()
289
306
290
307
# This will raise an exception
291
- assert_raises_rpc_error (- 26 , "bad-txns-spends-conflicting-tx" , self .nodes [0 ].sendrawtransaction , tx2_hex , 0 )
308
+ reject_reason = "bad-txns-spends-conflicting-tx"
309
+ reject_details = f"{ reject_reason } , { tx2 .hash } spends conflicting transaction { tx1a ['tx' ].hash } "
310
+ res = self .nodes [0 ].testmempoolaccept (rawtxs = [tx2_hex ])[0 ]
311
+ assert_equal (res ["reject-reason" ], reject_reason )
312
+ assert_equal (res ["reject-details" ], reject_details )
313
+ assert_raises_rpc_error (- 26 , f"{ reject_details } " , self .nodes [0 ].sendrawtransaction , tx2_hex , 0 )
314
+
292
315
293
316
# Spend tx1a's output to test the indirect case.
294
317
tx1b_utxo = self .wallet .send_self_transfer (
@@ -319,14 +342,21 @@ def test_new_unconfirmed_inputs(self):
319
342
fee = Decimal ("0.1" ),
320
343
)
321
344
322
- tx2_hex = self .wallet .create_self_transfer_multi (
345
+ tx2 = self .wallet .create_self_transfer_multi (
323
346
utxos_to_spend = [confirmed_utxo , unconfirmed_utxo ],
324
347
sequence = 0 ,
325
348
amount_per_output = 1 * COIN ,
326
- )["hex" ]
349
+ )["tx" ]
350
+ tx2_hex = tx2 .serialize ().hex ()
327
351
328
352
# This will raise an exception
329
- assert_raises_rpc_error (- 26 , "replacement-adds-unconfirmed" , self .nodes [0 ].sendrawtransaction , tx2_hex , 0 )
353
+ reject_reason = "replacement-adds-unconfirmed"
354
+ reject_details = f"{ reject_reason } , replacement { tx2 .hash } adds unconfirmed input, idx 1"
355
+ res = self .nodes [0 ].testmempoolaccept (rawtxs = [tx2_hex ])[0 ]
356
+ assert_equal (res ["reject-reason" ], reject_reason )
357
+ assert_equal (res ["reject-details" ], reject_details )
358
+ assert_raises_rpc_error (- 26 , f"{ reject_details } " , self .nodes [0 ].sendrawtransaction , tx2_hex , 0 )
359
+
330
360
331
361
def test_too_many_replacements (self ):
332
362
"""Replacements that evict too many transactions are rejected"""
@@ -368,7 +398,13 @@ def test_too_many_replacements(self):
368
398
double_tx_hex = double_tx .serialize ().hex ()
369
399
370
400
# This will raise an exception
371
- assert_raises_rpc_error (- 26 , "too many potential replacements" , self .nodes [0 ].sendrawtransaction , double_tx_hex , 0 )
401
+ reject_reason = "too many potential replacements"
402
+ reject_details = f"{ reject_reason } , rejecting replacement { double_tx .hash } ; too many potential replacements ({ MAX_REPLACEMENT_LIMIT + 1 } > { MAX_REPLACEMENT_LIMIT } )"
403
+ res = self .nodes [0 ].testmempoolaccept (rawtxs = [double_tx_hex ])[0 ]
404
+ assert_equal (res ["reject-reason" ], reject_reason )
405
+ assert_equal (res ["reject-details" ], reject_details )
406
+ assert_raises_rpc_error (- 26 , f"{ reject_details } " , self .nodes [0 ].sendrawtransaction , double_tx_hex , 0 )
407
+
372
408
373
409
# If we remove an input, it should pass
374
410
double_tx .vin .pop ()
0 commit comments