mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-01-09 19:37:27 -03:00
rpc: include verbose reject-details field in testmempoolaccept response
This commit is contained in:
parent
ae69fc37e4
commit
221c789e91
6 changed files with 36 additions and 13 deletions
|
@ -146,7 +146,8 @@ static RPCHelpMan testmempoolaccept()
|
||||||
{RPCResult{RPCResult::Type::STR_HEX, "", "transaction wtxid in hex"},
|
{RPCResult{RPCResult::Type::STR_HEX, "", "transaction wtxid in hex"},
|
||||||
}},
|
}},
|
||||||
}},
|
}},
|
||||||
{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)"},
|
||||||
|
{RPCResult::Type::STR, "reject-details", /*optional=*/true, "Rejection details (only present when 'allowed' is false and rejection details exist)"},
|
||||||
}},
|
}},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -245,6 +246,7 @@ static RPCHelpMan testmempoolaccept()
|
||||||
result_inner.pushKV("reject-reason", "missing-inputs");
|
result_inner.pushKV("reject-reason", "missing-inputs");
|
||||||
} else {
|
} else {
|
||||||
result_inner.pushKV("reject-reason", state.GetRejectReason());
|
result_inner.pushKV("reject-reason", state.GetRejectReason());
|
||||||
|
result_inner.pushKV("reject-details", state.ToString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
rpc_result.push_back(std::move(result_inner));
|
rpc_result.push_back(std::move(result_inner));
|
||||||
|
|
|
@ -148,6 +148,10 @@ class BIP65Test(BitcoinTestFramework):
|
||||||
# create and test one invalid tx per CLTV failure reason (5 in total)
|
# create and test one invalid tx per CLTV failure reason (5 in total)
|
||||||
for i in range(5):
|
for i in range(5):
|
||||||
spendtx = wallet.create_self_transfer()['tx']
|
spendtx = wallet.create_self_transfer()['tx']
|
||||||
|
assert_equal(len(spendtx.vin), 1)
|
||||||
|
coin = spendtx.vin[0]
|
||||||
|
coin_txid = format(coin.prevout.hash, '064x')
|
||||||
|
coin_vout = coin.prevout.n
|
||||||
cltv_invalidate(spendtx, i)
|
cltv_invalidate(spendtx, i)
|
||||||
|
|
||||||
expected_cltv_reject_reason = [
|
expected_cltv_reject_reason = [
|
||||||
|
@ -159,12 +163,15 @@ class BIP65Test(BitcoinTestFramework):
|
||||||
][i]
|
][i]
|
||||||
# First we show that this tx is valid except for CLTV by getting it
|
# First we show that this tx is valid except for CLTV by getting it
|
||||||
# rejected from the mempool for exactly that reason.
|
# rejected from the mempool for exactly that reason.
|
||||||
|
spendtx_txid = spendtx.hash
|
||||||
|
spendtx_wtxid = spendtx.getwtxid()
|
||||||
assert_equal(
|
assert_equal(
|
||||||
[{
|
[{
|
||||||
'txid': spendtx.hash,
|
'txid': spendtx_txid,
|
||||||
'wtxid': spendtx.getwtxid(),
|
'wtxid': spendtx_wtxid,
|
||||||
'allowed': False,
|
'allowed': False,
|
||||||
'reject-reason': expected_cltv_reject_reason,
|
'reject-reason': expected_cltv_reject_reason,
|
||||||
|
'reject-details': expected_cltv_reject_reason + f", input 0 of {spendtx_txid} (wtxid {spendtx_wtxid}), spending {coin_txid}:{coin_vout}"
|
||||||
}],
|
}],
|
||||||
self.nodes[0].testmempoolaccept(rawtxs=[spendtx.serialize().hex()], maxfeerate=0),
|
self.nodes[0].testmempoolaccept(rawtxs=[spendtx.serialize().hex()], maxfeerate=0),
|
||||||
)
|
)
|
||||||
|
|
|
@ -109,18 +109,23 @@ class BIP66Test(BitcoinTestFramework):
|
||||||
self.log.info("Test that transactions with non-DER signatures cannot appear in a block")
|
self.log.info("Test that transactions with non-DER signatures cannot appear in a block")
|
||||||
block.nVersion = 4
|
block.nVersion = 4
|
||||||
|
|
||||||
spendtx = self.create_tx(self.coinbase_txids[1])
|
coin_txid = self.coinbase_txids[1]
|
||||||
|
spendtx = self.create_tx(coin_txid)
|
||||||
unDERify(spendtx)
|
unDERify(spendtx)
|
||||||
spendtx.rehash()
|
spendtx.rehash()
|
||||||
|
|
||||||
# First we show that this tx is valid except for DERSIG by getting it
|
# First we show that this tx is valid except for DERSIG by getting it
|
||||||
# rejected from the mempool for exactly that reason.
|
# rejected from the mempool for exactly that reason.
|
||||||
|
spendtx_txid = spendtx.hash
|
||||||
|
spendtx_wtxid = spendtx.getwtxid()
|
||||||
assert_equal(
|
assert_equal(
|
||||||
[{
|
[{
|
||||||
'txid': spendtx.hash,
|
'txid': spendtx_txid,
|
||||||
'wtxid': spendtx.getwtxid(),
|
'wtxid': spendtx_wtxid,
|
||||||
'allowed': False,
|
'allowed': False,
|
||||||
'reject-reason': 'mandatory-script-verify-flag-failed (Non-canonical DER signature)',
|
'reject-reason': 'mandatory-script-verify-flag-failed (Non-canonical DER signature)',
|
||||||
|
'reject-details': 'mandatory-script-verify-flag-failed (Non-canonical DER signature), ' +
|
||||||
|
f"input 0 of {spendtx_txid} (wtxid {spendtx_wtxid}), spending {coin_txid}:0"
|
||||||
}],
|
}],
|
||||||
self.nodes[0].testmempoolaccept(rawtxs=[spendtx.serialize().hex()], maxfeerate=0),
|
self.nodes[0].testmempoolaccept(rawtxs=[spendtx.serialize().hex()], maxfeerate=0),
|
||||||
)
|
)
|
||||||
|
|
|
@ -67,6 +67,8 @@ class MempoolAcceptanceTest(BitcoinTestFramework):
|
||||||
if "fees" in r:
|
if "fees" in r:
|
||||||
r["fees"].pop("effective-feerate")
|
r["fees"].pop("effective-feerate")
|
||||||
r["fees"].pop("effective-includes")
|
r["fees"].pop("effective-includes")
|
||||||
|
if "reject-details" in r:
|
||||||
|
r.pop("reject-details")
|
||||||
assert_equal(result_expected, result_test)
|
assert_equal(result_expected, result_test)
|
||||||
assert_equal(self.nodes[0].getmempoolinfo()['size'], self.mempool_size) # Must not change mempool state
|
assert_equal(self.nodes[0].getmempoolinfo()['size'], self.mempool_size) # Must not change mempool state
|
||||||
|
|
||||||
|
|
|
@ -100,13 +100,15 @@ class MempoolWtxidTest(BitcoinTestFramework):
|
||||||
"txid": child_one_txid,
|
"txid": child_one_txid,
|
||||||
"wtxid": child_one_wtxid,
|
"wtxid": child_one_wtxid,
|
||||||
"allowed": False,
|
"allowed": False,
|
||||||
"reject-reason": "txn-already-in-mempool"
|
"reject-reason": "txn-already-in-mempool",
|
||||||
|
"reject-details": "txn-already-in-mempool"
|
||||||
}])
|
}])
|
||||||
assert_equal(node.testmempoolaccept([child_two.serialize().hex()])[0], {
|
assert_equal(node.testmempoolaccept([child_two.serialize().hex()])[0], {
|
||||||
"txid": child_two_txid,
|
"txid": child_two_txid,
|
||||||
"wtxid": child_two_wtxid,
|
"wtxid": child_two_wtxid,
|
||||||
"allowed": False,
|
"allowed": False,
|
||||||
"reject-reason": "txn-same-nonwitness-data-in-mempool"
|
"reject-reason": "txn-same-nonwitness-data-in-mempool",
|
||||||
|
"reject-details": "txn-same-nonwitness-data-in-mempool"
|
||||||
})
|
})
|
||||||
|
|
||||||
# sendrawtransaction will not throw but quits early when the exact same transaction is already in mempool
|
# sendrawtransaction will not throw but quits early when the exact same transaction is already in mempool
|
||||||
|
|
|
@ -110,17 +110,21 @@ class RPCPackagesTest(BitcoinTestFramework):
|
||||||
self.assert_testres_equal(package_bad, testres_bad)
|
self.assert_testres_equal(package_bad, testres_bad)
|
||||||
|
|
||||||
self.log.info("Check testmempoolaccept tells us when some transactions completed validation successfully")
|
self.log.info("Check testmempoolaccept tells us when some transactions completed validation successfully")
|
||||||
tx_bad_sig_hex = node.createrawtransaction([{"txid": coin["txid"], "vout": 0}],
|
tx_bad_sig_hex = node.createrawtransaction([{"txid": coin["txid"], "vout": coin["vout"]}],
|
||||||
{address : coin["amount"] - Decimal("0.0001")})
|
{address : coin["amount"] - Decimal("0.0001")})
|
||||||
tx_bad_sig = tx_from_hex(tx_bad_sig_hex)
|
tx_bad_sig = tx_from_hex(tx_bad_sig_hex)
|
||||||
testres_bad_sig = node.testmempoolaccept(self.independent_txns_hex + [tx_bad_sig_hex])
|
testres_bad_sig = node.testmempoolaccept(self.independent_txns_hex + [tx_bad_sig_hex])
|
||||||
# By the time the signature for the last transaction is checked, all the other transactions
|
# By the time the signature for the last transaction is checked, all the other transactions
|
||||||
# have been fully validated, which is why the node returns full validation results for all
|
# have been fully validated, which is why the node returns full validation results for all
|
||||||
# transactions here but empty results in other cases.
|
# transactions here but empty results in other cases.
|
||||||
|
tx_bad_sig_txid = tx_bad_sig.rehash()
|
||||||
|
tx_bad_sig_wtxid = tx_bad_sig.getwtxid()
|
||||||
assert_equal(testres_bad_sig, self.independent_txns_testres + [{
|
assert_equal(testres_bad_sig, self.independent_txns_testres + [{
|
||||||
"txid": tx_bad_sig.rehash(),
|
"txid": tx_bad_sig_txid,
|
||||||
"wtxid": tx_bad_sig.getwtxid(), "allowed": False,
|
"wtxid": tx_bad_sig_wtxid, "allowed": False,
|
||||||
"reject-reason": "mandatory-script-verify-flag-failed (Operation not valid with the current stack size)"
|
"reject-reason": "mandatory-script-verify-flag-failed (Operation not valid with the current stack size)",
|
||||||
|
"reject-details": "mandatory-script-verify-flag-failed (Operation not valid with the current stack size), " +
|
||||||
|
f"input 0 of {tx_bad_sig_txid} (wtxid {tx_bad_sig_wtxid}), spending {coin['txid']}:{coin['vout']}"
|
||||||
}])
|
}])
|
||||||
|
|
||||||
self.log.info("Check testmempoolaccept reports txns in packages that exceed max feerate")
|
self.log.info("Check testmempoolaccept reports txns in packages that exceed max feerate")
|
||||||
|
@ -304,7 +308,8 @@ class RPCPackagesTest(BitcoinTestFramework):
|
||||||
assert testres_rbf_single[0]["allowed"]
|
assert testres_rbf_single[0]["allowed"]
|
||||||
testres_rbf_package = self.independent_txns_testres_blank + [{
|
testres_rbf_package = self.independent_txns_testres_blank + [{
|
||||||
"txid": replacement_tx["txid"], "wtxid": replacement_tx["wtxid"], "allowed": False,
|
"txid": replacement_tx["txid"], "wtxid": replacement_tx["wtxid"], "allowed": False,
|
||||||
"reject-reason": "bip125-replacement-disallowed"
|
"reject-reason": "bip125-replacement-disallowed",
|
||||||
|
"reject-details": "bip125-replacement-disallowed"
|
||||||
}]
|
}]
|
||||||
self.assert_testres_equal(self.independent_txns_hex + [replacement_tx["hex"]], testres_rbf_package)
|
self.assert_testres_equal(self.independent_txns_hex + [replacement_tx["hex"]], testres_rbf_package)
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue