Merge bitcoin/bitcoin#33427: rpc: Always return per-wtxid entries in submitpackage tx-results
cad9a7fd73rpc: Always return per-wtxid entries in submitpackage tx-results (John Moffett) Pull request description: Follow-up to #28848 When `submitpackage` produced no per-transaction result for a member, the RPC set `"error": "unevaluated"` but then continued without inserting the entry into `tx-results`, making it impossible for callers to know which `wtxids` were unevaluated. This inserts the error result before continuing, updates help text, and adjusts functional tests to expect entries for all submitted `wtxids`. ACKs for top commit: instagibbs: ACKcad9a7fd73glozow: ACKcad9a7fd73Tree-SHA512: 8df5c9b3d1f17aaf0311c38f028ae4b55d4c52a660f85171f105c4f65d130b14ab00698ac5d7c27403a0c37fff391c154c3ad44cc99ba4d549d9c30751b8360f
This commit is contained in:
2 files changed
+22
-7
No files matched your search
+10
-5
@@ -955,7 +955,7 @@ static RPCHelpMan submitpackage()
|
|||||||
RPCResult::Type::OBJ, "", "",
|
RPCResult::Type::OBJ, "", "",
|
||||||
{
|
{
|
||||||
{RPCResult::Type::STR, "package_msg", "The transaction package result message. \"success\" indicates all transactions were accepted into or are already in the mempool."},
|
{RPCResult::Type::STR, "package_msg", "The transaction package result message. \"success\" indicates all transactions were accepted into or are already in the mempool."},
|
||||||
{RPCResult::Type::OBJ_DYN, "tx-results", "transaction results keyed by wtxid",
|
{RPCResult::Type::OBJ_DYN, "tx-results", "The transaction results keyed by wtxid. An entry is returned for every submitted wtxid.",
|
||||||
{
|
{
|
||||||
{RPCResult::Type::OBJ, "wtxid", "transaction wtxid", {
|
{RPCResult::Type::OBJ, "wtxid", "transaction wtxid", {
|
||||||
{RPCResult::Type::STR_HEX, "txid", "The transaction hash in hex"},
|
{RPCResult::Type::STR_HEX, "txid", "The transaction hash in hex"},
|
||||||
@@ -968,7 +968,7 @@ static RPCHelpMan submitpackage()
|
|||||||
{{RPCResult::Type::STR_HEX, "", "transaction wtxid in hex"},
|
{{RPCResult::Type::STR_HEX, "", "transaction wtxid in hex"},
|
||||||
}},
|
}},
|
||||||
}},
|
}},
|
||||||
{RPCResult::Type::STR, "error", /*optional=*/true, "The transaction error string, if it was rejected by the mempool"},
|
{RPCResult::Type::STR, "error", /*optional=*/true, "Error string if rejected from mempool, or \"package-not-validated\" when the package aborts before any per-tx processing."},
|
||||||
}}
|
}}
|
||||||
}},
|
}},
|
||||||
{RPCResult::Type::ARR, "replaced-transactions", /*optional=*/true, "List of txids of replaced transactions",
|
{RPCResult::Type::ARR, "replaced-transactions", /*optional=*/true, "List of txids of replaced transactions",
|
||||||
@@ -1082,10 +1082,15 @@ static RPCHelpMan submitpackage()
|
|||||||
for (const auto& tx : txns) {
|
for (const auto& tx : txns) {
|
||||||
UniValue result_inner{UniValue::VOBJ};
|
UniValue result_inner{UniValue::VOBJ};
|
||||||
result_inner.pushKV("txid", tx->GetHash().GetHex());
|
result_inner.pushKV("txid", tx->GetHash().GetHex());
|
||||||
|
const auto wtxid_hex = tx->GetWitnessHash().GetHex();
|
||||||
auto it = package_result.m_tx_results.find(tx->GetWitnessHash());
|
auto it = package_result.m_tx_results.find(tx->GetWitnessHash());
|
||||||
if (it == package_result.m_tx_results.end()) {
|
if (it == package_result.m_tx_results.end()) {
|
||||||
// No results, report error and continue
|
// No per-tx result for this wtxid
|
||||||
result_inner.pushKV("error", "unevaluated");
|
// Current invariant: per-tx results are all-or-none (every member or empty on package abort).
|
||||||
|
// If any exist yet this one is missing, it's an unexpected partial map.
|
||||||
|
CHECK_NONFATAL(package_result.m_tx_results.empty());
|
||||||
|
result_inner.pushKV("error", "package-not-validated");
|
||||||
|
tx_result_map.pushKV(wtxid_hex, std::move(result_inner));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const auto& tx_result = it->second;
|
const auto& tx_result = it->second;
|
||||||
@@ -1118,7 +1123,7 @@ static RPCHelpMan submitpackage()
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
tx_result_map.pushKV(tx->GetWitnessHash().GetHex(), std::move(result_inner));
|
tx_result_map.pushKV(wtxid_hex, std::move(result_inner));
|
||||||
}
|
}
|
||||||
rpc_result.pushKV("tx-results", std::move(tx_result_map));
|
rpc_result.pushKV("tx-results", std::move(tx_result_map));
|
||||||
UniValue replaced_list(UniValue::VARR);
|
UniValue replaced_list(UniValue::VARR);
|
||||||
|
|||||||
@@ -263,13 +263,23 @@ class RPCPackagesTest(BitcoinTestFramework):
|
|||||||
])
|
])
|
||||||
|
|
||||||
submitres = node.submitpackage([tx1["hex"], tx2["hex"], tx_child["hex"]])
|
submitres = node.submitpackage([tx1["hex"], tx2["hex"], tx_child["hex"]])
|
||||||
assert_equal(submitres, {'package_msg': 'conflict-in-package', 'tx-results': {}, 'replaced-transactions': []})
|
expected = {
|
||||||
|
tx1["wtxid"]: {"txid": tx1["txid"], "error": "package-not-validated"},
|
||||||
|
tx2["wtxid"]: {"txid": tx2["txid"], "error": "package-not-validated"},
|
||||||
|
tx_child["wtxid"]: {"txid": tx_child["txid"], "error": "package-not-validated"},
|
||||||
|
}
|
||||||
|
assert_equal(submitres, {"package_msg": "conflict-in-package", "tx-results": expected,"replaced-transactions": []})
|
||||||
|
|
||||||
# Submit tx1 to mempool, then try the same package again
|
# Submit tx1 to mempool, then try the same package again
|
||||||
node.sendrawtransaction(tx1["hex"])
|
node.sendrawtransaction(tx1["hex"])
|
||||||
|
|
||||||
submitres = node.submitpackage([tx1["hex"], tx2["hex"], tx_child["hex"]])
|
submitres = node.submitpackage([tx1["hex"], tx2["hex"], tx_child["hex"]])
|
||||||
assert_equal(submitres, {'package_msg': 'conflict-in-package', 'tx-results': {}, 'replaced-transactions': []})
|
expected = {
|
||||||
|
tx1["wtxid"]: {"txid": tx1["txid"], "error": "package-not-validated"},
|
||||||
|
tx2["wtxid"]: {"txid": tx2["txid"], "error": "package-not-validated"},
|
||||||
|
tx_child["wtxid"]: {"txid": tx_child["txid"], "error": "package-not-validated"},
|
||||||
|
}
|
||||||
|
assert_equal(submitres, {"package_msg": "conflict-in-package", "tx-results": expected,"replaced-transactions": []})
|
||||||
assert tx_child["txid"] not in node.getrawmempool()
|
assert tx_child["txid"] not in node.getrawmempool()
|
||||||
|
|
||||||
# without the in-mempool ancestor tx1 included in the call, tx2 can be submitted, but
|
# without the in-mempool ancestor tx1 included in the call, tx2 can be submitted, but
|
||||||
|
|||||||
Reference in new issue
Block a user