rpc: replace ELISION references with explicit result fields #34764

pull satsfy wants to merge 5 commits into bitcoin:master from satsfy:fix-rpc-inheritance changing 5 files +170 −161
  1. satsfy commented at 8:18 pm on March 6, 2026: none

    Partially addresses #29912. Motivated by #34683, which exports OpenRPC from existing RPCHelpMan metadata. Sample OpenRPC.

    Some RPC help definitions currently rely on RPCResult::Type::ELISION entries whose structure is only described in prose. This is concise for human-readable help, but it prevents tools from deriving complete machine-readable result schemas from the metadata.

    This PR replaces all non-recursive ELISION-based reuses with shared structured definitions, so the result layout is represented directly in RPCHelpMan metadata instead of only in text.

    Affected RPCs:

    • decodepsbt
    • getrawtransaction
    • getblock
    • listsinceblock

    The patch also replaces DecodeTxDoc() with TxDoc() plus a TxDocOptions struct, so decoded transaction layouts can be reused without positional booleans and selectively extended with prevout, fee, and hex fields.

    As a consequence, bitcoin-cli output for affected RPCs becomes more verbose, since prose summaries like “Same output as verbosity = 1” are replaced by the full field definitions. The actual RPC return values are unchanged. I opened this as a draft because I’d like to discuss whether this tradeoff is acceptable, or whether the help renderer should collapse some sub-structures via manual configuration back into short summaries while keeping the underlying metadata explicit.

    This PR doesn’t cover getaddressinfo.embedded, which is recursive — runtime output can contain nested embedded objects, and RPCResult has no way to express that today. Happy to discuss approaches here if anyone has thoughts.

    This PR also implements the fee field fix in getblock RPC result (PR #34702 also implements), which should be optional but is not marked as such.

    Changes:

    • replace DecodeTxDoc() with TxDoc() and TxDocOptions
    • replace ELISION-based reuse in decodepsbt, getrawtransaction, getblock, and listsinceblock
    • factor shared result layouts into TxDoc(), GetBlockFields(), and ListSinceBlockTxFields()
    • mark getblock transaction fee documentation optional where it is conditionally present
  2. DrahtBot added the label RPC/REST/ZMQ on Mar 6, 2026
  3. DrahtBot commented at 8:19 pm on March 6, 2026: contributor

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

    Reviews

    See the guideline for information on the review process.

    Type Reviewers
    Concept ACK nervana21, Bortlesboat

    If your review is incorrectly listed, please copy-paste <!–meta-tag:bot-skip–> into the comment that the bot should ignore.

    Conflicts

    Reviewers, this pull request conflicts with the following ones:

    • #34702 (doc: Fix fee field in getblock RPC result by nervana21)
    • #34049 (rpc: Disallow captures in RPCMethodImpl by ajtowns)
    • #31252 (rpc: print P2WSH and P2SH redem Script in (get/decode)rawtransaction by polespinasa)
    • #21283 (Implement BIP 370 PSBTv2 by achow101)

    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.

    LLM Linter (✨ experimental)

    Possible places where named args for integral literals may be used (e.g. func(x, /*named_arg=*/0) in C++, and func(x, named_arg=0) in Python):

    • RPCResult{RPCResult::Type::STR_HEX, “witness”, /optional=/true, “The coinbase input’s first (and only) witness stack element, if present”} in src/rpc/blockchain.cpp
    • RPCResult{RPCResult::Type::STR_HEX, “previousblockhash”, /optional=/true, “The hash of the previous block (if available)”} in src/rpc/blockchain.cpp
    • RPCResult{RPCResult::Type::STR_HEX, “nextblockhash”, /optional=/true, “The hash of the next block (if available)”} in src/rpc/blockchain.cpp
    • RPCResult{RPCResult::Type::OBJ, “non_witness_utxo”, /optional=/true, “Decoded network transaction for non-witness UTXOs”, TxDoc(“The transaction id”)} in src/rpc/rawtransaction.cpp
    • RPCResult{RPCResult::Type::BOOL, “in_active_chain”, /optional=/true, “Whether specified block is in the active chain or not (only present with explicit "blockhash" argument)”} in src/rpc/rawtransaction.cpp
    • RPCResult{RPCResult::Type::STR_HEX, “blockhash”, /optional=/true, “the block hash”} in src/rpc/rawtransaction.cpp
    • RPCResult{RPCResult::Type::NUM, “confirmations”, /optional=/true, “The confirmations”} in src/rpc/rawtransaction.cpp
    • RPCResult{RPCResult::Type::NUM_TIME, “blocktime”, /optional=/true, “The block time expressed in " + UNIX_EPOCH_TIME} in src/rpc/rawtransaction.cpp
    • RPCResult{RPCResult::Type::NUM, “time”, /optional=/true, “Same as "blocktime"”} in src/rpc/rawtransaction.cpp
    • RPCResult{RPCResult::Type::NUM, “fee”, /optional=/true, “transaction fee in " + CURRENCY_UNIT + “, omitted if block undo data is not available”} in src/rpc/rawtransaction.cpp
    • {RPCResult::Type::STR_HEX, “txid”, /optional=/true, “The transaction id (if not coinbase transaction)”} in src/rpc/rawtransaction_util.cpp
    • {RPCResult::Type::NUM, “vout”, /optional=/true, “The output number (if not coinbase transaction)”} in src/rpc/rawtransaction_util.cpp
    • {RPCResult::Type::OBJ, “scriptSig”, /optional=/true, “The script (if not coinbase transaction)”, { … }} in src/rpc/rawtransaction_util.cpp
    • {RPCResult::Type::ARR, “txinwitness”, /optional=/true, “”, { {RPCResult::Type::STR_HEX, “hex”, “hex-encoded witness data (if any)”} }} in src/rpc/rawtransaction_util.cpp
    • {RPCResult::Type::OBJ, “prevout”, /optional=/true, “The previous output, omitted if block undo data is not available”, { … }} in src/rpc/rawtransaction_util.cpp
    • vout_item.emplace_back(RPCResult::Type::BOOL, “ischange”, /optional=/true, “Output script is change (only present if true)”); in src/rpc/rawtransaction_util.cpp
    • {RPCResult::Type::STR, “address”, /optional=/true, “The bitcoin address of the transaction (not returned if the output does not have an address, e.g. OP_RETURN null data).”} in src/wallet/rpc/transactions.cpp
    • {RPCResult::Type::STR_AMOUNT, “fee”, /optional=/true, “The amount of the fee in " + CURRENCY_UNIT + “. This is negative and only available for the\n’send’ category of transactions.”} in src/wallet/rpc/transactions.cpp
    • {RPCResult::Type::STR, “label”, /optional=/true, “A comment for the address/transaction, if any”} in src/wallet/rpc/transactions.cpp

    If you would like, I can produce specific suggested comment-style naming (e.g., replacing the third positional bool with a named comment like /optional=/) for each of these constructor/initializer usages.

    2026-03-07 02:30:58

  4. nervana21 commented at 9:19 pm on March 6, 2026: contributor
    Concept ACK
  5. rpc: replace DecodeTxDoc with TxDoc
    DecodeTxDoc() uses positional bool arguments to control which
    optional fields appear in decoded transaction result documentation.
    As more call sites need different combinations of prevout, fee, and
    hex fields, this becomes harder to read and more error-prone.
    
    Replace it with TxDoc(), which takes a TxDocOptions struct with
    named fields defaulting to false. Callers can then opt into the
    needed fields explicitly, e.g.
    
        TxDoc("The transaction id", TxDocOptions{.prevout = true, .fee = true})
    
    This is a pure refactor. Help output is unchanged. Move the helper
    to rpc/util.{h,cpp} so it can be reused across subsystems in
    follow-up commits.
    2c9e5e3336
  6. rpc: make decodepsbt transaction results explicit
    decodepsbt describes its "tx" and "non_witness_utxo" result fields
    using ELISION prose referring to decoderawtransaction output. This
    works for human-readable help, but schema generators cannot resolve
    those references into structured field definitions.
    
    Replace both ELISION entries with TxDoc() so the transaction layout
    is represented directly in RPCHelpMan metadata.
    4c4887edd8
  7. rpc: make getrawtransaction verbosity=2 result explicit
    The verbosity=2 result for getrawtransaction contains ELISION prose
    both at the top level ("Same output as verbosity = 1") and within
    each vin entry. These references are readable for humans but do not
    provide structured result metadata.
    
    Replace them with the full result structure using Cat() and TxDoc()
    with prevout enabled.
    3a7c72a03d
  8. rpc: make getblock verbosity results explicit
    getblock defines four verbosity levels. The verbosity=2 and
    verbosity=3 results use ELISION entries to refer to lower verbosity
    layouts, even though the only material difference between levels is
    the shape of the "tx" field.
    
    Introduce GetBlockFields(RPCResult tx_result) to build the full
    block result structure while substituting the appropriate "tx"
    definition in the correct position. This avoids ELISION prose and
    also avoids the duplicate "tx" field a naive Cat() approach would
    produce.
    
    Remove the now-unused getblock_vin helper.
    cefe884ffd
  9. wallet: make listsinceblock removed results explicit
    The "removed" array in listsinceblock is described with an ELISION
    entry referring to the "transactions" array layout. This is clear in
    human-readable help, but it leaves the result structure implicit.
    
    Extract ListSinceBlockTxFields() and use it for both arrays so the
    transaction layout is defined once and represented explicitly in
    RPCHelpMan metadata.
    b2e56e3957
  10. satsfy force-pushed on Mar 7, 2026
  11. Bortlesboat commented at 10:50 pm on March 7, 2026: none

    Code Review ACK

    Thorough review of the diff. This is a well-structured elimination of RPCResult::Type::ELISION in favor of explicit documentation:

    What it does:

    • Renames DecodeTxDocTxDoc with a new TxDocOptions struct using designated initializers instead of positional booleans — much cleaner API
    • Creates GetBlockFields() to deduplicate the getblock verbosity=1/2/3 help text, parameterized by the tx array result
    • Creates ListSinceBlockTxFields() to share field definitions between transactions and removed arrays in listsinceblock
    • Expands all ELISION placeholders into explicit field documentation

    Why this matters: ELISION forced users reading bitcoin-cli help getblock to mentally cross-reference different verbosity levels. Now each level is self-contained, which is especially helpful for verbosity=3 where the prevout fields were previously buried behind two levels of “same as above”.

    Code observations:

    • TxDocOptions with default-false members + designated initializers is clean C++20 — callers only name what they enable
    • fee_optional controlling the /*optional=*/ param on RPCResult is a nice touch
    • GetBlockFields taking RPCResult tx_result by value + std::move is correct
    • The #include <rpc/rawtransaction_util.h> addition in blockchain.cpp is the right include for the new TxDoc/TxDocOptions dependency

    One minor note: the old verbosity=2 getblock ELISION had descriptive text “The transactions in the format of the getrawtransaction RPC. Different from verbosity = 1 ’tx’ result” — this contextual note is lost, but the explicit fields are self-documenting so arguably better.

  12. DrahtBot added the label Needs rebase on Mar 8, 2026
  13. DrahtBot commented at 2:44 pm on March 8, 2026: contributor
    🐙 This pull request conflicts with the target branch and needs rebase.

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: 2026-03-09 12:13 UTC

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