rpc: replace ELISION references with explicit result fields #34764

pull satsfy wants to merge 6 commits into bitcoin:master from satsfy:fix-rpc-inheritance changing 9 files +378 −203
  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 rely on RPCResult::Type::ELISION entries whose structure is only described in prose. This keeps human-readable help concise, but leaves parts of the result layout implicit and prevents tools from deriving complete machine-readable schemas from RPCHelpMan metadata.

    This PR replaces ELISION-based reuse with shared structured definitions, so result layouts are represented directly in metadata rather than only in text. At the same time, human-readable help remains compact via explicit help-rendering elision using HelpElision, so previously elided sections stay abbreviated without losing schema completeness.

    Affected RPCs: getrawtransaction, getblock, listsinceblock, estimaterawfee, getaddressinfo.

    RPC return values are unchanged. Human-readable help remains compact, while structured result metadata becomes explicit enough to derive complete machine-readable schemas.

    A related RPCResult::Type::ELISION use in importdescriptors was split out into the follow-up PR #34867 because it changes the generated help output, per this review comment.

    Changes:

    • Introduce HelpElision (NONE, START, SKIP) and ElideGroup(), replacing the tri-state print_elision
    • Add an RPCResult copy-with-replacement-options constructor to support applying elision while keeping m_opts const
    • Extend TxDoc() / TxDocOptions to support reusable transaction layouts with optional prevout, fee, hex, and elision behavior
    • Replace ELISION-based reuse in getrawtransaction and getblock with explicit structured definitions
    • Factor shared result layouts into GetBlockFields(), ListSinceBlockTxFields(), FeeRateBucketDoc(), GetAddressInfoEmbeddedFields() and FeeEstimateHorizonDoc()
    • Expand listsinceblock.removed, estimaterawfee horizons/buckets and getaddressinfo.embedded into explicit metadata while preserving concise help output
  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, w0xlt

    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:

    • #34683 (RFC: Support a formal description of our JSON-RPC interface by willcl-ark)
    • #34049 (rpc: Disallow captures in RPCMethodImpl by ajtowns)
    • #31252 (rpc: print P2WSH and P2SH redem Script in (get/decode)rawtransaction by polespinasa)

    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.

  4. nervana21 commented at 9:19 pm on March 6, 2026: contributor
    Concept ACK
  5. satsfy force-pushed on Mar 7, 2026
  6. 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.

  7. DrahtBot added the label Needs rebase on Mar 8, 2026
  8. satsfy force-pushed on Mar 9, 2026
  9. satsfy marked this as ready for review on Mar 9, 2026
  10. DrahtBot removed the label Needs rebase on Mar 9, 2026
  11. willcl-ark commented at 1:53 pm on March 10, 2026: member

    Currently this doesn’t compile as a few brackets are mis-matched:

     0diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp
     1index 920080d3b9e..44baf03aad6 100644
     2--- a/src/rpc/blockchain.cpp
     3+++ b/src/rpc/blockchain.cpp
     4@@ -793,9 +793,7 @@ static RPCHelpMan getblock()
     5                         {
     6                             {RPCResult::Type::ELISION, "", "The transactions in the format of the getrawtransaction RPC. Different from verbosity = 1 \"tx\" result"},
     7                             {RPCResult::Type::NUM, "fee", /*optional=*/true, "The transaction fee in " + CURRENCY_UNIT + ", omitted if block undo data is not available"},
     8-                        }},
     9-                    }},
    10-                }},
    11+                        }})},
    12                     RPCResult{"for verbosity = 3",
    13                 RPCResult::Type::OBJ, "", "",
    14                 {
    15@@ -806,7 +804,9 @@ static RPCHelpMan getblock()
    16                         {
    17                             {RPCResult::Type::OBJ, "", "",
    18                                 TxDoc("The transaction id", TxDocOptions{.prevout = true, .fee = true, .fee_optional = true, .hex = true})},
    19-                        }})},
    20+                        }},
    21+                    }},
    22+                }},
    23                 },
    24                 RPCExamples{
    25                     HelpExampleCli("getblock", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\"")
    

    I’m not super thrilled about expanding (an already large) help output e.g.

     0❯ bitcoin-cli -regtest help getblock
     1getblock "blockhash" ( verbosity )
     2
     3If verbosity is 0, returns a string that is serialized, hex-encoded data for block 'hash'.
     4If verbosity is 1, returns an Object with information about block <hash>.
     5If verbosity is 2, returns an Object with information about block <hash> and information about each transaction.
     6If verbosity is 3, returns an Object with information about block <hash> and information about each transaction, including prevout information for inputs (only for unpruned blocks in the current best chain).
     7
     8Arguments:
     91. blockhash    (string, required) The block hash
    102. verbosity    (numeric, optional, default=1) 0 for hex-encoded data, 1 for a JSON object, 2 for JSON object with transaction data, and 3 for JSON object with transaction data including prevout information for inputs
    11
    12Result (for verbosity = 0):
    13"hex"    (string) A string that is serialized, hex-encoded data for block 'hash'
    14
    15Result (for verbosity = 1):
    16{                                 (json object)
    17  "hash" : "hex",                 (string) the block hash (same as provided)
    18  "confirmations" : n,            (numeric) The number of confirmations, or -1 if the block is not on the main chain
    19  "size" : n,                     (numeric) The block size
    20  "strippedsize" : n,             (numeric) The block size excluding witness data
    21  "weight" : n,                   (numeric) The block weight as defined in BIP 141
    22  "coinbase_tx" : {               (json object) Coinbase transaction metadata
    23    "version" : n,                (numeric) The coinbase transaction version
    24    "locktime" : n,               (numeric) The coinbase transaction's locktime (nLockTime)
    25    "sequence" : n,               (numeric) The coinbase input's sequence number (nSequence)
    26    "coinbase" : "hex",           (string) The coinbase input's script
    27    "witness" : "hex"             (string, optional) The coinbase input's first (and only) witness stack element, if present
    28  },
    29  "height" : n,                   (numeric) The block height or index
    30  "version" : n,                  (numeric) The block version
    31  "versionHex" : "hex",           (string) The block version formatted in hexadecimal
    32  "merkleroot" : "hex",           (string) The merkle root
    33  "tx" : [                        (json array) The transaction ids
    34    "hex",                        (string) The transaction id
    35    ...
    36  ],
    37  "time" : xxx,                   (numeric) The block time expressed in UNIX epoch time
    38  "mediantime" : xxx,             (numeric) The median block time expressed in UNIX epoch time
    39  "nonce" : n,                    (numeric) The nonce
    40  "bits" : "hex",                 (string) nBits: compact representation of the block difficulty target
    41  "target" : "hex",               (string) The difficulty target
    42  "difficulty" : n,               (numeric) The difficulty
    43  "chainwork" : "hex",            (string) Expected number of hashes required to produce the chain up to this block (in hex)
    44  "nTx" : n,                      (numeric) The number of transactions in the block
    45  "previousblockhash" : "hex",    (string, optional) The hash of the previous block (if available)
    46  "nextblockhash" : "hex"         (string, optional) The hash of the next block (if available)
    47}
    48
    49Result (for verbosity = 2):
    50{                   (json object)
    51  ...,              Same output as verbosity = 1
    52  "tx" : [          (json array)
    53    {               (json object)
    54      ...,          The transactions in the format of the getrawtransaction RPC. Different from verbosity = 1 "tx" result
    55      "fee" : n     (numeric) The transaction fee in BTC, omitted if block undo data is not available
    56    },
    57    ...
    58  ]
    59}
    60
    61Result (for verbosity = 3):
    62{                                        (json object)
    63  ...,                                   Same output as verbosity = 2
    64  "tx" : [                               (json array)
    65    {                                    (json object)
    66      "vin" : [                          (json array)
    67        {                                (json object)
    68          ...,                           The same output as verbosity = 2
    69          "prevout" : {                  (json object) (Only if undo information is available)
    70            "generated" : true|false,    (boolean) Coinbase or not
    71            "height" : n,                (numeric) The height of the prevout
    72            "value" : n,                 (numeric) The value in BTC
    73            "scriptPubKey" : {           (json object)
    74              "asm" : "str",             (string) Disassembly of the output script
    75              "desc" : "str",            (string) Inferred descriptor for the output
    76              "hex" : "hex",             (string) The raw output script bytes, hex-encoded
    77              "address" : "str",         (string, optional) The Bitcoin address (only if a well-defined address exists)
    78              "type" : "str"             (string) The type (one of: nonstandard, anchor, pubkey, pubkeyhash, scripthash, multisig, nulldata, witness_v0_scripthash, witness_v0_keyhash, witness_v1_taproot, witness_unknown)
    79            }
    80          }
    81        },
    82        ...
    83      ]
    84    },
    85    ...
    86  ]
    87}
    88
    89Examples:
    90> bitcoin-cli getblock "00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09"
    91> curl --user myusername --data-binary '{"jsonrpc": "2.0", "id": "curltest", "method": "getblock", "params": ["00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09"]}' -H 'content-type: application/json' http://127.0.0.1:8332/
    

    goes to

      0❯ ./build/bin/bitcoin-cli -regtest help getblock
      1getblock "blockhash" ( verbosity )
      2
      3If verbosity is 0, returns a string that is serialized, hex-encoded data for block 'hash'.
      4If verbosity is 1, returns an Object with information about block <hash>.
      5If verbosity is 2, returns an Object with information about block <hash> and information about each transaction.
      6If verbosity is 3, returns an Object with information about block <hash> and information about each transaction, including prevout information for inputs (only for unpruned blocks in the current best chain).
      7
      8Arguments:
      91. blockhash    (string, required) The block hash
     102. verbosity    (numeric, optional, default=1) 0 for hex-encoded data, 1 for a JSON object, 2 for JSON object with transaction data, and 3 for JSON object with transaction data including prevout information for inputs
     11
     12Result (for verbosity = 0):
     13"hex"    (string) A string that is serialized, hex-encoded data for block 'hash'
     14
     15Result (for verbosity = 1):
     16{                                 (json object)
     17  "hash" : "hex",                 (string) the block hash (same as provided)
     18  "confirmations" : n,            (numeric) The number of confirmations, or -1 if the block is not on the main chain
     19  "size" : n,                     (numeric) The block size
     20  "strippedsize" : n,             (numeric) The block size excluding witness data
     21  "weight" : n,                   (numeric) The block weight as defined in BIP 141
     22  "coinbase_tx" : {               (json object) Coinbase transaction metadata
     23    "version" : n,                (numeric) The coinbase transaction version
     24    "locktime" : n,               (numeric) The coinbase transaction's locktime (nLockTime)
     25    "sequence" : n,               (numeric) The coinbase input's sequence number (nSequence)
     26    "coinbase" : "hex",           (string) The coinbase input's script
     27    "witness" : "hex"             (string, optional) The coinbase input's first (and only) witness stack element, if present
     28  },
     29  "height" : n,                   (numeric) The block height or index
     30  "version" : n,                  (numeric) The block version
     31  "versionHex" : "hex",           (string) The block version formatted in hexadecimal
     32  "merkleroot" : "hex",           (string) The merkle root
     33  "tx" : [                        (json array) The transaction ids
     34    "hex",                        (string) The transaction id
     35    ...
     36  ],
     37  "time" : xxx,                   (numeric) The block time expressed in UNIX epoch time
     38  "mediantime" : xxx,             (numeric) The median block time expressed in UNIX epoch time
     39  "nonce" : n,                    (numeric) The nonce
     40  "bits" : "hex",                 (string) nBits: compact representation of the block difficulty target
     41  "target" : "hex",               (string) The difficulty target
     42  "difficulty" : n,               (numeric) The difficulty
     43  "chainwork" : "hex",            (string) Expected number of hashes required to produce the chain up to this block (in hex)
     44  "nTx" : n,                      (numeric) The number of transactions in the block
     45  "previousblockhash" : "hex",    (string, optional) The hash of the previous block (if available)
     46  "nextblockhash" : "hex"         (string, optional) The hash of the next block (if available)
     47}
     48
     49Result (for verbosity = 2):
     50{                                 (json object)
     51  "hash" : "hex",                 (string) the block hash (same as provided)
     52  "confirmations" : n,            (numeric) The number of confirmations, or -1 if the block is not on the main chain
     53  "size" : n,                     (numeric) The block size
     54  "strippedsize" : n,             (numeric) The block size excluding witness data
     55  "weight" : n,                   (numeric) The block weight as defined in BIP 141
     56  "coinbase_tx" : {               (json object) Coinbase transaction metadata
     57    "version" : n,                (numeric) The coinbase transaction version
     58    "locktime" : n,               (numeric) The coinbase transaction's locktime (nLockTime)
     59    "sequence" : n,               (numeric) The coinbase input's sequence number (nSequence)
     60    "coinbase" : "hex",           (string) The coinbase input's script
     61    "witness" : "hex"             (string, optional) The coinbase input's first (and only) witness stack element, if present
     62  },
     63  "height" : n,                   (numeric) The block height or index
     64  "version" : n,                  (numeric) The block version
     65  "versionHex" : "hex",           (string) The block version formatted in hexadecimal
     66  "merkleroot" : "hex",           (string) The merkle root
     67  "tx" : [                        (json array)
     68    ...,                          The transactions in the format of the getrawtransaction RPC. Different from verbosity = 1 "tx" result
     69    n,                            (numeric, optional) The transaction fee in BTC, omitted if block undo data is not available
     70    ...
     71  ],
     72  "time" : xxx,                   (numeric) The block time expressed in UNIX epoch time
     73  "mediantime" : xxx,             (numeric) The median block time expressed in UNIX epoch time
     74  "nonce" : n,                    (numeric) The nonce
     75  "bits" : "hex",                 (string) nBits: compact representation of the block difficulty target
     76  "target" : "hex",               (string) The difficulty target
     77  "difficulty" : n,               (numeric) The difficulty
     78  "chainwork" : "hex",            (string) Expected number of hashes required to produce the chain up to this block (in hex)
     79  "nTx" : n,                      (numeric) The number of transactions in the block
     80  "previousblockhash" : "hex",    (string, optional) The hash of the previous block (if available)
     81  "nextblockhash" : "hex"         (string, optional) The hash of the next block (if available)
     82}
     83
     84Result (for verbosity = 3):
     85{                                          (json object)
     86  ...,                                     Same output as verbosity = 2
     87  "tx" : [                                 (json array)
     88    {                                      (json object)
     89      "" : {                               (json object)
     90        "txid" : "hex",                    (string) The transaction id
     91        "hash" : "hex",                    (string) The transaction hash (differs from txid for witness transactions)
     92        "size" : n,                        (numeric) The serialized transaction size
     93        "vsize" : n,                       (numeric) The virtual transaction size (differs from size for witness transactions)
     94        "weight" : n,                      (numeric) The transaction's weight (between vsize*4-3 and vsize*4)
     95        "version" : n,                     (numeric) The version
     96        "locktime" : xxx,                  (numeric) The lock time
     97        "vin" : [                          (json array)
     98          {                                (json object)
     99            "coinbase" : "hex",            (string, optional) The coinbase value (only if coinbase transaction)
    100            "txid" : "hex",                (string, optional) The transaction id (if not coinbase transaction)
    101            "vout" : n,                    (numeric, optional) The output number (if not coinbase transaction)
    102            "scriptSig" : {                (json object, optional) The script (if not coinbase transaction)
    103              "asm" : "str",               (string) Disassembly of the signature script
    104              "hex" : "hex"                (string) The raw signature script bytes, hex-encoded
    105            },
    106            "txinwitness" : [              (json array, optional)
    107              "hex",                       (string) hex-encoded witness data (if any)
    108              ...
    109            ],
    110            "prevout" : {                  (json object, optional) The previous output, omitted if block undo data is not available
    111              "generated" : true|false,    (boolean) Coinbase or not
    112              "height" : n,                (numeric) The height of the prevout
    113              "value" : n,                 (numeric) The value in BTC
    114              "scriptPubKey" : {           (json object)
    115                "asm" : "str",             (string) Disassembly of the output script
    116                "desc" : "str",            (string) Inferred descriptor for the output
    117                "hex" : "hex",             (string) The raw output script bytes, hex-encoded
    118                "address" : "str",         (string, optional) The Bitcoin address (only if a well-defined address exists)
    119                "type" : "str"             (string) The type (one of: nonstandard, anchor, pubkey, pubkeyhash, scripthash, multisig, nulldata, witness_v0_scripthash, witness_v0_keyhash, witness_v1_taproot, witness_unknown)
    120              }
    121            },
    122            "sequence" : n                 (numeric) The script sequence number
    123          },
    124          ...
    125        ],
    126        "vout" : [                         (json array)
    127          {                                (json object)
    128            "value" : n,                   (numeric) The value in BTC
    129            "n" : n,                       (numeric) index
    130            "scriptPubKey" : {             (json object)
    131              "asm" : "str",               (string) Disassembly of the output script
    132              "desc" : "str",              (string) Inferred descriptor for the output
    133              "hex" : "hex",               (string) The raw output script bytes, hex-encoded
    134              "address" : "str",           (string, optional) The Bitcoin address (only if a well-defined address exists)
    135              "type" : "str"               (string) The type (one of: nonstandard, anchor, pubkey, pubkeyhash, scripthash, multisig, nulldata, witness_v0_scripthash, witness_v0_keyhash, witness_v1_taproot, witness_unknown)
    136            }
    137          },
    138          ...
    139        ],
    140        "fee" : n,                         (numeric, optional) transaction fee in BTC, omitted if block undo data is not available
    141        "hex" : "hex"                      (string) The hex-encoded transaction data
    142      }
    143    },
    144    ...
    145  ]
    146}
    147
    148Examples:
    149> bitcoin-cli getblock "00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09"
    150> curl --user myusername --data-binary '{"jsonrpc": "2.0", "id": "curltest", "method": "getblock", "params": ["00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09"]}' -H 'content-type: application/json' http://127.0.0.1:8332/
    

    but, this is certainly one “solution” to ellisions being difficult for a spec parser to read, so it definitely improves on this front. But doing it at the expense of a worse experience for humans reading bitcoin-cli help <cmd>.

    I’ve picked this PR (with the fixup) into #34683 so we can take a look at it all in one place there.

  12. satsfy force-pushed on Mar 10, 2026
  13. satsfy commented at 3:47 pm on March 10, 2026: none

    Thanks for the review, will keep supporting the OpenRPC implementation.

    In the latest push, I fixed bracket balancing and dropped the fee optionality config since it’s always optional (see #34702).

    On the help output getting larger for user, I envision a follow-up with the OpenRPC work that:

    • Fully defines all RPCHelpMan results, eliminating ELISIONs
    • Allows configuring what bitcoin-cli help displays to avoid excessive verbosity
    • Improves the type system for codegen use (see this comment).
  14. satsfy commented at 4:15 pm on March 10, 2026: none
    Note for reviewers: the changes in this PR have been incorporated into #34683. I’ll keep this open until it’s clear which one will move forward.
  15. w0xlt commented at 11:38 pm on March 10, 2026: contributor
    Concept ACK
  16. maflcko commented at 11:29 am on March 11, 2026: member

    I’d presume it would be possible to return a human readable help text, but use the full structure internally for MatchesType checks. This is required for #34702 (comment) etc …

    I’ve implemented this in #34799.

    If you agree, you may review it and rebase on top of it. I’ve also re-named the function to TxDoc, so that it is easier for you to rebase.

  17. willcl-ark commented at 11:39 am on March 11, 2026: member
    Perhaps we could approve CI to run in here please?
  18. satsfy force-pushed on Mar 11, 2026
  19. DrahtBot added the label CI failed on Mar 12, 2026
  20. in src/rpc/rawtransaction_util.h:86 in e9072d1e55 outdated
    82+ * Optional sections are controlled by @p opts.
    83+ *
    84+ * @param[in] opts            Selects which optional fields to include
    85+ *
    86+ * @return A vector of RPCResult describing the decoded transaction object
    87+ */
    


    maflcko commented at 2:46 pm on March 12, 2026:

    nit in e9072d1e55a96912c1a90ad8b385be4f9de79ef8: I think the comment is a bit long. The function should be pretty self-explanatory and a very brief comment should be sufficient:

    0/// Explain the UniValue "decoded" transaction object, some fields are adjusted according to the passed [@p](/bitcoin-bitcoin/contributor/p/) opts.
    

    satsfy commented at 3:12 am on March 18, 2026:
    Sure, done!
  21. in src/rpc/rawtransaction_util.h:63 in e9072d1e55 outdated
    55@@ -56,15 +56,34 @@ void AddOutputs(CMutableTransaction& rawTx, const UniValue& outputs_in);
    56 /** Create a transaction from univalue parameters */
    57 CMutableTransaction ConstructTransaction(const UniValue& inputs_in, const UniValue& outputs_in, const UniValue& locktime, std::optional<bool> rbf, uint32_t version);
    58 
    59+/** Options controlling which optional fields TxDoc() includes. All fields
    60+ * default to false so callers only need to name the ones they enable:
    61+ *
    62+ *   TxDoc({.prevout = true, .hex = true})
    63+ */
    


    maflcko commented at 2:51 pm on March 12, 2026:

    nit in e9072d1e55a96912c1a90ad8b385be4f9de79ef8: Same here. I think this can be removed. Also, “all default to false” may not be accurate, if the type is std::string or std::optional.

    Maybe remove or:

    0/// Options controlling some fields in TxDoc(). Callers only need to name the ones they enable:
    1///
    2/// TxDoc({.prevout = true, .hex = true})
    

    (Also changed to the doxygen /// comment format, because the /** is a bit ugly, when the text starts inconsistently and is inconsistently indented)


    maflcko commented at 2:53 pm on March 12, 2026:

    Also, in the same commit: It could be easier to review if the commit adding the option also made use of it at the same time. Otherwise, this looks like dead code.

    That is, adding prevout option to TxDoc could be done in the commit f225a25a9eff167cce0c5012bd7b7475f486cd3e, which makes use of it.


    satsfy commented at 3:15 am on March 18, 2026:
    Comment change done. My current commit order still have some dead code, will address.

    satsfy commented at 3:29 am on March 19, 2026:
    All bisect issues and review coherence issues solved. Lmk if anything else should change.
  22. maflcko commented at 2:54 pm on March 12, 2026: member
    left some nits
  23. satsfy marked this as a draft on Mar 12, 2026
  24. satsfy commented at 8:28 pm on March 12, 2026: none

    In light of @maflcko’s work in #34799, I’m adjusting this PR so the result structure remains explicit in metadata without worsening the human-readable help output.

    I’ve already updated estimaterawfee. After re-checking getaddressinfo.embedded, I think its currently documented shape can also be made explicit here, so I plan to include that as well. I’ll also cover the remaining related case in importdescriptors and clean up the documentation diffs affecting getblock and listsinceblock.

    The goal remains the same: make these result layouts fully specified in code while avoiding unnecessary user-visible help churn.

  25. luke-jr commented at 6:55 am on March 16, 2026: member
    Seems like it should be practical to continue to elide for human-facing docs, while still keeping track of the structure internally for checking and OpenRPC…
  26. DrahtBot removed the label CI failed on Mar 16, 2026
  27. satsfy force-pushed on Mar 18, 2026
  28. satsfy marked this as ready for review on Mar 18, 2026
  29. rpc: introduce HelpElision enum and ElideGroup helper
    Replace the tri-state std::optional<std::string> print_elision
    option with an explicit HelpElision enum (NONE, START, SKIP),
    and add an ElideGroup() helper for stamping elision onto a vector
    of RPCResult fields.
    
    Keep Type::ELISION as a deprecated alias.
    a5511eab6f
  30. in src/wallet/rpc/backup.cpp:348 in 514f8dbf69
    346-                                {RPCResult::Type::ELISION, "", "JSONRPC error"},
    347-                            }},
    348+                                ElideGroup({
    349+                                    {RPCResult::Type::NUM, "code", "JSONRPC error code"},
    350+                                    {RPCResult::Type::STR, "message", "JSONRPC error message"},
    351+                                }, "JSONRPC error")},
    


    maflcko commented at 6:37 am on March 18, 2026:

    nit in 514f8dbf691b115f0223dfbb53489a08510b2b96: Looks like there are two fields and elision brings them down to one. Not sure why this is done. It could make sense to confirm that exactly both fields are always returned (even with a different jsonrpc version) and then print both in the help text, as well as the machine readable json.

    Maybe as a separate pull request, since it would be unrelated to the new elision feature?


    satsfy commented at 3:53 am on March 19, 2026:

    Good catch. I verified this on regtest. The "error" field in importdescriptors is returned as a structured JSON-RPC object with code and message:

    0{
    1  "success": false,
    2  "error": {
    3    "code": -5,
    4    "message": "Missing checksum"
    5  }
    6}
    

    I agree that making the help text reflect both fields would be a separate follow-up, since that would be unrelated to the elision change here.


    maflcko commented at 5:14 am on March 19, 2026:
    What I wanted to say is that there is no need to first change the code, then only to change it again. It would be better to only change the code once.

    maflcko commented at 1:56 pm on March 19, 2026:
    I think it could make sense to split up fc98a984bb60b6382f708b892362b0c952485a76 into its own pull, as it is conceptually different from the other changes here.

    satsfy commented at 4:22 pm on March 19, 2026:
    Thanks for the suggestion, have separated the change in a new PR: #34867.
  31. satsfy force-pushed on Mar 19, 2026
  32. rpc: extend TxDoc() for getrawtransaction verbosity 2
    Add prevout, elision_description_silent, and
    vin_inner_elision options to TxDocOptions, and use them to
    describe getrawtransaction verbosity=2 with structured metadata
    instead of raw ELISION entries.
    
    When vin_inner_elision is set, vin fields are elided while
    keeping prevout visible.
    4e6d200fca
  33. satsfy force-pushed on Mar 19, 2026
  34. willcl-ark commented at 1:51 pm on March 19, 2026: member

    While the CI is not re-run here (sorry, it takes a manual approval for new contributors which is tedious) you could run the clang-tidy ci locally and fixup

    0env -i HOME="$HOME" PATH="$PATH" USER="$USER" FILE_ENV="./ci/test/00_setup_env_native_tidy.sh" ./ci/test_run_all.sh
    
  35. DrahtBot added the label CI failed on Mar 19, 2026
  36. satsfy force-pushed on Mar 19, 2026
  37. in src/rpc/util.cpp:1196 in 2da7be19aa
    1192@@ -1193,6 +1193,7 @@ UniValue RPCResult::MatchesType(const UniValue& result) const
    1193         }
    1194 
    1195         for (const auto& doc_entry : m_inner) {
    1196+            if (doc_entry.m_opts.skip_type_check) continue;
    


    w0xlt commented at 6:20 pm on March 19, 2026:

    Placing this here causes skip_type_check fields to bypass checks for required fields. Moving it below the key lookup ensures that only type validation is skipped.

     0--- a/src/rpc/util.cpp
     1+++ b/src/rpc/util.cpp
     2@@ -1193,7 +1193,6 @@ UniValue RPCResult::MatchesType(const UniValue& result) const
     3         }
     4 
     5         for (const auto& doc_entry : m_inner) {
     6-            if (doc_entry.m_opts.skip_type_check) continue;
     7             const auto result_it{result_obj.find(doc_entry.m_key_name)};
     8             if (result_it == result_obj.end()) {
     9                 if (!doc_entry.m_optional) {
    10@@ -1201,6 +1200,7 @@ UniValue RPCResult::MatchesType(const UniValue& result) const
    11                 }
    12                 continue;
    13             }
    14+            if (doc_entry.m_opts.skip_type_check) continue;
    15             UniValue match{doc_entry.MatchesType(result_it->second)};
    16             if (!match.isTrue()) errors.pushKV(doc_entry.m_key_name, std::move(match));
    17         }
    

    The following test mirrors the getwalletinfo RPC’s scanning field behavior and can be used to validate this.

     0--- a/src/test/rpc_tests.cpp
     1+++ b/src/test/rpc_tests.cpp
     2@@ -600,6 +600,24 @@ static void CheckRpc(const std::vector<RPCArg>& params, const UniValue& args, RP
     3     rpc.HandleRequest(req);
     4 }
     5 
     6+BOOST_AUTO_TEST_CASE(rpc_result_skip_type_check_still_checks_presence)
     7+{
     8+    const RPCResult result_doc{
     9+        RPCResult::Type::OBJ,
    10+        "",
    11+        "",
    12+        {
    13+            {RPCResult::Type::BOOL, "scanning", "Either false or a scanning progress object", {}, {.skip_type_check = true}},
    14+        },
    15+    };
    16+
    17+    const UniValue missing_result{result_doc.MatchesType(JSON(R"({})"))};
    18+    BOOST_CHECK_EQUAL(missing_result.write(), R"({"scanning":"key missing, despite not being optional in doc"})");
    19+
    20+    BOOST_CHECK(result_doc.MatchesType(JSON(R"({"scanning":false})")).isTrue());
    21+    BOOST_CHECK(result_doc.MatchesType(JSON(R"({"scanning":{"duration":1,"progress":0.5}})")).isTrue());
    22+}
    23+
    24 BOOST_AUTO_TEST_CASE(rpc_arg_helper)
    25 {
    26     constexpr bool DEFAULT_BOOL = true;
    

    satsfy commented at 8:30 pm on March 20, 2026:
    Thanks for pointing this out. While addressing it, I ran into CI failures and re-checked the prevout handling covered by this PR. That made it clear that prevout should remain documented as optional here, so the skip_type_check change is not needed after all. I’ve dropped that modification in the updated version.
  38. DrahtBot removed the label CI failed on Mar 20, 2026
  39. satsfy force-pushed on Mar 20, 2026
  40. rpc: extend TxDoc() for getblock verbosity 2/3
    Add fee, hex, fee_doc, prevout_doc, and vin_item_doc
    options to TxDocOptions, and use them to describe
    getblock verbosity=2/3 with structured metadata instead
    of inline ELISION-based reuse.
    
    Add GetBlockFields() to share the block-level result layout
    across verbosity levels.
    0f86c95fba
  41. rpc: extract ListSinceBlockTxFields() helper
    Extract the inline listsinceblock transaction field list into
    a reusable helper.
    
    Use the shared definition for both the transactions and removed
    arrays, replacing the ELISION-based removed entry with explicit
    metadata.
    f632f94889
  42. rpc: extract fee estimate result helpers
    Replace inline fee estimation field lists in estimaterawfee with
    reusable FeeRateBucketDoc() and FeeEstimateHorizonDoc() helpers.
    
    Use ElideGroup() to keep repeated horizon and bucket sections
    compact in human-readable help while preserving explicit result
    metadata.
    087e53eb74
  43. rpc: expand getaddressinfo embedded with explicit fields
    Replace the ELISION entry inside getaddressinfo's embedded object
    with explicit fields using ElideGroup().
    
    Factor the embedded field list into a helper so the nested layout
    can be reused without duplicating the full structure inline.
    88ec943b9b
  44. satsfy force-pushed on Mar 20, 2026
  45. satsfy commented at 10:20 pm on March 20, 2026: none

    For reviewers following earlier revisions: after several force-pushes, the current PR is limited to the help/metadata elision refactor.

    Current scope:

    • introduce HelpElision / ElideGroup()
    • extend TxDoc() for reusable transaction layouts
    • replace ELISION-based reuse with explicit structured metadata in getrawtransaction, getblock, listsinceblock.removed, estimaterawfee, and getaddressinfo.embedded
    • factor repeated layouts into small helpers

    No longer part of this PR:

    • importdescriptors error-object change, split out into #34867
    • earlier skip_type_check / MatchesType() change, now dropped

    bitcoin-cli help output is unchanged.

  46. DrahtBot added the label CI failed on Mar 24, 2026
  47. DrahtBot removed the label CI failed on Mar 24, 2026

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-30 00:13 UTC

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