{
 "number": 36642,
 "repo": "bitcoin/bitcoin",
 "url": "https://github.com/bitcoin/bitcoin/pull/36642",
 "title": "rpc: reset id and version per batch element",
 "author": "fametrano",
 "author_association": "FIRST_TIME_CONTRIBUTOR",
 "created_at": "2026-10-24T06:49:59Z",
 "updated_at": "2026-11-01T18:41:37Z",
 "description_hash": "bda9f55b49d27797",
 "age_days": 8,
 "draft": false,
 "labels": [
  "RPC/REST/ZMQ"
 ],
 "milestone": null,
 "base": "master",
 "head_sha": "2ab7c47f6036cec706e6a0df58905aa3eeb1d843",
 "head_ref": "rpc-batch-reset-id",
 "head_repo": "fametrano/bitcoin",
 "head_history": [
  {
   "t": "2026-11-01T18:29:58Z",
   "sha": "2ab7c47f6036cec706e6a0df58905aa3eeb1d843"
  }
 ],
 "additions": 23,
 "deletions": 2,
 "changed_files": 2,
 "commit_count": 1,
 "size_bucket": "S",
 "mergeable_state": "clean",
 "bot": {
  "drahtbot": {
   "present": true,
   "reviews": {
    "concept_ack": [
     {
      "login": "pinheadmz",
      "url": "https://github.com/bitcoin/bitcoin/pull/36642#pullrequestreview-5658199014"
     }
    ],
    "stale_ack": [
     {
      "login": "AndreaDiazCorreia",
      "url": "https://github.com/bitcoin/bitcoin/pull/36642#pullrequestreview-5646637313"
     }
    ]
   },
   "conflicts": []
  }
 },
 "acks_parsed": {
  "AndreaDiazCorreia": {
   "kind": "ack",
   "hash": "0811092e117f08ac9ad0e608f796cd8ac014abd0",
   "t": "2026-10-26T02:05:40Z",
   "stale": true
  },
  "pinheadmz": {
   "kind": "concept_ack",
   "hash": null,
   "t": "2026-10-26T20:05:20Z",
   "stale": false
  }
 },
 "acks_tally": {
  "ack": 0,
  "stale_ack": 1,
  "concept_ack": 1,
  "approach_ack": 0,
  "nack": 0,
  "concept_nack": 0,
  "approach_nack": 0
 },
 "reviews": {
  "approved": 0,
  "changes_requested": 0,
  "distinct_reviewers": [
   "AndreaDiazCorreia",
   "pinheadmz"
  ]
 },
 "signals": {
  "needs_rebase": false,
  "ci_failed": false,
  "mergeable_state": "clean",
  "last_author_activity": "2026-11-01T18:41:36Z",
  "last_reviewer_activity": "2026-10-26T20:05:20Z",
  "last_reviewer": "pinheadmz",
  "author_silent_days": 0,
  "waiting_on_author_days": 0,
  "days_since_update": 0
 },
 "refs": {
  "mentioned": [
   27101
  ],
  "depends_on": [],
  "fixes": [],
  "linked_issues": [],
  "references": [
   {
    "number": 27101,
    "type": "pull",
    "state": "closed",
    "merged": true,
    "merged_at": "2024-05-16",
    "title": "Support JSON-RPC 2.0 when requested by client"
   }
  ],
  "conflicts": []
 },
 "stack": {
  "shares_commits_with": [],
  "based_on": [],
  "base_for": []
 },
 "review_paths": [
  "src/rpc/request.cpp",
  "test/functional/interface_rpc.py"
 ],
 "body": "In a JSON-RPC batch, an element that is not an object gets an error reply with the id and version of the element before it.\n\n`ExecuteHTTPRPC` uses one request object for the whole batch. `parse()` throws on a non-object before it resets `id` and `m_json_version`. For `[{\"jsonrpc\":\"2.0\",\"method\":\"getblockcount\",\"id\":\"X\"}, 2]` the reply has two objects with `\"id\":\"X\"`, one with a result and one with an error. If the first element is a notification, the error is dropped. I reset both fields at the top of `parse()`, so the error is the one the first element of a batch already gets. The new case in `interface_rpc.py` fails on master and passes with this change.",
 "commits": [
  {
   "sha": "2ab7c47f6036cec706e6a0df58905aa3eeb1d843",
   "date": "2026-11-01T05:59:34Z",
   "message": "rpc: reset id and version per batch element\n\nIn a JSON-RPC batch, an element that is not an object gets an error\nreply with the id and version of the element before it. A client that\nmatches replies by id can take that error for the result of the\nprevious call. If the previous element was a 2.0 notification, the\nerror is dropped.\n\nI reset both at the start of JSONRPCRequest::parse(). The functional\ntest covers the two cases."
  }
 ],
 "timeline": [
  {
   "t": "2026-10-26T02:05:40Z",
   "kind": "review",
   "who": "AndreaDiazCorreia",
   "assoc": "NONE",
   "state": "COMMENTED",
   "commit": "0811092e117f08ac9ad0e608f796cd8ac014abd0",
   "text": "ACK 0811092e117f08ac9ad0e608f796cd8ac014abd0\n\nReviewed and tested, looks good to me.\n\nSmall nit: the existing m_json_version reset before the jsonrpc check is now redundant and could be removed.",
   "id": "r:5646637313",
   "url": "https://github.com/bitcoin/bitcoin/pull/36642#pullrequestreview-5646637313",
   "hash": "2423bef2e468ea14",
   "edited": null
  },
  {
   "t": "2026-10-26T20:01:01Z",
   "kind": "review_comment",
   "who": "pinheadmz",
   "assoc": "MEMBER",
   "path": "src/rpc/request.cpp",
   "commit": "2ab7c47f6036cec706e6a0df58905aa3eeb1d843",
   "in_reply_to": null,
   "text": "remove the copy of this statement on line 221?",
   "id": "rc:4381855545",
   "url": "https://github.com/bitcoin/bitcoin/pull/36642#discussion_r4381855545",
   "hash": "6b92d4ca78704fe4",
   "edited": "2026-10-26T20:05:20Z"
  },
  {
   "t": "2026-10-26T20:03:37Z",
   "kind": "review_comment",
   "who": "pinheadmz",
   "assoc": "MEMBER",
   "path": "test/functional/interface_rpc.py",
   "commit": "0811092e117f08ac9ad0e608f796cd8ac014abd0",
   "in_reply_to": null,
   "text": "this is a little confusing to read, here and below. what if you just assert the response to the valid request is correct and the second response exists, and doesn't have the same id?",
   "id": "rc:4381879933",
   "url": "https://github.com/bitcoin/bitcoin/pull/36642#discussion_r4381879933",
   "hash": "5d11e1e1054091c1",
   "edited": "2026-10-26T20:05:20Z"
  },
  {
   "t": "2026-10-26T20:05:20Z",
   "kind": "review",
   "who": "pinheadmz",
   "assoc": "MEMBER",
   "state": "COMMENTED",
   "commit": "0811092e117f08ac9ad0e608f796cd8ac014abd0",
   "text": "concept ACK\n\nThis is a reasonable follow up to #27101 and fixes something we missed from the jsonrpc 2.0 spec that could confuse consumers of the interface expecting unique IDs in batch responses.",
   "id": "r:5658199014",
   "url": "https://github.com/bitcoin/bitcoin/pull/36642#pullrequestreview-5658199014",
   "hash": "a94a6fc603e8cb8a",
   "edited": null
  },
  {
   "t": "2026-11-01T18:29:58Z",
   "kind": "force_push",
   "who": "fametrano",
   "commit": "2ab7c47f6036cec706e6a0df58905aa3eeb1d843",
   "id": "push:2ab7c47f6036cec706e6a0df58905aa3eeb1d843"
  },
  {
   "t": "2026-11-01T18:41:36Z",
   "kind": "comment",
   "who": "fametrano",
   "assoc": "NONE",
   "text": "Done: I removed the second `m_json_version` reset and simplified the test's asserts. The batch case now checks the valid reply, then that the error reply has another id and no `jsonrpc` field, which fails if the version reset stays where it was; the notification case checks that the error reply is there.\n\n@AndreaDiazCorreia, the removed reset is the one from your nit; would you mind taking another look at 2ab7c47f60?",
   "id": "c:6562230978",
   "url": "https://github.com/bitcoin/bitcoin/pull/36642#issuecomment-6562230978",
   "hash": "28f6f872b3440805",
   "edited": null
  }
 ],
 "labels_log": [
  {
   "t": "2026-10-24T06:50:04Z",
   "action": "labeled",
   "label": "RPC/REST/ZMQ",
   "who": "DrahtBot"
  }
 ],
 "state_log": [],
 "text_chars": 2180,
 "text_tokens_estimate": 545,
 "changed_paths": [
  "src/rpc/request.cpp",
  "test/functional/interface_rpc.py"
 ],
 "files": [
  {
   "path": "src/rpc/request.cpp",
   "add": 5,
   "del": 0
  },
  {
   "path": "test/functional/interface_rpc.py",
   "add": 14,
   "del": 0
  }
 ],
 "test_lines": 14,
 "git": {
  "head": "0811092e117f08ac9ad0e608f796cd8ac014abd0",
  "head_matches_backup": true,
  "base": "a773e1e33b349dc819b5a0edc1c7a4839dc73b48",
  "patch_id": "96743e4790dd2ad8",
  "commits": [
   {
    "sha": "0811092e11",
    "subject": "rpc: reset id and version per batch element",
    "files": 2,
    "add": 19,
    "del": 0
   }
  ],
  "patch_truncated": false
 },
 "patch_id": "96743e4790dd2ad8",
 "input_hash": "d87615f073d58e90",
 "extracted_at": "2026-11-02T01:09:49+00:00"
}