test: cover testmempoolaccept debug-message in RBF test

This commit is contained in:
Matthew Zipkin 2023-07-21 10:42:41 -04:00
parent f9650e18ea
commit f9cac63523
No known key found for this signature in database
GPG key ID: E7E2984B6289C93A

View file

@ -103,14 +103,22 @@ class ReplaceByFeeTest(BitcoinTestFramework):
"""Simple doublespend""" """Simple doublespend"""
# we use MiniWallet to create a transaction template with inputs correctly set, # we use MiniWallet to create a transaction template with inputs correctly set,
# and modify the output (amount, scriptPubKey) according to our needs # and modify the output (amount, scriptPubKey) according to our needs
tx = self.wallet.create_self_transfer()["tx"] tx = self.wallet.create_self_transfer(fee_rate=Decimal("0.003"))["tx"]
tx1a_txid = self.nodes[0].sendrawtransaction(tx.serialize().hex()) tx1a_txid = self.nodes[0].sendrawtransaction(tx.serialize().hex())
# Should fail because we haven't changed the fee # Should fail because we haven't changed the fee
tx.vout[0].scriptPubKey[-1] ^= 1 tx.vout[0].scriptPubKey[-1] ^= 1
tx.rehash()
tx_hex = tx.serialize().hex()
# This will raise an exception due to insufficient fee # This will raise an exception due to insufficient fee
assert_raises_rpc_error(-26, "insufficient fee", self.nodes[0].sendrawtransaction, tx.serialize().hex(), 0) reject_reason = "insufficient fee"
reject_details = f"{reject_reason}, rejecting replacement {tx.hash}; new feerate 0.00300000 BTC/kvB <= old feerate 0.00300000 BTC/kvB"
res = self.nodes[0].testmempoolaccept(rawtxs=[tx_hex])[0]
assert_equal(res["reject-reason"], reject_reason)
assert_equal(res["reject-details"], reject_details)
assert_raises_rpc_error(-26, f"{reject_details}", self.nodes[0].sendrawtransaction, tx_hex, 0)
# Extra 0.1 BTC fee # Extra 0.1 BTC fee
tx.vout[0].nValue -= int(0.1 * COIN) tx.vout[0].nValue -= int(0.1 * COIN)
@ -154,7 +162,14 @@ class ReplaceByFeeTest(BitcoinTestFramework):
dbl_tx_hex = dbl_tx.serialize().hex() dbl_tx_hex = dbl_tx.serialize().hex()
# This will raise an exception due to insufficient fee # This will raise an exception due to insufficient fee
assert_raises_rpc_error(-26, "insufficient fee", self.nodes[0].sendrawtransaction, dbl_tx_hex, 0) reject_reason = "insufficient fee"
reject_details = f"{reject_reason}, rejecting replacement {dbl_tx.hash}, less fees than conflicting txs; 3.00 < 4.00"
res = self.nodes[0].testmempoolaccept(rawtxs=[dbl_tx_hex])[0]
assert_equal(res["reject-reason"], reject_reason)
assert_equal(res["reject-details"], reject_details)
assert_raises_rpc_error(-26, f"{reject_details}", self.nodes[0].sendrawtransaction, dbl_tx_hex, 0)
# Accepted with sufficient fee # Accepted with sufficient fee
dbl_tx.vout[0].nValue = int(0.1 * COIN) dbl_tx.vout[0].nValue = int(0.1 * COIN)
@ -273,22 +288,30 @@ class ReplaceByFeeTest(BitcoinTestFramework):
utxo1 = self.make_utxo(self.nodes[0], int(1.2 * COIN)) utxo1 = self.make_utxo(self.nodes[0], int(1.2 * COIN))
utxo2 = self.make_utxo(self.nodes[0], 3 * COIN) utxo2 = self.make_utxo(self.nodes[0], 3 * COIN)
tx1a_utxo = self.wallet.send_self_transfer( tx1a = self.wallet.send_self_transfer(
from_node=self.nodes[0], from_node=self.nodes[0],
utxo_to_spend=utxo1, utxo_to_spend=utxo1,
sequence=0, sequence=0,
fee=Decimal("0.1"), fee=Decimal("0.1"),
)["new_utxo"] )
tx1a_utxo = tx1a["new_utxo"]
# Direct spend an output of the transaction we're replacing. # Direct spend an output of the transaction we're replacing.
tx2_hex = self.wallet.create_self_transfer_multi( tx2 = self.wallet.create_self_transfer_multi(
utxos_to_spend=[utxo1, utxo2, tx1a_utxo], utxos_to_spend=[utxo1, utxo2, tx1a_utxo],
sequence=0, sequence=0,
amount_per_output=int(COIN * tx1a_utxo["value"]), amount_per_output=int(COIN * tx1a_utxo["value"]),
)["hex"] )["tx"]
tx2_hex = tx2.serialize().hex()
# This will raise an exception # This will raise an exception
assert_raises_rpc_error(-26, "bad-txns-spends-conflicting-tx", self.nodes[0].sendrawtransaction, tx2_hex, 0) reject_reason = "bad-txns-spends-conflicting-tx"
reject_details = f"{reject_reason}, {tx2.hash} spends conflicting transaction {tx1a['tx'].hash}"
res = self.nodes[0].testmempoolaccept(rawtxs=[tx2_hex])[0]
assert_equal(res["reject-reason"], reject_reason)
assert_equal(res["reject-details"], reject_details)
assert_raises_rpc_error(-26, f"{reject_details}", self.nodes[0].sendrawtransaction, tx2_hex, 0)
# Spend tx1a's output to test the indirect case. # Spend tx1a's output to test the indirect case.
tx1b_utxo = self.wallet.send_self_transfer( tx1b_utxo = self.wallet.send_self_transfer(
@ -319,14 +342,21 @@ class ReplaceByFeeTest(BitcoinTestFramework):
fee=Decimal("0.1"), fee=Decimal("0.1"),
) )
tx2_hex = self.wallet.create_self_transfer_multi( tx2 = self.wallet.create_self_transfer_multi(
utxos_to_spend=[confirmed_utxo, unconfirmed_utxo], utxos_to_spend=[confirmed_utxo, unconfirmed_utxo],
sequence=0, sequence=0,
amount_per_output=1 * COIN, amount_per_output=1 * COIN,
)["hex"] )["tx"]
tx2_hex = tx2.serialize().hex()
# This will raise an exception # This will raise an exception
assert_raises_rpc_error(-26, "replacement-adds-unconfirmed", self.nodes[0].sendrawtransaction, tx2_hex, 0) reject_reason = "replacement-adds-unconfirmed"
reject_details = f"{reject_reason}, replacement {tx2.hash} adds unconfirmed input, idx 1"
res = self.nodes[0].testmempoolaccept(rawtxs=[tx2_hex])[0]
assert_equal(res["reject-reason"], reject_reason)
assert_equal(res["reject-details"], reject_details)
assert_raises_rpc_error(-26, f"{reject_details}", self.nodes[0].sendrawtransaction, tx2_hex, 0)
def test_too_many_replacements(self): def test_too_many_replacements(self):
"""Replacements that evict too many transactions are rejected""" """Replacements that evict too many transactions are rejected"""
@ -368,7 +398,13 @@ class ReplaceByFeeTest(BitcoinTestFramework):
double_tx_hex = double_tx.serialize().hex() double_tx_hex = double_tx.serialize().hex()
# This will raise an exception # This will raise an exception
assert_raises_rpc_error(-26, "too many potential replacements", self.nodes[0].sendrawtransaction, double_tx_hex, 0) reject_reason = "too many potential replacements"
reject_details = f"{reject_reason}, rejecting replacement {double_tx.hash}; too many potential replacements ({MAX_REPLACEMENT_LIMIT + 1} > {MAX_REPLACEMENT_LIMIT})"
res = self.nodes[0].testmempoolaccept(rawtxs=[double_tx_hex])[0]
assert_equal(res["reject-reason"], reject_reason)
assert_equal(res["reject-details"], reject_details)
assert_raises_rpc_error(-26, f"{reject_details}", self.nodes[0].sendrawtransaction, double_tx_hex, 0)
# If we remove an input, it should pass # If we remove an input, it should pass
double_tx.vin.pop() double_tx.vin.pop()