-
Notifications
You must be signed in to change notification settings - Fork 35.5k
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
include verbose "debug-message" field in testmempoolaccept response #28121
base: master
Are you sure you want to change the base?
Conversation
The following sections might be updated with supplementary metadata relevant to reviewers and maintainers. Code CoverageFor detailed information about the code coverage, see the test coverage report. 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. ConflictsReviewers, this pull request conflicts with the following ones:
If you consider this pull request important, please also help to review the conflicting pull requests. Ideally, start with the one that should be merged first. |
Why not pass the details in |
My thinking was to match exactly the single combined string returned by |
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? |
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 bcdc364 modulo the question of a new field vs the appending to the reject_reason
output.
test/functional/feature_rbf.py
Outdated
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'] |
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 bafd175, 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 |
Thanks for taking a look, @0xB10C. I've refactored the PR to add a new field instead of changing anything already in place. Edited PR title and description. I made the tests super clear that the complete string is returned by |
I've played around a bit with this in 0xB10C/find-non-standard-tx#2. I've seen output for the following reasons:
Other reasons like e.g. I haven't yet taken a closer look at the code. |
debug-message was empty like if (!state.GetDebugMessage().empty()) result_inner.pushKV("debug-message", state.GetDebugMessage()); |
You're right. I should have been clearer in my comment: the field wasn't present. My tooling handles the missing field by setting the value to "". |
force-push to fix merge conflict which also looked like a git mistake on my part in the first place 😬 |
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 d2917e7
src/rpc/mempool.cpp
Outdated
@@ -141,6 +141,7 @@ static RPCHelpMan testmempoolaccept() | |||
}}, | |||
}}, | |||
{RPCResult::Type::STR, "reject-reason", /*optional=*/true, "Rejection string (only present when 'allowed' is false)"}, | |||
{RPCResult::Type::STR, "debug-message", /*optional=*/true, "Rejection details (only present when 'allowed' is false and a message is provided)"}, |
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.
-
it might be more user-friendly to call the field
reject-details
?edit: (also, per include verbose "debug-message" field in testmempoolaccept response #28121 (comment), the rationale for adding this field isn't only for debugging)
-
maybe just me, but
a message is provided
is potentially confusing, as it might sound like user input
{RPCResult::Type::STR, "debug-message", /*optional=*/true, "Rejection details (only present when 'allowed' is false and a message is provided)"}, | |
{RPCResult::Type::STR, "reject-details", /*optional=*/true, "Rejection details (only present when 'allowed' is false and rejection details exist)"}, |
src/rpc/mempool.cpp
Outdated
@@ -141,6 +141,7 @@ static RPCHelpMan testmempoolaccept() | |||
}}, | |||
}}, | |||
{RPCResult::Type::STR, "reject-reason", /*optional=*/true, "Rejection string (only present when 'allowed' is false)"}, |
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.
c1be9d4 while touching the next line, string
here might be a relic from when the field type wasn't auto-generated in the help, ISTM reason
would be clearer
{RPCResult::Type::STR, "reject-reason", /*optional=*/true, "Rejection string (only present when 'allowed' is false)"}, | |
{RPCResult::Type::STR, "reject-reason", /*optional=*/true, "Rejection reason (only present when 'allowed' is false)"}, |
@@ -0,0 +1,5 @@ | |||
RPC |
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.
d2917e7 unsure if Updated RPCs
would be better here, feel free to ignore
doc/release-notes-28121.md
Outdated
RPC | ||
--- | ||
|
||
`testmempoolaccept` response will now include verbose field "debug-message" |
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.
d2917e7 the new field won't always be included (and why "verbose"?)
`testmempoolaccept` response will now include verbose field "debug-message" | |
The RPC `testmempoolaccept` response now includes a "reject-details" field in some cases |
Thanks for reviewing @jonatack I like the idea of "reject-details" and addressed your other comments as well |
Adds a new field
debug-message
intestmempoolaccept
responses to includem_debug_message
fromValidationState
. This string is part of 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: