rpc: Always return per-wtxid entries in submitpackage tx-results #33427

pull john-moffett wants to merge 1 commits into bitcoin:master from john-moffett:rpc-submitpackage-reportall changing 2 files +22 −7
  1. john-moffett commented at 1:17 pm on September 18, 2025: contributor

    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.

  2. DrahtBot added the label RPC/REST/ZMQ on Sep 18, 2025
  3. DrahtBot commented at 1:17 pm on September 18, 2025: contributor

    The following sections might be updated with supplementary metadata relevant to reviewers and maintainers.

    Code Coverage & Benchmarks

    For details see: https://corecheck.dev/bitcoin/bitcoin/pulls/33427.

    Reviews

    See the guideline for information on the review process.

    Type Reviewers
    ACK glozow, instagibbs

    If your review is incorrectly listed, please react with 👎 to this comment and the bot will ignore it on the next update.

  4. fanquake requested review from instagibbs on Sep 18, 2025
  5. glozow commented at 1:23 pm on September 18, 2025: member

    Concept ACK, this looks like an unintentional drop. I thought “unknown-not-validated” would be better since it matches the error string for skipped transactions, but I think it’s better to have separate messages for “nothing was validated because the package was ill-formed” vs “this particular transaction wasn’t validated.”

    cc @instagibbs

  6. instagibbs commented at 1:28 pm on September 18, 2025: member
    concept ACK
  7. john-moffett force-pushed on Sep 18, 2025
  8. john-moffett commented at 4:15 pm on September 18, 2025: contributor

    I thought “unknown-not-validated” would be better since it matches the error string for skipped transactions, but I think it’s better to have separate messages for “nothing was validated because the package was ill-formed” vs “this particular transaction wasn’t validated.”

    Right now the code can only ever return the former, as both the RPC code and the actual acceptance code are all-or-nothing. I added a check for the latter in case it ever changes, as the API allows for it.

  9. in src/rpc/mempool.cpp:1089 in f8cda4cf01
    1086                 auto it = package_result.m_tx_results.find(tx->GetWitnessHash());
    1087                 if (it == package_result.m_tx_results.end()) {
    1088-                    // No results, report error and continue
    1089-                    result_inner.pushKV("error", "unevaluated");
    1090+                    // No per-tx result for this wtxid
    1091+                    result_inner.pushKV("error", any_per_tx_results ? "unknown-not-validated" : "package-not-validated");
    


    instagibbs commented at 1:00 pm on September 19, 2025:
    “unknown-not-validated” needs some functional coverage? :pray:

    john-moffett commented at 1:33 pm on September 19, 2025:

    Currently not reachable as the RPC:

    CHECK_NONFATAL(m_tx_results.size() == txns.size() || m_tx_results.empty())

    and acceptance code:

    Assume(results_final.size() == package.size())

    both are all-or-nothing in terms of package result reporting. I put that there as a reserve possibility since the API seems to allow for it.

    Happy to roll back to my original PR code, though, just renamed to package-not-validated.


    instagibbs commented at 1:37 pm on September 19, 2025:
    may be redundant but could add a more local assertion to this fact; easier for future reviewers to see what is unexpected?
  10. rpc: Always return per-wtxid entries in submitpackage tx-results
    When submitpackage produced no per-transaction result for a member,
    the RPC previously set "error": "unevaluated" but then continued
    without inserting the entry into tx-results, making it impossible for
    callers to know which wtxids were unevaluated.
    
    Insert the placeholder result before continuing, update help text, and
    adjust functional tests to expect entries for all submitted wtxids.
    cad9a7fd73
  11. john-moffett force-pushed on Sep 19, 2025
  12. john-moffett commented at 2:42 pm on September 19, 2025: contributor
    Updated with suggestions. Thanks @instagibbs & @glozow.
  13. in src/rpc/mempool.cpp:1091 in cad9a7fd73
    1088-                    // No results, report error and continue
    1089-                    result_inner.pushKV("error", "unevaluated");
    1090+                    // No per-tx result for this wtxid
    1091+                    // Current invariant: per-tx results are all-or-none (every member or empty on package abort).
    1092+                    // If any exist yet this one is missing, it's an unexpected partial map.
    1093+                    CHECK_NONFATAL(package_result.m_tx_results.empty());
    


    instagibbs commented at 3:35 pm on September 19, 2025:

    Do we want the RPC to return an error, or stumble through and try to return something?

    Middle ground is adding an Assume() that gets compiled out in release builds @glozow


    glozow commented at 4:14 pm on September 19, 2025:
    I think CHECK_NONFATAL is fine. Assume might make it seem like this API quirk is more important than it actually is, and then we’d have to explain why it’s ok to delete it later.

    john-moffett commented at 1:10 pm on September 20, 2025:

    This is somewhat academic today as the RPC already errors on anything but all-or-none results from ProcessNewPackage:

    CHECK_NONFATAL(m_tx_results.size() == txns.size() || m_tx_results.empty())

    So if partial maps from ProcessNewPackage were ever done in practice, a call to submitpackage would run into that first check. If that guard were relaxed and tested to accommodate the change, the new check here would (appropriately) error as belt-and-suspenders, alerting the developer to change that as well. My feeling is that we should use the same check (CHECK_NONFATAL or Assume) for both places.

    I prefer that the RPC method guarantees a result for each wtxid, so having guards to keep it so makes sense to me.

  14. in src/rpc/mempool.cpp:971 in cad9a7fd73
    967@@ -968,7 +968,7 @@ static RPCHelpMan submitpackage()
    968                                 {{RPCResult::Type::STR_HEX, "", "transaction wtxid in hex"},
    969                             }},
    970                         }},
    971-                        {RPCResult::Type::STR, "error", /*optional=*/true, "The transaction error string, if it was rejected by the mempool"},
    972+                        {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."},
    


    glozow commented at 4:17 pm on September 19, 2025:
    is optional now false?

    john-moffett commented at 4:34 pm on September 19, 2025:

    I’d think it stays optional, as successful (and partially successful) submissions won’t have an error for every tx. See, eg, this test, where only the child has an error.

    Edit: this contrasts with the fact that we still got a result (ie - a tx-results entry) for every tx.


    glozow commented at 4:51 pm on September 19, 2025:
    Oh I did not read that carefully 🤦 yes.
  15. in src/rpc/mempool.cpp:1085 in cad9a7fd73
    1081@@ -1082,10 +1082,15 @@ static RPCHelpMan submitpackage()
    1082             for (const auto& tx : txns) {
    1083                 UniValue result_inner{UniValue::VOBJ};
    1084                 result_inner.pushKV("txid", tx->GetHash().GetHex());
    1085+                const auto wtxid_hex = tx->GetWitnessHash().GetHex();
    


    glozow commented at 9:28 pm on September 22, 2025:

    Fwiw not a huge deal but I wouldn’t recommend doing an unnecessary refactor at the same time as a fix to the missing RPC result.

    Looks like this is creating a copy of the string to avoid 2 calls to GetHex(), which seems sensible.


    john-moffett commented at 4:06 pm on September 24, 2025:
    Apologies if it was too minor to refactor! Will try to keep it more surgical in the future for these types of touch-up PRs.
  16. glozow commented at 9:29 pm on September 22, 2025: member
    ACK cad9a7fd7370f6df38370569f9d2de6ac6b7137a
  17. DrahtBot requested review from instagibbs on Sep 22, 2025
  18. instagibbs commented at 12:40 pm on September 23, 2025: member
    ACK cad9a7fd7370f6df38370569f9d2de6ac6b7137a
  19. fanquake merged this on Sep 23, 2025
  20. fanquake closed this on Sep 23, 2025


github-metadata-mirror

This is a metadata mirror of the GitHub repository bitcoin/bitcoin. This site is not affiliated with GitHub. Content is generated from a GitHub metadata backup.
generated: 2025-09-26 15:13 UTC

This site is hosted by @0xB10C
More mirrored repositories can be found on mirror.b10c.me