{
 "number": 36175,
 "repo": "bitcoin/bitcoin",
 "url": "https://github.com/bitcoin/bitcoin/pull/36175",
 "title": "rpc: Stamp `getblock` OpenRPC result discriminator",
 "author": "nervana21",
 "author_association": "CONTRIBUTOR",
 "created_at": "2026-09-05T14:20:31Z",
 "updated_at": "2026-09-17T05:08:44Z",
 "age_days": 12,
 "draft": false,
 "labels": [
  "RPC/REST/ZMQ"
 ],
 "milestone": null,
 "base": "master",
 "head_sha": "3b02b9b66935d06eba77b8369520bdabebf300ad",
 "head_ref": "openrpc-discriminated-result",
 "head_repo": "nervana21/bitcoin",
 "head_history": [
  {
   "t": "2026-09-06T21:52:20Z",
   "sha": "270ecacf902c586eccdcbe89cdd499201b7c2cd2"
  },
  {
   "t": "2026-09-07T22:49:36Z",
   "sha": "213b2ed9f807d1bdd0a77f4f459e8045028bda08"
  },
  {
   "t": "2026-09-16T23:23:32Z",
   "sha": "3b02b9b66935d06eba77b8369520bdabebf300ad"
  }
 ],
 "additions": 54,
 "deletions": 5,
 "changed_files": 4,
 "commit_count": 3,
 "size_bucket": "S",
 "mergeable_state": "clean",
 "bot": {
  "drahtbot": {
   "present": true,
   "reviews": {
    "concept_ack": [
     {
      "login": "jeanpablojp",
      "url": "https://github.com/bitcoin/bitcoin/pull/36175#pullrequestreview-5126833383"
     }
    ]
   },
   "conflicts": []
  }
 },
 "acks_parsed": {
  "jeanpablojp": {
   "kind": "concept_ack",
   "hash": null,
   "t": "2026-09-06T22:40:06Z",
   "stale": false
  }
 },
 "acks_tally": {
  "ack": 0,
  "stale_ack": 0,
  "concept_ack": 1,
  "approach_ack": 0,
  "nack": 0,
  "concept_nack": 0,
  "approach_nack": 0
 },
 "reviews": {
  "approved": 0,
  "changes_requested": 0,
  "distinct_reviewers": [
   "jeanpablojp",
   "maflcko"
  ]
 },
 "signals": {
  "needs_rebase": false,
  "ci_failed": false,
  "mergeable_state": "clean",
  "last_author_activity": "2026-09-16T23:24:02Z",
  "last_reviewer_activity": "2026-09-17T05:08:44Z",
  "last_reviewer": "maflcko",
  "author_silent_days": 0,
  "waiting_on_author_days": 0,
  "days_since_update": 0
 },
 "refs": {
  "mentioned": [],
  "depends_on": [],
  "fixes": [],
  "linked_issues": [],
  "references": [],
  "conflicts": []
 },
 "stack": {
  "shares_commits_with": [],
  "based_on": [],
  "base_for": []
 },
 "review_paths": [
  "src/rpc/blockchain.cpp",
  "src/rpc/server.cpp",
  "src/rpc/util.h"
 ],
 "body": "OpenRPC documents `getblock` as a four-way `oneOf` on `verbosity`, but the dump does not say which integer selects which arm. Therefore, clients that expose a type or method per verbosity (e.g. corepc, btcd) have to hardcode that map.\n\nThis patch adds optional `RPCResultDiscriminator` metadata, emits it as `x-bitcoin-discriminated-result`, and stamps `getblock`. `getblock` request handling and returned block data are unchanged. Now, `help getblock` notes that verbosity 2 and 3 cannot be told apart by validating a response alone.\n\nAlso updates `getopenrpcinfo` schema text to document `x-bitcoin-discriminated-result` and `x-bitcoin-default-hint`.\n\nThe change to the schema's format is:\n\n<code>x-bitcoin-discriminated-result</code> on <code>getblock</code>\n\n```diff\ndiff dump.json dump_new.json\n5590c5590,5600\n<           ]\n---\n[quoted text omitted]\n```\n\n<code>getblock</code> description notes verbosity 2 and 3 overlap\n\n```diff\ndiff openrpc.json openrpc_new.json\n4696c4696\n<       \"description\": \"If verbosity is 0, returns a string that is serialized, hex-encoded data for block 'hash'.\\nIf verbosity is 1, returns an Object with information about block <hash>.\\nIf verbosity is 2, returns an Object with information about block <hash> and information about each transaction.\\nIf 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).\",\n---\n[quoted text omitted]\n```\n\nschema text for <code>x-bitcoin-default-hint</code> and <code>x-bitcoin-discriminated-result</code>\n\n```diff\ndiff openrpc.json openrpc_new.json\n8610c8610\n<                           \"description\": \"JSON Schema for the parameter.\"\n---\n[quoted text omitted]\n8649c8649\n<                         \"description\": \"JSON Schema for the result. Numeric schemas may include \\\"x-bitcoin-unit\\\" property: \\\"amount\\\" which denotes a Bitcoin amount in BTC.\"\n---\n[quoted text omitted]\n13319c13319\n<                           \"description\": \"JSON Schema for the parameter.\"\n---\n[quoted text omitted]\n13358c13358\n<                         \"description\": \"JSON Schema for the result. Numeric schemas may include \\\"x-bitcoin-unit\\\" property: \\\"amount\\\" which denotes a Bitcoin amount in BTC.\"\n---\n[quoted text omitted]\n```\n\nOther results can also use the same discriminator pattern.",
 "commits": [
  {
   "sha": "4badc3b9899d6ba09e4dd69a6f54f1c20a790160",
   "date": "2026-09-16T23:22:31Z",
   "message": "rpc: Stamp `getblock` OpenRPC result discriminator\n\nOpenRPC documents `getblock` as a four-way `oneOf` on `verbosity`, but\nnothing in the schema maps `verbosity` values onto those branches.\n\nAdd optional `RPCResultDiscriminator` on `RPCResults`, emit it as\n`x-bitcoin-discriminated-result`, and stamp `getblock` so `verbosity`\nselects the existing oneOf arms via {0, 1, 2, 3} in that order.\n\nNo runtime behavior change."
  },
  {
   "sha": "04608c9346462ae49b760d5c954241e286104561",
   "date": "2026-09-16T23:22:32Z",
   "message": "rpc: Document `getblock` verbosity 2/3 schema overlap"
  },
  {
   "sha": "3b02b9b66935d06eba77b8369520bdabebf300ad",
   "date": "2026-09-16T23:22:32Z",
   "message": "rpc: Document OpenRPC schema extensions\n\nParameter schemas may include `x-bitcoin-default-hint` when the default\ncannot be expressed as a JSON value.\n\nMulti-result schemas may include `x-bitcoin-discriminated-result`\nnaming the request parameter or parameters that select among the\ntop-level oneOf branches."
  }
 ],
 "timeline": [
  {
   "t": "2026-09-06T21:52:20Z",
   "kind": "force_push",
   "who": "nervana21",
   "commit": "270ecacf902c586eccdcbe89cdd499201b7c2cd2"
  },
  {
   "t": "2026-09-06T22:40:06Z",
   "kind": "review",
   "who": "jeanpablojp",
   "assoc": "CONTRIBUTOR",
   "state": "COMMENTED",
   "commit": "270ecacf902c586eccdcbe89cdd499201b7c2cd2",
   "text": "Concept ACK\n\nOne thing I could not settle by reading. The test asserts the discriminator's literals rather than the two relations behind them.\n\nInserting an argument before `verbosity` in `getblock` leaves `parameterIndex` 1 addressing the new argument, and swapping the verbosity 2 and 3 arms points value 2 at the arm with `prevout`. rpc_openrpc.py passes on both builds, and none of the three new `CHECK_NONFATAL`s looks at either relation. Worth pinning them?\n\nComparing `getblock[\"params\"][discriminator[\"parameterIndex\"]][\"name\"]` to `discriminator[\"parameter\"]`, and asserting the two object arms differ in `prevout` in the order `values` claims, fails on both and passes on this head."
  },
  {
   "t": "2026-09-06T22:40:07Z",
   "kind": "review_comment",
   "who": "jeanpablojp",
   "assoc": "CONTRIBUTOR",
   "path": "src/rpc/util.h",
   "commit": "3b02b9b66935d06eba77b8369520bdabebf300ad",
   "in_reply_to": null,
   "text": "The only constructor takes `std::vector<int>`, though `values` is already a `std::vector<UniValue>`. Of the fifteen methods with a `oneOf` result today, only `getrawtransaction` is another integer case and six more turn on a boolean or a string, so `UniValue` would cover eight instead of two. The other seven need a different shape rather than a wider type, so eight is the ceiling for this shape. Is the integer form deliberate for a first pass? I tried it, and a `std::vector<UniValue>` overload sits beside the `int` one, with `getblockheader` emitting `\"values\": [true, false]` and `getblock` unchanged.\n\nnit: `param_name`, `param_index` and `values` could carry the `m_` prefix and the const that `RPCResults` and `RPCResult` next door use."
  },
  {
   "t": "2026-09-06T22:40:07Z",
   "kind": "review_comment",
   "who": "jeanpablojp",
   "assoc": "CONTRIBUTOR",
   "path": "src/rpc/server.cpp",
   "commit": "270ecacf902c586eccdcbe89cdd499201b7c2cd2",
   "in_reply_to": null,
   "text": "The `schema` field in `OpenRPCDocResult` already explains `x-bitcoin-unit` to whoever reads the help. Worth a line for `x-bitcoin-discriminatedResult` too? The parameter-side `schema` field next to it has the same gap for `x-bitcoin-default-hint`, if you would rather cover both at once.\n\nnit: the other `x-bitcoin-` keys in the document are all lowercase and hyphenated, so `x-bitcoin-discriminated-result` would match."
  },
  {
   "t": "2026-09-06T22:40:07Z",
   "kind": "review_comment",
   "who": "jeanpablojp",
   "assoc": "CONTRIBUTOR",
   "path": "src/rpc/blockchain.cpp",
   "commit": "3b02b9b66935d06eba77b8369520bdabebf300ad",
   "in_reply_to": null,
   "text": "Worth putting in the description? Validating cannot pick the arm either, because a block with no spends comes back byte identical at verbosity 2 and 3, since a coinbase input has no `prevout` to add, and arm 3 lists `prevout` without requiring it, so both arms accept both responses and the `oneOf` does not resolve. That answers the reviewer who asks why a consumer cannot just validate, which the current wording leaves open. Already true on the base."
  },
  {
   "t": "2026-09-07T20:14:13Z",
   "kind": "review_comment",
   "who": "nervana21",
   "assoc": "CONTRIBUTOR",
   "path": "src/rpc/blockchain.cpp",
   "commit": "3b02b9b66935d06eba77b8369520bdabebf300ad",
   "in_reply_to": 3945488554,
   "text": "Done."
  },
  {
   "t": "2026-09-07T20:14:48Z",
   "kind": "review_comment",
   "who": "nervana21",
   "assoc": "CONTRIBUTOR",
   "path": "src/rpc/server.cpp",
   "commit": "270ecacf902c586eccdcbe89cdd499201b7c2cd2",
   "in_reply_to": 3945488552,
   "text": "Done."
  },
  {
   "t": "2026-09-07T20:18:41Z",
   "kind": "review_comment",
   "who": "nervana21",
   "assoc": "CONTRIBUTOR",
   "path": "src/rpc/util.h",
   "commit": "3b02b9b66935d06eba77b8369520bdabebf300ad",
   "in_reply_to": 3945488550,
   "text": "Yes, the integer form was done deliberately on this first pass. Would prefer to add overloads in specific commits that use them.\n\nNits done."
  },
  {
   "t": "2026-09-07T20:37:28Z",
   "kind": "comment",
   "who": "nervana21",
   "assoc": "CONTRIBUTOR",
   "text": "[quoted text omitted]\n\nGood catch, thanks! I've updated the tests according to your suggestion"
  },
  {
   "t": "2026-09-07T22:49:36Z",
   "kind": "force_push",
   "who": "nervana21",
   "commit": "213b2ed9f807d1bdd0a77f4f459e8045028bda08"
  },
  {
   "t": "2026-09-16T23:23:32Z",
   "kind": "force_push",
   "who": "nervana21",
   "commit": "3b02b9b66935d06eba77b8369520bdabebf300ad"
  },
  {
   "t": "2026-09-16T23:24:02Z",
   "kind": "comment",
   "who": "nervana21",
   "assoc": "CONTRIBUTOR",
   "text": "Rebased off master"
  },
  {
   "t": "2026-09-17T05:08:44Z",
   "kind": "review_comment",
   "who": "maflcko",
   "assoc": "MEMBER",
   "path": "src/rpc/server.cpp",
   "commit": "3b02b9b66935d06eba77b8369520bdabebf300ad",
   "in_reply_to": null,
   "text": "What is this cast for?"
  }
 ],
 "labels_log": [
  {
   "t": "2026-09-05T14:20:35Z",
   "action": "labeled",
   "label": "RPC/REST/ZMQ",
   "who": "DrahtBot"
  }
 ],
 "state_log": [],
 "text_chars": 5829,
 "text_tokens_estimate": 1457,
 "changed_paths": [
  "src/rpc/blockchain.cpp",
  "src/rpc/server.cpp",
  "src/rpc/util.h",
  "test/functional/rpc_openrpc.py"
 ],
 "files": [
  {
   "path": "src/rpc/blockchain.cpp",
   "add": 5,
   "del": 3
  },
  {
   "path": "src/rpc/server.cpp",
   "add": 15,
   "del": 2
  },
  {
   "path": "src/rpc/util.h",
   "add": 23,
   "del": 0
  },
  {
   "path": "test/functional/rpc_openrpc.py",
   "add": 11,
   "del": 0
  }
 ],
 "test_lines": 11,
 "git": {
  "head": "3b02b9b66935d06eba77b8369520bdabebf300ad",
  "head_matches_backup": true,
  "base": "b8215855437288cac95c7fd5d41104c73c0f3495",
  "commits": [
   {
    "sha": "4badc3b989",
    "subject": "rpc: Stamp `getblock` OpenRPC result discriminator",
    "files": 4,
    "add": 48,
    "del": 2
   },
   {
    "sha": "04608c9346",
    "subject": "rpc: Document `getblock` verbosity 2/3 schema overlap",
    "files": 1,
    "add": 3,
    "del": 1
   },
   {
    "sha": "3b02b9b669",
    "subject": "rpc: Document OpenRPC schema extensions",
    "files": 1,
    "add": 3,
    "del": 2
   }
  ],
  "patch_truncated": false
 },
 "input_hash": "e1e5c0500cb812d1",
 "extracted_at": "2026-09-17T16:15:31+00:00"
}