@@ -103,14 +103,22 @@ def test_simple_doublespend(self):
103103 """Simple doublespend"""
104104 # we use MiniWallet to create a transaction template with inputs correctly set,
105105 # 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" ]
107107 tx1a_txid = self .nodes [0 ].sendrawtransaction (tx .serialize ().hex ())
108108
109109 # Should fail because we haven't changed the fee
110110 tx .vout [0 ].scriptPubKey [- 1 ] ^= 1
111+ tx .rehash ()
112+ tx_hex = tx .serialize ().hex ()
111113
112114 # 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+
114122
115123 # Extra 0.1 BTC fee
116124 tx .vout [0 ].nValue -= int (0.1 * COIN )
@@ -154,7 +162,14 @@ def test_doublespend_chain(self):
154162 dbl_tx_hex = dbl_tx .serialize ().hex ()
155163
156164 # 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+
158173
159174 # Accepted with sufficient fee
160175 dbl_tx .vout [0 ].nValue = int (0.1 * COIN )
@@ -273,22 +288,30 @@ def test_spends_of_conflicting_outputs(self):
273288 utxo1 = self .make_utxo (self .nodes [0 ], int (1.2 * COIN ))
274289 utxo2 = self .make_utxo (self .nodes [0 ], 3 * COIN )
275290
276- tx1a_utxo = self .wallet .send_self_transfer (
291+ tx1a = self .wallet .send_self_transfer (
277292 from_node = self .nodes [0 ],
278293 utxo_to_spend = utxo1 ,
279294 sequence = 0 ,
280295 fee = Decimal ("0.1" ),
281- )["new_utxo" ]
296+ )
297+ tx1a_utxo = tx1a ["new_utxo" ]
282298
283299 # 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 (
285301 utxos_to_spend = [utxo1 , utxo2 , tx1a_utxo ],
286302 sequence = 0 ,
287303 amount_per_output = int (COIN * tx1a_utxo ["value" ]),
288- )["hex" ]
304+ )["tx" ]
305+ tx2_hex = tx2 .serialize ().hex ()
289306
290307 # 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+
292315
293316 # Spend tx1a's output to test the indirect case.
294317 tx1b_utxo = self .wallet .send_self_transfer (
@@ -319,14 +342,21 @@ def test_new_unconfirmed_inputs(self):
319342 fee = Decimal ("0.1" ),
320343 )
321344
322- tx2_hex = self .wallet .create_self_transfer_multi (
345+ tx2 = self .wallet .create_self_transfer_multi (
323346 utxos_to_spend = [confirmed_utxo , unconfirmed_utxo ],
324347 sequence = 0 ,
325348 amount_per_output = 1 * COIN ,
326- )["hex" ]
349+ )["tx" ]
350+ tx2_hex = tx2 .serialize ().hex ()
327351
328352 # 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+
330360
331361 def test_too_many_replacements (self ):
332362 """Replacements that evict too many transactions are rejected"""
@@ -368,7 +398,13 @@ def test_too_many_replacements(self):
368398 double_tx_hex = double_tx .serialize ().hex ()
369399
370400 # 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+
372408
373409 # If we remove an input, it should pass
374410 double_tx .vin .pop ()
0 commit comments