-
Notifications
You must be signed in to change notification settings - Fork 38.6k
include verbose "reject-details" field in testmempoolaccept response #28121
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
|
The following sections might be updated with supplementary metadata relevant to reviewers and maintainers. Code Coverage & BenchmarksFor details see: https://corecheck.dev/bitcoin/bitcoin/pulls/28121. ReviewsSee the guideline for information on the review process.
If your review is incorrectly listed, please react with 👎 to this comment and the bot will ignore it on the next update. ConflictsNo conflicts as of last run. |
|
Why not pass the details in |
My thinking was to match exactly the single combined string returned by |
glozow
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Concept ACK to providing the debug string, I'm sure it'd be helpful for users. Would be nice to do this for submitpackage as well.
I'm not sure if we try to keep strings for reject-reason stable at all. If we do, I'd be in favor of adding a new field error_msg with the full string instead of a separate field with just the debug message.
You mean like how block reject reasons are defined in BIP22? |
jonatack
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lgtm ACK bcdc3646c3e24930433e30b6363ca2d6f6fb9198 modulo the question of a new field vs the appending to the reject_reason output.
test/functional/feature_rbf.py
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In commit bafd175ca898c3ff74ae7927a3e9e3607ea3c8cd, can make a helper for this.
diff
--- a/test/functional/feature_rbf.py
+++ b/test/functional/feature_rbf.py
@@ -107,6 +107,11 @@ class ReplaceByFeeTest(BitcoinTestFramework):
return self.wallet.get_utxo(txid=tx["txid"], vout=tx["sent_vout"])
+ def assert_rejected_by_testmempoolaccept(self, tx_hex, msg):
+ result = self.nodes[0].testmempoolaccept(rawtxs=[tx_hex])[0]
+ assert not result["allowed"]
+ assert msg in result["reject-reason"]
+
def test_simple_doublespend(self):
"""Simple doublespend"""
# we use MiniWallet to create a transaction template with inputs correctly set,
@@ -121,9 +126,7 @@ class ReplaceByFeeTest(BitcoinTestFramework):
# This will raise an exception due to insufficient fee
debug_message = f"insufficient fee, rejecting replacement {tx.hash}; new feerate"
assert_raises_rpc_error(-26, debug_message, self.nodes[0].sendrawtransaction, tx.serialize().hex(), 0)
- res = self.nodes[0].testmempoolaccept(rawtxs=[tx.serialize().hex()])[0]
- assert not res['allowed']
- assert debug_message in res['reject-reason']
+ self.assert_rejected_by_testmempoolaccept(tx.serialize().hex(), debug_message)
# Extra 0.1 BTC fee
tx.vout[0].nValue -= int(0.1 * COIN)
@@ -168,9 +171,7 @@ class ReplaceByFeeTest(BitcoinTestFramework):
# This will raise an exception due to insufficient fee
debug_message = f"insufficient fee, rejecting replacement {dbl_tx['txid']}; less fees than conflicting txs"
assert_raises_rpc_error(-26, debug_message, self.nodes[0].sendrawtransaction, dbl_tx["hex"], 0)
- res = self.nodes[0].testmempoolaccept(rawtxs=[dbl_tx["hex"]])[0]
- assert not res['allowed']
- assert debug_message in res['reject-reason']
+ self.assert_rejected_by_testmempoolaccept(dbl_tx["hex"], debug_message)
# Accepted with sufficient fee
dbl_tx["tx"].vout[0].nValue = int(0.1 * COIN)
@@ -307,9 +308,7 @@ class ReplaceByFeeTest(BitcoinTestFramework):
# This will raise an exception
debug_message = f"bad-txns-spends-conflicting-tx, {tx2['txid']} spends conflicting transaction {tx1a['txid']}"
assert_raises_rpc_error(-26, debug_message, self.nodes[0].sendrawtransaction, tx2["hex"], 0)
- res = self.nodes[0].testmempoolaccept(rawtxs=[tx2["hex"]])[0]
- assert not res['allowed']
- assert debug_message in res['reject-reason']
+ self.assert_rejected_by_testmempoolaccept(tx2["hex"], debug_message)
# Spend tx1a's output to test the indirect case.
tx1b_utxo = self.wallet.send_self_transfer(
@@ -349,9 +348,7 @@ class ReplaceByFeeTest(BitcoinTestFramework):
# This will raise an exception
debug_message = f"replacement-adds-unconfirmed, replacement {tx2['txid']} adds unconfirmed input, idx"
assert_raises_rpc_error(-26, debug_message, self.nodes[0].sendrawtransaction, tx2["hex"], 0)
- res = self.nodes[0].testmempoolaccept(rawtxs=[tx2["hex"]])[0]
- assert not res['allowed']
- assert debug_message in res['reject-reason']
+ self.assert_rejected_by_testmempoolaccept(tx2["hex"], debug_message)
def test_too_many_replacements(self):
"""Replacements that evict too many transactions are rejected"""
@@ -394,9 +391,7 @@ class ReplaceByFeeTest(BitcoinTestFramework):
# This will raise an exception
debug_message = f"too many potential replacements, rejecting replacement {double_tx['txid']}; too many potential replacements"
assert_raises_rpc_error(-26, debug_message, self.nodes[0].sendrawtransaction, double_tx["hex"], 0)
- res = self.nodes[0].testmempoolaccept(rawtxs=[double_tx["hex"]])[0]
- assert not res['allowed']
- assert debug_message in res['reject-reason']
+ self.assert_rejected_by_testmempoolaccept(double_tx["hex"], debug_message)
# If we remove an input, it should pass
double_tx["tx"].vin.pop()
@@ -720,9 +715,7 @@ class ReplaceByFeeTest(BitcoinTestFramework):
tx.rehash()
debug_message = f"insufficient fee, rejecting replacement {tx.hash}; not enough additional fees to relay"
assert_raises_rpc_error(-26, debug_message, self.nodes[0].sendrawtransaction, tx.serialize().hex())
- res = self.nodes[0].testmempoolaccept(rawtxs=[tx.serialize().hex()])[0]
- assert not res['allowed']
- assert debug_message in res['reject-reason']
+ self.assert_rejected_by_testmempoolaccept(tx.serialize().hex(), debug_message)
def test_fullrbf(self):
Yeah exactly. Like if somebody has a fee bumper that's triggered by |
Yeah ok so, the detailed message is appended to the original so "somebody" would just need to change their |
|
Needs rebase if still relevant |
Done 🙏 |
|
concept ACK unfortunately I know people do use reject-reason strings for various informational purposes. Would be a good project to gather those uses and maybe think of better error codes to capture these? |
|
@instagibbs thanks for taking a look! Not sure what you mean about gathering uses though. Are you agreeing with @luke-jr that the debug messages should have their own field in TMA response object and leave |
Looking at why error codes aren't enough for production uses |
I'm working on an RBF-batcher with CardCoins and we were getting Line 983 in 6e721c9
Line 1004 in 6e721c9
|
|
Concept ACK |
|
I have a slight preference to keep the |
6f4c80d to
08946d3
Compare
|
Rebased on master (+cmake), and then rebased on master again after #31112 merged. This PR now adds some extra test coverage to the logging in 31112 as well. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Successful make and functional tests. Partial review, will complete the review soon.
I tested it out on local with 2 cases: passing in an unsigned transaction, and then passing in a tx with incorrect input.
Simulated `testmempoolaccept` failures
➜ ~ bitcoinclireg testmempoolaccept "[\"02000000011d7064f723f688af381d4f2d7f1d8c7ea9d1e0199531b636f3e7499d68dd21900000000000ffffffff0178de052a010000001600148d6b22f6e4c0c5dc96529ca5ebc6ad0cde42966800000000\"]"
[
{
"txid": "7d7d6f5e1e5fdc0955ac16309636597c5dc9e117950a3aee2203fb60177131fc",
"wtxid": "7d7d6f5e1e5fdc0955ac16309636597c5dc9e117950a3aee2203fb60177131fc",
"allowed": false,
"reject-reason": "mandatory-script-verify-flag-failed (Witness program hash mismatch)",
"reject-details": "mandatory-script-verify-flag-failed (Witness program hash mismatch), input 0 of 7d7d6f5e1e5fdc0955ac16309636597c5dc9e117950a3aee2203fb60177131fc (wtxid 7d7d6f5e1e5fdc0955ac16309636597c5dc9e117950a3aee2203fb60177131fc), spending 9021dd689d49e7f336b6319519e0d1a97e8c1d7f2d4f1d38af88f623f764701d:0"
}
]
➜ ~ bitcoinclireg testmempoolaccept "[\"02000000012d7064f723f688af381d4f2d7f1d8c7ea9d1e0199531b636f3e7499d68dd21900000000000ffffffff0178de052a010000001600148d6b22f6e4c0c5dc96529ca5ebc6ad0cde42966800000000\"]"
[
{
"txid": "3b9d266452396611cc6843b2a39adc555538a6f7c59e4cbb653f5826756be0a1",
"wtxid": "3b9d266452396611cc6843b2a39adc555538a6f7c59e4cbb653f5826756be0a1",
"allowed": false,
"reject-reason": "missing-inputs"
}
]
| result_inner.pushKV("allowed", false); | ||
| const TxValidationState state = tx_result.m_state; | ||
| if (state.GetResult() == TxValidationResult::TX_MISSING_INPUTS) { | ||
| result_inner.pushKV("reject-reason", "missing-inputs"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not returning the details from here because it'd be same as "missing-inputs"?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually in this case m_reject_reason would be "bad-txns-inputs-missingorspent" and m_reject_details would be an empty string, but the RPC response has this hard coded instead (covered by mempool_accept.py)
test/functional/feature_rbf.py
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: Extra line
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
got it thanks
Thank you for rebasing on master, I can test it out on local now. |
Adds a new field
reject-detailsintestmempoolacceptresponses to includem_debug_messagefromValidationState. This string is the complete error message thrown by the mempool in response tosendrawtransaction.The extra verbosity is helpful to consumers of
testmempoolaccept, which is sort of a debug tool anyway.example: