Skip to content

Commit a86e1a6

Browse files
committed
Merge bitcoin/bitcoin#33427: rpc: Always return per-wtxid entries in submitpackage tx-results
cad9a7f rpc: 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: ACK cad9a7f glozow: ACK cad9a7f Tree-SHA512: 8df5c9b3d1f17aaf0311c38f028ae4b55d4c52a660f85171f105c4f65d130b14ab00698ac5d7c27403a0c37fff391c154c3ad44cc99ba4d549d9c30751b8360f
2 parents 6861dad + cad9a7f commit a86e1a6

File tree

2 files changed

+22
-7
lines changed

2 files changed

+22
-7
lines changed

src/rpc/mempool.cpp

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -955,7 +955,7 @@ static RPCHelpMan submitpackage()
955955
RPCResult::Type::OBJ, "", "",
956956
{
957957
{RPCResult::Type::STR, "package_msg", "The transaction package result message. \"success\" indicates all transactions were accepted into or are already in the mempool."},
958-
{RPCResult::Type::OBJ_DYN, "tx-results", "transaction results keyed by wtxid",
958+
{RPCResult::Type::OBJ_DYN, "tx-results", "The transaction results keyed by wtxid. An entry is returned for every submitted wtxid.",
959959
{
960960
{RPCResult::Type::OBJ, "wtxid", "transaction wtxid", {
961961
{RPCResult::Type::STR_HEX, "txid", "The transaction hash in hex"},
@@ -968,7 +968,7 @@ static RPCHelpMan submitpackage()
968968
{{RPCResult::Type::STR_HEX, "", "transaction wtxid in hex"},
969969
}},
970970
}},
971-
{RPCResult::Type::STR, "error", /*optional=*/true, "The transaction error string, if it was rejected by the mempool"},
971+
{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."},
972972
}}
973973
}},
974974
{RPCResult::Type::ARR, "replaced-transactions", /*optional=*/true, "List of txids of replaced transactions",
@@ -1082,10 +1082,15 @@ static RPCHelpMan submitpackage()
10821082
for (const auto& tx : txns) {
10831083
UniValue result_inner{UniValue::VOBJ};
10841084
result_inner.pushKV("txid", tx->GetHash().GetHex());
1085+
const auto wtxid_hex = tx->GetWitnessHash().GetHex();
10851086
auto it = package_result.m_tx_results.find(tx->GetWitnessHash());
10861087
if (it == package_result.m_tx_results.end()) {
1087-
// No results, report error and continue
1088-
result_inner.pushKV("error", "unevaluated");
1088+
// No per-tx result for this wtxid
1089+
// Current invariant: per-tx results are all-or-none (every member or empty on package abort).
1090+
// If any exist yet this one is missing, it's an unexpected partial map.
1091+
CHECK_NONFATAL(package_result.m_tx_results.empty());
1092+
result_inner.pushKV("error", "package-not-validated");
1093+
tx_result_map.pushKV(wtxid_hex, std::move(result_inner));
10891094
continue;
10901095
}
10911096
const auto& tx_result = it->second;
@@ -1118,7 +1123,7 @@ static RPCHelpMan submitpackage()
11181123
}
11191124
break;
11201125
}
1121-
tx_result_map.pushKV(tx->GetWitnessHash().GetHex(), std::move(result_inner));
1126+
tx_result_map.pushKV(wtxid_hex, std::move(result_inner));
11221127
}
11231128
rpc_result.pushKV("tx-results", std::move(tx_result_map));
11241129
UniValue replaced_list(UniValue::VARR);

test/functional/rpc_packages.py

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -263,13 +263,23 @@ def test_conflicting(self):
263263
])
264264

265265
submitres = node.submitpackage([tx1["hex"], tx2["hex"], tx_child["hex"]])
266-
assert_equal(submitres, {'package_msg': 'conflict-in-package', 'tx-results': {}, 'replaced-transactions': []})
266+
expected = {
267+
tx1["wtxid"]: {"txid": tx1["txid"], "error": "package-not-validated"},
268+
tx2["wtxid"]: {"txid": tx2["txid"], "error": "package-not-validated"},
269+
tx_child["wtxid"]: {"txid": tx_child["txid"], "error": "package-not-validated"},
270+
}
271+
assert_equal(submitres, {"package_msg": "conflict-in-package", "tx-results": expected,"replaced-transactions": []})
267272

268273
# Submit tx1 to mempool, then try the same package again
269274
node.sendrawtransaction(tx1["hex"])
270275

271276
submitres = node.submitpackage([tx1["hex"], tx2["hex"], tx_child["hex"]])
272-
assert_equal(submitres, {'package_msg': 'conflict-in-package', 'tx-results': {}, 'replaced-transactions': []})
277+
expected = {
278+
tx1["wtxid"]: {"txid": tx1["txid"], "error": "package-not-validated"},
279+
tx2["wtxid"]: {"txid": tx2["txid"], "error": "package-not-validated"},
280+
tx_child["wtxid"]: {"txid": tx_child["txid"], "error": "package-not-validated"},
281+
}
282+
assert_equal(submitres, {"package_msg": "conflict-in-package", "tx-results": expected,"replaced-transactions": []})
273283
assert tx_child["txid"] not in node.getrawmempool()
274284

275285
# without the in-mempool ancestor tx1 included in the call, tx2 can be submitted, but

0 commit comments

Comments
 (0)