{
 "number": 33922,
 "repo": "bitcoin/bitcoin",
 "url": "https://github.com/bitcoin/bitcoin/pull/33922",
 "title": "mining: add getMemoryLoad() and track template non-mempool memory footprint",
 "author": "Sjors",
 "author_association": "MEMBER",
 "created_at": "2025-11-21T15:34:14Z",
 "updated_at": "2026-09-17T08:02:32Z",
 "age_days": 300,
 "draft": true,
 "labels": [
  "Mining"
 ],
 "milestone": null,
 "base": "master",
 "head_sha": "1647b291ccae0c0c5c79f0117adcbb0d73231221",
 "head_ref": "2025/11/ipc-memusage",
 "head_repo": "Sjors/bitcoin",
 "head_history": [
  {
   "t": "2025-11-21T16:04:54Z",
   "sha": "f22413f31f32b6985b0090d10ab5d62ba91595cb"
  },
  {
   "t": "2025-11-21T16:22:21Z",
   "sha": "3b77529f74b76ea52c1b7b4ac4edacb0947ff202"
  },
  {
   "t": "2025-11-25T15:47:05Z",
   "sha": "24592b737fb80f07276a88fbcf8eaf0ee64c7e49"
  },
  {
   "t": "2025-11-25T17:21:57Z",
   "sha": "03dcfaeb5892fa877eaae0fe6d6942943b7d9b95"
  },
  {
   "t": "2025-11-25T18:13:13Z",
   "sha": "ac1e97a59279b2407e5f64bd684170587bae88dc"
  },
  {
   "t": "2025-12-03T09:36:11Z",
   "sha": "e8f8f7f677bcde0179526be3ed9a657c44998b93"
  },
  {
   "t": "2025-12-05T11:09:09Z",
   "sha": "e75406dccc39b1f5d988994083e7fd959fa2a49a"
  },
  {
   "t": "2025-12-05T11:13:53Z",
   "sha": "9a03d3837f2532619f8249e4a062453b333c0692"
  },
  {
   "t": "2025-12-05T11:18:27Z",
   "sha": "7f4249b0d0a126cfaddba48bc1bd4966c14fbd0d"
  },
  {
   "t": "2025-12-19T10:24:15Z",
   "sha": "71795a21e6ec854f2f450ce04cc6ff9e108a2c89"
  },
  {
   "t": "2026-01-14T09:54:27Z",
   "sha": "6fb639a089d83a2e4e4eeca26f3041d2da15d0c7"
  },
  {
   "t": "2026-02-03T13:32:38Z",
   "sha": "c518fdf2dec42b6e52eff172816a097738389d16"
  },
  {
   "t": "2026-02-19T11:04:55Z",
   "sha": "6cfd0f29e544c85c175a4ea6bf9db64fe57cdc05"
  },
  {
   "t": "2026-02-23T10:51:15Z",
   "sha": "2ba0f0ba36a23665c23e190b60282dade1108bbf"
  },
  {
   "t": "2026-02-24T12:17:03Z",
   "sha": "c37d715c1d32020fe16ddc92f7ca95f585cc6b4b"
  },
  {
   "t": "2026-03-05T19:58:25Z",
   "sha": "04553cd6612f08d757fb20287fe111007bfb6db1"
  },
  {
   "t": "2026-04-08T09:28:48Z",
   "sha": "430990c0c5bc72f8b64e76056b304b88821b9af0"
  },
  {
   "t": "2026-04-08T09:36:05Z",
   "sha": "10acf818ed70d4cd2af864278a35a6b64de0bb16"
  },
  {
   "t": "2026-04-14T14:56:16Z",
   "sha": "d1b9df5805b9219217b7b22eedaf1fcb5704e35d"
  },
  {
   "t": "2026-04-14T18:24:33Z",
   "sha": "cd1fce108dca9c02abf76cbeb009ed6c2cfa8cc9"
  },
  {
   "t": "2026-04-14T18:39:33Z",
   "sha": "e8aaada3f2f8396b47eda9fad576ab89dbdf80ab"
  },
  {
   "t": "2026-04-17T13:01:06Z",
   "sha": "bf49247b35f43ed9bcb769ea0f9a8eba2ce082d5"
  },
  {
   "t": "2026-04-17T13:02:18Z",
   "sha": "4673836a656a2638292fd02453e5d8ef42cd8eab"
  },
  {
   "t": "2026-04-17T13:10:21Z",
   "sha": "5094af74bc5280b89835654ff7a7604d57a31d8c"
  },
  {
   "t": "2026-04-17T13:21:17Z",
   "sha": "ceb5b70a53c43fd31dbaaaf5737e6550c2fe51e6"
  },
  {
   "t": "2026-04-17T13:29:41Z",
   "sha": "e23a8f3015d8b3c682c45adb3cb39db912f7d1a9"
  },
  {
   "t": "2026-04-17T14:42:01Z",
   "sha": "79a74da860a557af73788f277306a4aee67bc50a"
  },
  {
   "t": "2026-04-17T15:26:55Z",
   "sha": "b89942d29f1e71429070b2d1140d2792eb33bf47"
  },
  {
   "t": "2026-04-17T19:49:18Z",
   "sha": "d37e0fc16c235ff511bd9485ef505f0c5615d9e4"
  },
  {
   "t": "2026-05-22T07:40:04Z",
   "sha": "9f353d56735293677c1db92e639ef034c615eedd"
  },
  {
   "t": "2026-05-26T16:03:27Z",
   "sha": "39254e9edf50781fffa613966f886809595aa998"
  },
  {
   "t": "2026-05-28T17:58:47Z",
   "sha": "c82ccf896759b0d89a953dfb0c66fda176f22afc"
  },
  {
   "t": "2026-06-24T09:45:43Z",
   "sha": "3cb6c4779e20f183347c3c1d63d8abb9d2e4c4ee"
  },
  {
   "t": "2026-06-24T19:37:28Z",
   "sha": "8b4967e3570a7adce2e73c3476bcdd5d676cf090"
  },
  {
   "t": "2026-07-08T07:58:27Z",
   "sha": "837060b034e65ceabed52e35f9e4bcc276a4bafb"
  },
  {
   "t": "2026-07-08T10:19:38Z",
   "sha": "d1f9b11b40661bb49d19333e9fcc43d5a969eb3f"
  },
  {
   "t": "2026-07-16T13:55:00Z",
   "sha": "ef901fa30831b99ca1892bf7949e7bd92a42460b"
  },
  {
   "t": "2026-07-16T15:14:19Z",
   "sha": "239af38f706835a5a5ca10176a4bcda45196d919"
  },
  {
   "t": "2026-07-23T17:37:26Z",
   "sha": "794a8a04dd6bfeac3553a71c24f21be9d0afa38b"
  },
  {
   "t": "2026-07-23T18:04:26Z",
   "sha": "1f569895ea25814e46ba53f94efa618c7bc9eacc"
  },
  {
   "t": "2026-07-24T13:25:55Z",
   "sha": "de2c7a8f975f0309bb7eb9c86675ce825342cf4f"
  },
  {
   "t": "2026-08-20T09:23:04Z",
   "sha": "c10e77f9897ed74ca9f3cf3085cd1eabb956fbe3"
  },
  {
   "t": "2026-09-09T07:44:37Z",
   "sha": "4259dde8f195b71e0282bb8f82d5009107945aa2"
  },
  {
   "t": "2026-09-14T09:56:27Z",
   "sha": "11739697d0b6d8015c2746dd3d42866a694bcae3"
  },
  {
   "t": "2026-09-14T12:47:55Z",
   "sha": "1647b291ccae0c0c5c79f0117adcbb0d73231221"
  }
 ],
 "additions": 1087,
 "deletions": 463,
 "changed_files": 34,
 "commit_count": 19,
 "size_bucket": "XL",
 "mergeable_state": "clean",
 "bot": {
  "drahtbot": {
   "present": true,
   "reviews": {
    "concept_ack": [
     {
      "login": "ismaelsadeeq",
      "url": "https://github.com/bitcoin/bitcoin/pull/33922#pullrequestreview-3493499544"
     },
     {
      "login": "ryanofsky",
      "url": "https://github.com/bitcoin/bitcoin/pull/33922#issuecomment-3608940825"
     }
    ],
    "stale_ack": [
     {
      "login": "enirox001",
      "url": "https://github.com/bitcoin/bitcoin/pull/33922#pullrequestreview-4061578431"
     },
     {
      "login": "vasild",
      "url": "https://github.com/bitcoin/bitcoin/pull/33922#pullrequestreview-4179948443"
     }
    ]
   },
   "conflicts": [
    {
     "number": 36257,
     "title": "qa: assert_equals -> assert_true/assert_false",
     "author": "hodlinator"
    },
    {
     "number": 36244,
     "title": "validation, net: Process blocks asynchronously and reduce cs_main contention",
     "author": "w0xlt"
    },
    {
     "number": 36188,
     "title": "crypto: plug hardware optimized SHA256 into libsecp256k1's context",
     "author": "furszy"
    },
    {
     "number": 36109,
     "title": "test: harden arbitrary-parent block creation",
     "author": "l0rinc"
    },
    {
     "number": 36097,
     "title": "mining: replace interrupt methods with cancellation arguments",
     "author": "xyzconstant"
    },
    {
     "number": 36047,
     "title": "rpc: handle createNewBlock() returning nullptr during shutdown",
     "author": "chriszeng1010"
    },
    {
     "number": 36000,
     "title": "validation: prefetch blocks while connecting",
     "author": "l0rinc"
    },
    {
     "number": 35671,
     "title": "mining: add TxCollection to bandwidth-efficiently validate external block templates",
     "author": "Sjors"
    },
    {
     "number": 35646,
     "title": "RFC: Separate out runtime errors from BlockValidationState using `util::Expected`",
     "author": "yuvicc"
    },
    {
     "number": 35581,
     "title": "node: add block template manager and track waitNext fee inflow",
     "author": "ismaelsadeeq"
    },
    {
     "number": 35569,
     "title": "Encapsulation for CTransaction",
     "author": "purpleKarrot"
    },
    {
     "number": 35511,
     "title": "RFC: consensus: Make `CAmount` a class",
     "author": "hodlinator"
    },
    {
     "number": 32468,
     "title": "rpc: generateblock to allow multiple outputs",
     "author": "polespinasa"
    },
    {
     "number": 31117,
     "title": "miner: Reorg Testnet4 minimum difficulty blocks",
     "author": "fjahr"
    },
    {
     "number": 29700,
     "title": "kernel, refactor: return error status on all fatal errors",
     "author": "ryanofsky"
    }
   ]
  }
 },
 "acks_parsed": {
  "ismaelsadeeq": {
   "kind": "concept_ack",
   "hash": null,
   "t": "2025-11-21T16:22:59Z",
   "stale": false
  },
  "ryanofsky": {
   "kind": "concept_ack",
   "hash": "e8f8f7f677bcde0179526be3ed9a657c44998b93",
   "t": "2025-12-03T21:36:31Z",
   "stale": false
  },
  "vasild": {
   "kind": "ack",
   "hash": "d37e0fc16c235ff511bd9485ef505f0c5615d9e4",
   "t": "2026-04-27T10:04:18Z",
   "stale": true
  },
  "enirox001": {
   "kind": "ack",
   "hash": "04553cd",
   "t": "2026-04-06T10:52:35Z",
   "stale": true
  }
 },
 "acks_tally": {
  "ack": 0,
  "stale_ack": 2,
  "concept_ack": 2,
  "approach_ack": 0,
  "nack": 0,
  "concept_nack": 0,
  "approach_nack": 0
 },
 "reviews": {
  "approved": 4,
  "changes_requested": 0,
  "distinct_reviewers": [
   "brunoerg",
   "enirox001",
   "hebasto",
   "ismaelsadeeq",
   "maflcko",
   "ryanofsky",
   "vasild"
  ]
 },
 "signals": {
  "needs_rebase": false,
  "ci_failed": false,
  "mergeable_state": "clean",
  "last_author_activity": "2026-09-14T12:47:55Z",
  "last_reviewer_activity": "2026-04-27T10:04:18Z",
  "last_reviewer": "vasild",
  "author_silent_days": 3,
  "waiting_on_author_days": 0,
  "days_since_update": 0
 },
 "refs": {
  "mentioned": [
   33421,
   33819,
   33899,
   33965,
   33966,
   34003,
   34020,
   34184,
   34422,
   34452,
   34568,
   34644,
   34646,
   34806,
   34896,
   35073,
   35101,
   35403,
   35581,
   35598,
   35675
  ],
  "depends_on": [],
  "fixes": [],
  "linked_issues": [],
  "references": [
   {
    "number": 33899,
    "type": "issue",
    "state": "open",
    "merged": false,
    "merged_at": null,
    "title": "Block template memory management (for IPC clients)"
   },
   {
    "number": 35675,
    "type": "pull",
    "state": "open",
    "merged": false,
    "merged_at": null,
    "title": "mining: add block template manager"
   },
   {
    "number": 33421,
    "type": "pull",
    "state": "closed",
    "merged": false,
    "merged_at": null,
    "title": "node: add  `BlockTemplateCache`"
   },
   {
    "number": 33819,
    "type": "pull",
    "state": "closed",
    "merged": true,
    "merged_at": "2026-01-13",
    "title": "mining: getCoinbase() returns struct instead of raw tx"
   },
   {
    "number": 33965,
    "type": "pull",
    "state": "closed",
    "merged": true,
    "merged_at": "2026-02-12",
    "title": "mining: fix -blockreservedweight shadows IPC option"
   },
   {
    "number": 33966,
    "type": "pull",
    "state": "closed",
    "merged": true,
    "merged_at": "2026-05-26",
    "title": "refactor: disentangle miner startup defaults from runtime options"
   },
   {
    "number": 34003,
    "type": "pull",
    "state": "closed",
    "merged": true,
    "merged_at": "2025-12-16",
    "title": "test: interface_ipc.py minor fixes and cleanup"
   },
   {
    "number": 34020,
    "type": "pull",
    "state": "closed",
    "merged": true,
    "merged_at": "2026-07-07",
    "title": "mining: add getTransactions(ByWitnessID) IPC methods"
   },
   {
    "number": 34184,
    "type": "pull",
    "state": "closed",
    "merged": true,
    "merged_at": "2026-02-24",
    "title": "mining: add cooldown to createNewBlock() immediately after IBD"
   },
   {
    "number": 34422,
    "type": "pull",
    "state": "closed",
    "merged": true,
    "merged_at": "2026-03-03",
    "title": "Update libmultiprocess subtree to be more stable with rust IPC client"
   },
   {
    "number": 34452,
    "type": "pull",
    "state": "closed",
    "merged": true,
    "merged_at": "2026-02-07",
    "title": "test: split interface_ipc.py"
   },
   {
    "number": 34568,
    "type": "pull",
    "state": "closed",
    "merged": true,
    "merged_at": "2026-02-20",
    "title": "mining: Break compatibility with existing IPC mining clients"
   },
   {
    "number": 34644,
    "type": "pull",
    "state": "closed",
    "merged": true,
    "merged_at": "2026-05-28",
    "title": "mining: add submitBlock to IPC Mining interface"
   },
   {
    "number": 34646,
    "type": "pull",
    "state": "closed",
    "merged": true,
    "merged_at": "2026-02-23",
    "title": "Fix two issues in p2p_private_broadcast.py"
   },
   {
    "number": 34806,
    "type": "pull",
    "state": "closed",
    "merged": true,
    "merged_at": "2026-05-22",
    "title": "refactor: logging: Various API improvements"
   },
   {
    "number": 34896,
    "type": "pull",
    "state": "closed",
    "merged": true,
    "merged_at": "2026-03-25",
    "title": "ci: Upgrade IWYU to 0.26 compatible with Clang 22"
   },
   {
    "number": 35073,
    "type": "pull",
    "state": "closed",
    "merged": false,
    "merged_at": null,
    "title": "iwyu: map std::hash to <functional>"
   },
   {
    "number": 35101,
    "type": "pull",
    "state": "closed",
    "merged": true,
    "merged_at": "2026-06-10",
    "title": "refactor: disable default std::hash for CTransactionRef"
   },
   {
    "number": 35403,
    "type": "pull",
    "state": "closed",
    "merged": true,
    "merged_at": "2026-06-23",
    "title": "mining: pr 33966 followups (disentangle miner startup defaults)"
   },
   {
    "number": 35581,
    "type": "pull",
    "state": "open",
    "merged": false,
    "merged_at": null,
    "title": "node: add block template manager and track waitNext fee inflow"
   },
   {
    "number": 35598,
    "type": "pull",
    "state": "open",
    "merged": false,
    "merged_at": null,
    "title": "test: cover feeThreshold = MAX_MONEY in interface_ipc_mining.py"
   }
  ],
  "conflicts": [
   36257,
   36244,
   36188,
   36109,
   36097,
   36047,
   36000,
   35671,
   35646,
   35581,
   35569,
   35511,
   32468,
   31117,
   29700
  ]
 },
 "stack": {
  "shares_commits_with": [
   35581,
   35675
  ],
  "based_on": [
   35675
  ],
  "base_for": []
 },
 "review_paths": [
  "src/node/context.h",
  "src/node/interfaces.cpp",
  "src/node/miner.h",
  "src/node/types.h",
  "src/primitives/transaction.h",
  "src/rpc/mining.cpp",
  "test/functional/interface_ipc.py"
 ],
 "body": "Implements a way to track the memory footprint of all non-mempool transactions that are still being referenced by block templates, see discussion in  #33899. It does not impose a limit.\n\nIPC clients can query this footprint (total, across all clients) using the `getMemoryLoad()` IPC method. Its client-side usage is demonstrated here:\n- https://github.com/stratum-mining/sv2-tp/pull/63\n\nAdditionally, the functional test in `interface_ipc.py` is expanded to demonstrate how template memory management works: templates are not released until the client drops references to them, or calls the template destroy method, or disconnects. The destroy method is called automatically by clients using [libmultiprocess](https://github.com/bitcoin-core/libmultiprocess), as [sv2-tp](https://github.com/stratum-mining/sv2-tp) does. In the Python tests it also happens when references are destroyed or go out of scope.\n\nBased on:\n\n- #35675\n\nCommits:\n\n- _refactor: move CTransactionRefComp to util/hasher_\n- _mining: track non-mempool memory usage_: add `TxTemplateMap` to `BlockTemplateManager` to track how many templates contain any given transaction. This map is updated by the `BlockTemplate` constructor and destructor.\n- _mining: add GetTemplateMemoryUsage()_ - loops over this map and sums up the memory footprint for transactions outside the mempool (includes a fuzzer)\n- _ipc: add getMemoryLoad()_ expose this information to IPC clients and add test coverage",
 "commits": [
  {
   "sha": "482a5d27124c4241c27ed323659914cd38409650",
   "date": "2026-09-13T10:33:47Z",
   "message": "node: introduce BlockTemplateManager\n\nAdd BlockTemplateManager, a wrapper around\nBlockAssembler::CreateNewBlock(), and store it in NodeContext.\n\nWire it into node init and test setup so it is reset before its\nmempool/chainman dependencies, and update tests and fuzz setups that\nrebuild chainman or mempool. Add a unit test that verifies a block\ntemplate can be created through the manager."
  },
  {
   "sha": "bcdadf2b7111a061d2bbeba350233db7b258a787",
   "date": "2026-09-13T11:28:23Z",
   "message": "node: move mining_args to BlockTemplateManager\n\nPass the parsed mining args to BlockTemplateManager at construction\nand expose them via BlockCreateArgs(), so the manager owns the\ninit-time block create options instead of NodeContext."
  },
  {
   "sha": "07964c525d4769d00004b9942225a2cb1306e09d",
   "date": "2026-09-13T11:28:23Z",
   "message": "miner: move SubmitBlock into BlockTemplateManager\n\nMove SubmitBlockStateCatcher and SubmitBlock from miner.cpp into\nBlockTemplateManager as a member function. This groups block submission\nwith block creation in the same class. The function uses m_chainman\ndirectly instead of taking it as a parameter."
  },
  {
   "sha": "037d3519f2ff9937aa82060a42939aafab4179f1",
   "date": "2026-09-13T11:28:25Z",
   "message": "node: move tip and wait helpers into BlockTemplateManager\n\nMove the mining tip lookup and block-template waiting helpers (GetTip,\nWaitTipChanged, WaitAndCreateNewBlock, InterruptWait,\nCooldownIfHeadersAhead) into BlockTemplateManager so the manager owns\nthe template waiting flow. The manager now takes KernelNotifications\nat construction."
  },
  {
   "sha": "400ac328c91b653e793bd140b89e8fabfb42e3ac",
   "date": "2026-09-13T11:28:26Z",
   "message": "interfaces: create block template via BlockTemplateManager\n\nRoute the Mining interface's createNewBlock() through\nBlockTemplateManager::CreateNewTemplate() instead of constructing a\nBlockAssembler directly. Merging the init-time defaults into unset\noptions now happens inside CreateNewTemplate(), so every caller gets\nthem applied."
  },
  {
   "sha": "011cbfbcd2e3a3282ae7e5afdfd923bc444d1845",
   "date": "2026-09-13T11:28:27Z",
   "message": "rpc: route getblocktemplate internals through node\n\nAdd EnsureBlockTemplateManager() and use it in getblocktemplate for tip\nlookup and longpoll waiting, while using ChainstateManager directly for\ntest-chain and IBD checks."
  },
  {
   "sha": "0998c0bbdfcc3c3f7c105a1fb7223bace529556a",
   "date": "2026-09-13T11:28:28Z",
   "message": "rpc: build getblocktemplate via BlockTemplateManager"
  },
  {
   "sha": "951fac807d37302e7de5e289c0ab05f8dfcb1e1c",
   "date": "2026-09-13T11:28:29Z",
   "message": "rpc: do not copy template data in getblocktemplate\n\nThe transactions, fees and sigops costs, and the coinbase outputs\nare only read, so reference them from the template instead of copying\nthem out of it."
  },
  {
   "sha": "38556f817e060187b48cd31490f578cdf63134ee",
   "date": "2026-09-13T11:28:29Z",
   "message": "rpc: only copy the header in getblocktemplate\n\nThe block copy exists solely to apply header adjustments (time, nonce,\nversion bits) that must not mutate the cached template. Now that the\ntransactions are read directly from the template, copy only the header\ninstead of the entire block."
  },
  {
   "sha": "8372721f20e2ea2c15bae38a046476736169d801",
   "date": "2026-09-13T11:28:30Z",
   "message": "rpc: build generation templates via BlockTemplateManager\n\ngenerateblock is no longer safe for fuzzing: it previously threw at\nEnsureMining (node.mining is never set in the fuzz setup), but with\nEnsureBlockTemplateManager it now executes, mining and submitting a\nreal block. Submission mutates the chain state shared across fuzz\niterations and writes the block to disk."
  },
  {
   "sha": "ec4f24ef181a7987bcea72a21e507f59dc1b8126",
   "date": "2026-09-13T11:28:31Z",
   "message": "rpc: wait for tips via BlockTemplateManager\n\nThe waitforblock, waitforblockheight and waitfornewblock RPCs are no\nlonger safe for fuzzing: they previously threw at EnsureMining\n(node.mining is never set in the fuzz setup), but with\nEnsureBlockTemplateManager they now really wait. The tip never changes\nduring fuzzing and nothing interrupts the wait, so a call without a\ntimeout blocks forever."
  },
  {
   "sha": "6c71166bcfa4339d5019f2b27d477eb45ce7fe86",
   "date": "2026-09-13T11:28:32Z",
   "message": "test: create templates via BlockTemplateManager"
  },
  {
   "sha": "ffe3a631f38b1224db8b0ea246a3c976f358c59e",
   "date": "2026-09-13T11:28:33Z",
   "message": "node: remove NodeContext::mining and EnsureMining"
  },
  {
   "sha": "3d7d190b6995b3c0adb6528c2d9eac81a8f839d9",
   "date": "2026-09-13T11:28:34Z",
   "message": "ci: enforce iwyu for block template manager"
  },
  {
   "sha": "e8b283c35a656f808250e4b32d3494f49a000b08",
   "date": "2026-09-13T11:28:35Z",
   "message": "test: fuzz BlockTemplateManager"
  },
  {
   "sha": "f9d9aac99a40dce53cce243d1652d76e646a92ef",
   "date": "2026-09-14T12:44:19Z",
   "message": "refactor: move CTransactionRefComp to util/hasher"
  },
  {
   "sha": "4b10fc327fd1e1c1c397bc5a8f07b54bd7e61193",
   "date": "2026-09-14T12:44:19Z",
   "message": "mining: track non-mempool memory usage\n\nIPC clients can hold on to block templates indefinately, which has the\nsame impact as when the node holds a shared pointer to the\nCBlockTemplate. Because each template in turn tracks CTransactionRefs,\ntransactions that are removed from the mempool will not have\ntheir memory cleared.\n\nThis commit adds bookkeeping to the block template constructor and\ndestructor that will let us track the resulting memory footprint.\n\nCo-authored-by: Vasil Dimov <vd@FreeBSD.org>"
  },
  {
   "sha": "063ae8400ac71c190c1328f19afa7c3eff789df5",
   "date": "2026-09-14T12:44:46Z",
   "message": "mining: add GetTemplateMemoryUsage()\n\nCalculate the non-mempool memory footprint for template transaction\nreferences.\n\nAdd bench logging to collect data on whether caching or simplified\nheuristics are needed, such as not checking for mempool presence.\n\nCheck the calculation in the block template manager fuzz test."
  },
  {
   "sha": "1647b291ccae0c0c5c79f0117adcbb0d73231221",
   "date": "2026-09-14T12:44:47Z",
   "message": "ipc: add getMemoryLoad()\n\nAllow IPC clients to inspect the amount of memory consumed by\nnon-mempool transactions in blocks.\n\nReturns a MemoryLoad struct which can later be expanded to e.g.\ninclude a limit.\n\nExpand the interface_ipc.py test to demonstrate the behavior and\nto illustrate how clients can call destroy() to reduce memory\npressure."
  }
 ],
 "timeline": [
  {
   "t": "2025-11-21T15:36:54Z",
   "kind": "comment",
   "who": "Sjors",
   "assoc": "MEMBER",
   "text": "I haven't benchmarked this yet on mainnet, so I'm not sure if checking every (unique) transaction for mempool presence is unacceptably expensive.\n\nIf people prefer, I could also add a way for the `getblocktemplate` RPC to opt-out of the memory bookkeeping, since it holds on to one template max and no longer than a minute."
  },
  {
   "t": "2025-11-21T16:04:54Z",
   "kind": "force_push",
   "who": "Sjors",
   "commit": "f22413f31f32b6985b0090d10ab5d62ba91595cb"
  },
  {
   "t": "2025-11-21T16:17:32Z",
   "kind": "review_comment",
   "who": "Sjors",
   "assoc": "MEMBER",
   "path": "src/node/interfaces.cpp",
   "commit": "8b4967e3570a7adce2e73c3476bcdd5d676cf090",
   "in_reply_to": null,
   "text": "b9306b79b8f5667a2679236af8792bb1c36db817: in addition, we might be wiping the dummy coinbase from the template later: https://github.com/Sjors/bitcoin/pull/106"
  },
  {
   "t": "2025-11-21T16:22:21Z",
   "kind": "force_push",
   "who": "Sjors",
   "commit": "3b77529f74b76ea52c1b7b4ac4edacb0947ff202"
  },
  {
   "t": "2025-11-21T16:22:59Z",
   "kind": "review",
   "who": "ismaelsadeeq",
   "assoc": "MEMBER",
   "state": "COMMENTED",
   "commit": "3b77529f74b76ea52c1b7b4ac4edacb0947ff202",
   "text": "Concept ACK\n\nI think it would be better if we have internal memory management for the mining interface IPC, since we hold on to the block templates.\n\nI would suggest the following approach:\n\n- Add memory budget for the mining interface.\n- Introduce a tracking list of recently built block templates and total memory usage.\n- Add templates to the list and increment the memory usage after every `createnewblock` or `waitnext` return.\n- Whenever the memory budget is exhausted, we should release templates in FIFO order.\n\nI think since we create a new template after a time interval elapses even if fees increase and that interval is usually enough for the client to receive and distribute the template to miners, this mechanism should be safe as the miners have long switch to most recent template when the budget elapsed because of the time interval being used in between returns of waitnext.\n\nMining interface clients should also handle their own memory internally.\n\nCurrently, I don\u2019t see much use for the exposed `getMemoryLoad` method. In my opinion, we should not rely on the IPC client to manage our memory."
  },
  {
   "t": "2025-11-21T16:34:13Z",
   "kind": "comment",
   "who": "Sjors",
   "assoc": "MEMBER",
   "text": "[quoted text omitted]\n\n[quoted text omitted]\nIt seems counter intuitive, but from a memory management perspective IPC clients are treated no different than our own code. And if we started FIFO deleting templates that are used by our own code, we'd crash.\n\nSo I think FIFO deletion should be a last resort (not implemented here).\n\nThere's another reason why we should give clients an opportunity to gracefully release templates in whatever order they prefer. Maybe there's 100 downstream ASIC's, one of which is very slow at loading templates, so it's only given a new template when the tip changes, not when there's a fee change. In that scenario you have a specific template that the client wants to \"defend\" at all cost.\n\nIn practice I'm hoping none of this matters and we can pick and recommend defaults that make it unlikely to get close to a memory limit, other than during some weird token launch."
  },
  {
   "t": "2025-11-21T17:38:04Z",
   "kind": "comment",
   "who": "ismaelsadeeq",
   "assoc": "MEMBER",
   "text": "[quoted text omitted]\n\nIMHO I think we should separate that, and treat clients differently from our own code, because they are different codebases and separate applications with their own memory.\n\n[quoted text omitted]\nI see your point but I don\u2019t think that\u2019s a realistic scenario, and I think we shouldn\u2019t design software to be one-size-fits-all.\nIf you want to use only single block templates, then use `createnewblock` and create a new block template and mine that continuously until the chain tip changes or you mine a block.\n\n`waitNext` returning indicates that we assume your miners are switching from the block they are currently mining to the new one they receive.\nDepending on the budget (which I assume is large), many templates would need to be returned before we exhaust it.\n\nDelegating template eviction responsibility to the client can put us in a situation where they handle it poorly and cause us to OOM (but I guess your argument is that we rather take that chance than being in a situation where we make miners potentially lose on rewards).\nHowever I think if there is a clean separation of concerns between the Bitcoin Core node and its clients and clear interface definition and expectations that should not happen, and I believe the mining interface should not differ in that respect.\nOtherwise, if we do want a one-size-fits-all solution capable of handling the scenario you described, we should rethink the design entirely and revert to an approach where we do not retain block templates."
  },
  {
   "t": "2025-11-24T10:49:07Z",
   "kind": "comment",
   "who": "Sjors",
   "assoc": "MEMBER",
   "text": "[quoted text omitted]\n\nNote that it's _already_ the clients responsibility, that's inherent to how multiprocess works.\n\nIn the scenario where they handle it poorly, we can use FIFO deletion. All `getMemoryLoad()` does is give clients an opportunity to handle it better. If they're fine with FIFO, then they never have to call this method.\n\n[quoted text omitted]\nWe currently don't track whether any given `CBlockTemplate` is owned by an IPC client or by our internal code. Once we introduce FIFO deletion all call sites will have to check if it's been deleted since, or we need to exempt them from the memory accounting.\n\n[quoted text omitted]\nAfaik that means revalidating the block from scratch, removing one advantage the `submitBlock()` approach has over the `submitblock` RPC (I haven't benchmarked this though)."
  },
  {
   "t": "2025-11-24T16:56:34Z",
   "kind": "comment",
   "who": "Sjors",
   "assoc": "MEMBER",
   "text": "I tracked the non-mempool transaction memory footprint for half a day on mainnet, using fairly aggressive template update criteria (minimum fee delta 1 sat and no more than once per second). So far the footprint is minuscule, but of course this depends on the mempool weather:\n\nThe memory spike after each new block is because `sv2-tp` holds on to templates from previous blocks for 10 seconds. Those ~3 MB spikes may look impressive, but keep in mind that the default mempool is 300 MB."
  },
  {
   "t": "2025-11-25T15:47:05Z",
   "kind": "force_push",
   "who": "Sjors",
   "commit": "24592b737fb80f07276a88fbcf8eaf0ee64c7e49"
  },
  {
   "t": "2025-11-25T15:56:12Z",
   "kind": "comment",
   "who": "Sjors",
   "assoc": "MEMBER",
   "text": "I restructured the implementation and commits a bit.\n\nThe `TxTemplateMap` now lives on the `NodeContext` rather than `MinerImpl` (interface). This reflects the fact that we want to track the global memory footprint instead of per client. It's a lightweight member `template_tx_refs` which should be easy to fold into a block template manager later.\n\nIt's also [less code churn](https://github.com/bitcoin/bitcoin/compare/3b77529f74b76ea52c1b7b4ac4edacb0947ff202..24592b737fb80f07276a88fbcf8eaf0ee64c7e49#diff-0ef8ae12c6e9ef2accc78537f42612b3267e8a7c45dc7e9eb998f797e79f2e95) because I don't have to touch the `BlockTemplateImpl` constructor.\n\nIt also made it easier to move `GetTemplateMemoryUsage` from `interface.cpp` to `miner.cpp`, where it's more reusable.\n\nThis in turn let me split out a separate commit that introduces the actual `getMemoryLoad()` interface method. So even if we decide against including that method, the rest of the PR should be useful. However I do think it's worth keeping, it's already been a helpful debugging and monitoring tool.\n\nI added some comments to point out that we don't hold a `mempool.cs` lock during the calculation because we don't need an accurate result (mempool drift) and we don't want to bog down transaction relay with a potentially long lock (1-3ms in my testing so far)."
  },
  {
   "t": "2025-11-25T17:21:57Z",
   "kind": "force_push",
   "who": "Sjors",
   "commit": "03dcfaeb5892fa877eaae0fe6d6942943b7d9b95"
  },
  {
   "t": "2025-11-25T17:22:05Z",
   "kind": "comment",
   "who": "Sjors",
   "assoc": "MEMBER",
   "text": "`mining_getblocktemplate_longpoll.py` triggered a `stack-use-after-return`, due to `block_template` being `static` (to allow template reuse between RPC calls). I added a commit d752dccaa56b663001d1bb29ab8b9a50628602a9 to move this longpoll template to the node context. This seems more appropriate anyway since `BlockTemplate` has a `m_node` member, so it shouldn't be able to outlive the node.\n\nOne caveat is that `gbt_template` has to be cleared before `template_tx_refs`, so I swapped them and added a comment (cde248a6613b6e37f7f7e35c1aabeb75347ffe95 -> 9c667c362a1639b48113a3657882b751f475082c.\n\n---\n\nExpanded the PR description."
  },
  {
   "t": "2025-11-25T18:13:13Z",
   "kind": "force_push",
   "who": "Sjors",
   "commit": "ac1e97a59279b2407e5f64bd684170587bae88dc"
  },
  {
   "t": "2025-12-02T13:17:51Z",
   "kind": "review_comment",
   "who": "brunoerg",
   "assoc": "MEMBER",
   "path": "src/node/interfaces.cpp",
   "commit": "8b4967e3570a7adce2e73c3476bcdd5d676cf090",
   "in_reply_to": null,
   "text": "Just ran a mutation testing for this PR and this is the only unkilled mutant - feel free to ignore if it doesn't make sense to address:\n\n```diff\ndiff --git a/src/node/interfaces.cpp b/src/node/interfaces.cpp\nindex f734296b24..13ddbb672f 100644\n--- a/src/node/interfaces.cpp\n+++ b/src/node/interfaces.cpp\n@@ -880,7 +880,7 @@ public:\n         for (const CTransactionRef& tx : m_block_template->block.vtx | std::views::drop(1)) {\n             auto ref_count{m_node.template_tx_refs.find(tx)};\n             if (!Assume(ref_count != m_node.template_tx_refs.end())) break;\n-            if (--ref_count->second == 0) {\n+            if (1==1) {\n                 m_node.template_tx_refs.erase(ref_count);\n             }\n         }\n```"
  },
  {
   "t": "2025-12-03T08:19:54Z",
   "kind": "comment",
   "who": "Sjors",
   "assoc": "MEMBER",
   "text": "Here's a slightly more realistic plot from last night on a well connected node running on an Intel i5-8400:\n\nIt's connected to DMND pool, declaring custom templates and getting them approved, but not actually mining. Due to their rate limiting I set `-sv2interval=20`, so if fees go up, it waits at least 20 seconds before generating a new template. It does not wait when the tip changes.\n\nThe machine also runs a lightning node and BTCPay so the moment block comes in the system is quite busy."
  },
  {
   "t": "2025-12-03T09:36:11Z",
   "kind": "force_push",
   "who": "Sjors",
   "commit": "e8f8f7f677bcde0179526be3ed9a657c44998b93"
  },
  {
   "t": "2025-12-03T09:36:17Z",
   "kind": "review_comment",
   "who": "Sjors",
   "assoc": "MEMBER",
   "path": "src/node/interfaces.cpp",
   "commit": "8b4967e3570a7adce2e73c3476bcdd5d676cf090",
   "in_reply_to": 2581145624,
   "text": "@brunoerg that's useful. So far `interface_ipc.py` never had a transaction appear in multiple templates, so the destructor would always remove the last reference.\n\nI adjusted the test so that it does. Now your mutation causes a crash during this test."
  },
  {
   "t": "2025-12-03T21:36:31Z",
   "kind": "comment",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "text": "Concept ACK e8f8f7f677bcde0179526be3ed9a657c44998b93. All the changes here seem good and mostly straightforward. The `getMemoryLoad()` function seems useful by itself and the underlying tracking would seem to provide almost everything needed to limit memory used by block templates.\n\nI am a little concerned about the idea of proactively deleting block templates in FIFO order on behalf of clients, since it seems like this could increase complexity server-side, and client-side if clients have to deal with templates disappearing without being notified. Just not returning new templates after a certain amount of memory has been used would like a simpler approach.\n\nre: https://github.com/bitcoin/bitcoin/pull/33922#issue-3652141565\n\n[quoted text omitted]\nWould be good if this said templates are also released if the python references are destroyed or go out of scope. (This stood out because I tested this yesterday in https://github.com/bitcoin/bitcoin/issues/33940#issuecomment-3604081211.)"
  },
  {
   "t": "2025-12-04T06:06:14Z",
   "kind": "review_comment",
   "who": "brunoerg",
   "assoc": "MEMBER",
   "path": "src/node/interfaces.cpp",
   "commit": "8b4967e3570a7adce2e73c3476bcdd5d676cf090",
   "in_reply_to": 2581145624,
   "text": "Nice, thank you!"
  },
  {
   "t": "2025-12-04T10:46:46Z",
   "kind": "comment",
   "who": "Sjors",
   "assoc": "MEMBER",
   "text": "[quoted text omitted]\n\nIt is, but refusing to make new templates doesn't stop the footprint of existing templates from growing. The worst case extra memory footprint for _existing_ templates is the full size of the mempool.\n\nThis is rather unlikely though, it would only happen if between two blocks the entire mempool was gradually RBF'd in such a way that each transaction was at the top of the mempool briefly, and thus made it into a template.\n\n[quoted text omitted]\nAdded a sentence to the PR description."
  },
  {
   "t": "2025-12-04T17:37:39Z",
   "kind": "review_comment",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "path": "src/rpc/mining.cpp",
   "commit": "c37d715c1d32020fe16ddc92f7ca95f585cc6b4b",
   "in_reply_to": null,
   "text": "In commit \"rpc: move static block_template to node context\" (a5eee29fd7d177f57c78da9773cb656a129de839)\n\nI think it would actually be nice to move all these static variables to a struct or class like @ismaelsadeeq's  BlockTemplateCache from #33421. But this could be a followup, and doesn't need to complicate this PR."
  },
  {
   "t": "2025-12-04T17:55:02Z",
   "kind": "review_comment",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "path": "src/node/context.h",
   "commit": "e8f8f7f677bcde0179526be3ed9a657c44998b93",
   "in_reply_to": null,
   "text": "In commit \"mining: track non-mempool memory usage\" (7c4d03d7b23417612fbca2f22e5bb1a198c9e5a2)\n\nThis map can updated from multiple threads, so it needs a mutex to be used safely. I think I'd suggest combining `template_tx_refs` and `gbt_template` variables and a mutex into single struct called something like `BlockTemplateState` and adding a `unique_ptr` to that struct as a member here. The struct could be replaced with a cache class in #33421."
  },
  {
   "t": "2025-12-04T18:11:07Z",
   "kind": "review_comment",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "path": "test/functional/interface_ipc.py",
   "commit": "7f4249b0d0a126cfaddba48bc1bd4966c14fbd0d",
   "in_reply_to": null,
   "text": "In commit \"ipc: add getMemoryLoad()\" (e8f8f7f677bcde0179526be3ed9a657c44998b93)\n\nSeems ok to assert this log message is logged, but I'm wondering if there was a particular reason for doing this. Was the idea to pair the LOG_TIME_MILLIS_WITH_CATEGORY and assert_debug_log calls together?"
  },
  {
   "t": "2025-12-04T18:23:00Z",
   "kind": "review",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "state": "COMMENTED",
   "commit": "e8f8f7f677bcde0179526be3ed9a657c44998b93",
   "text": "Code review e8f8f7f677bcde0179526be3ed9a657c44998b93. This looks good except for a thread safety issue I think you can address by adding a mutex.\n\nre: https://github.com/bitcoin/bitcoin/pull/33922#issuecomment-3611468373\n\n[quoted text omitted]\nSorry, I should have made a more specific suggestion. The problem is is that this sentence is not accurate: \"templates are not released until the client disconnects or calls the destroy() method.\" Templates will be released if the client drops references to them, even if it never disconnects or calls destroy. I would just change it to \"templates are not released until the client drops references to them, or calls the template destroy method, or disconnects\""
  },
  {
   "t": "2025-12-05T09:26:08Z",
   "kind": "review_comment",
   "who": "Sjors",
   "assoc": "MEMBER",
   "path": "test/functional/interface_ipc.py",
   "commit": "7f4249b0d0a126cfaddba48bc1bd4966c14fbd0d",
   "in_reply_to": 2590089590,
   "text": "This just checks that bench logging happens."
  },
  {
   "t": "2025-12-05T11:09:09Z",
   "kind": "force_push",
   "who": "Sjors",
   "commit": "e75406dccc39b1f5d988994083e7fd959fa2a49a"
  },
  {
   "t": "2025-12-05T11:09:14Z",
   "kind": "review_comment",
   "who": "Sjors",
   "assoc": "MEMBER",
   "path": "src/node/context.h",
   "commit": "e8f8f7f677bcde0179526be3ed9a657c44998b93",
   "in_reply_to": 2590041765,
   "text": "To limit the scope of this PR, I only added the mutex, but called it `template_state_mutex` in anticipation."
  },
  {
   "t": "2025-12-05T11:13:53Z",
   "kind": "force_push",
   "who": "Sjors",
   "commit": "9a03d3837f2532619f8249e4a062453b333c0692"
  },
  {
   "t": "2025-12-05T11:18:27Z",
   "kind": "force_push",
   "who": "Sjors",
   "commit": "7f4249b0d0a126cfaddba48bc1bd4966c14fbd0d"
  },
  {
   "t": "2025-12-19T10:24:15Z",
   "kind": "force_push",
   "who": "Sjors",
   "commit": "71795a21e6ec854f2f450ce04cc6ff9e108a2c89"
  },
  {
   "t": "2025-12-19T10:25:37Z",
   "kind": "comment",
   "who": "Sjors",
   "assoc": "MEMBER",
   "text": "Rebased after #34003. Dropped c548d6f0e8ecc0da6e29256c7085d48d10e10216 _test: destroy templates more carefully_. That commit also added coverage for `feeThreshold == MAX_MONEY`, so I moved that into a new commit - not really related to this PR though."
  },
  {
   "t": "2026-01-14T09:54:19Z",
   "kind": "comment",
   "who": "Sjors",
   "assoc": "MEMBER",
   "text": "Rebased after #33819"
  },
  {
   "t": "2026-01-14T09:54:27Z",
   "kind": "force_push",
   "who": "Sjors",
   "commit": "6fb639a089d83a2e4e4eeca26f3041d2da15d0c7"
  },
  {
   "t": "2026-02-03T13:32:38Z",
   "kind": "force_push",
   "who": "Sjors",
   "commit": "c518fdf2dec42b6e52eff172816a097738389d16"
  },
  {
   "t": "2026-02-19T11:04:55Z",
   "kind": "force_push",
   "who": "Sjors",
   "commit": "6cfd0f29e544c85c175a4ea6bf9db64fe57cdc05"
  },
  {
   "t": "2026-02-19T11:06:26Z",
   "kind": "comment",
   "who": "Sjors",
   "assoc": "MEMBER",
   "text": "Rebased after #34452 and #33965."
  },
  {
   "t": "2026-02-23T10:51:15Z",
   "kind": "force_push",
   "who": "Sjors",
   "commit": "2ba0f0ba36a23665c23e190b60282dade1108bbf"
  },
  {
   "t": "2026-02-23T11:09:07Z",
   "kind": "comment",
   "who": "Sjors",
   "assoc": "MEMBER",
   "text": "Rebased after #34568.\n\nAncestor CI failure is probably related to #34646."
  },
  {
   "t": "2026-02-24T12:17:03Z",
   "kind": "force_push",
   "who": "Sjors",
   "commit": "c37d715c1d32020fe16ddc92f7ca95f585cc6b4b"
  },
  {
   "t": "2026-02-24T12:17:35Z",
   "kind": "comment",
   "who": "Sjors",
   "assoc": "MEMBER",
   "text": "Rebased after #34184."
  },
  {
   "t": "2026-03-03T14:35:53Z",
   "kind": "review_comment",
   "who": "vasild",
   "assoc": "MEMBER",
   "path": "src/node/context.h",
   "commit": "c37d715c1d32020fe16ddc92f7ca95f585cc6b4b",
   "in_reply_to": null,
   "text": "Is \"gbt_template\" supposed to mean \"get block template template\"? Maybe \"gbt_result\" or \"get_block_template_result\" would be better."
  },
  {
   "t": "2026-03-03T14:48:24Z",
   "kind": "review_comment",
   "who": "vasild",
   "assoc": "MEMBER",
   "path": "src/node/interfaces.cpp",
   "commit": "9f353d56735293677c1db92e639ef034c615eedd",
   "in_reply_to": null,
   "text": "In the commit message of ee259ca6b4dd4986be45e31aeee8d73bad8a115a `mining: track non-mempool memory usage`:\n\n\"transactions that are removed from the mempool will ~have~ not have their memory cleared.\""
  },
  {
   "t": "2026-03-03T15:26:49Z",
   "kind": "review_comment",
   "who": "vasild",
   "assoc": "MEMBER",
   "path": "src/node/types.h",
   "commit": "c37d715c1d32020fe16ddc92f7ca95f585cc6b4b",
   "in_reply_to": null,
   "text": "How many entries will be supposedly stored in this map? `std::map` has lookup `O(log(size))` whereas `std::unordered_map` has `O(1)`. Here we do not need the entries to be ordered.\n\nnit: start the comment with `/**` to make doxygen recognize it and attach it to the following code in the documentation."
  },
  {
   "t": "2026-03-03T15:43:36Z",
   "kind": "review_comment",
   "who": "vasild",
   "assoc": "MEMBER",
   "path": "src/node/context.h",
   "commit": "c37d715c1d32020fe16ddc92f7ca95f585cc6b4b",
   "in_reply_to": null,
   "text": "I think the comment warrants an elaboration. `gbt_template` is not explicitly cleared anywhere, so that happens at the destructor of `NodeContext`. `struct` members are destroyed in reverse order of their declaration. Is this comment intended to prevent swapping the declaration order of `template_tx_refs` and `gbt_template`?\n\nMaybe:\n\n```cpp\n    //! Cache latest getblocktemplate result for BIP 22 long polling. Must be cleared\n    //! before template_tx_refs because the destructor of this decrements the count\n    //! in `template_tx_refs` of each transaction in the template. If it does not find\n    //! some of its transactions in `template_tx_refs` then it will abort.\n```"
  },
  {
   "t": "2026-03-03T16:38:18Z",
   "kind": "review_comment",
   "who": "vasild",
   "assoc": "MEMBER",
   "path": "src/node/miner.h",
   "commit": "c37d715c1d32020fe16ddc92f7ca95f585cc6b4b",
   "in_reply_to": null,
   "text": "```\nsrc/node/miner.h:17 col 1 warning: Included header map is not used directly\n```"
  },
  {
   "t": "2026-03-03T16:40:47Z",
   "kind": "review_comment",
   "who": "vasild",
   "assoc": "MEMBER",
   "path": "src/node/miner.h",
   "commit": "c37d715c1d32020fe16ddc92f7ca95f585cc6b4b",
   "in_reply_to": null,
   "text": "In the commit message of ce781758df81bca7bc3b60b8e02e36064634439e `ipc: add getMemoryLoad()`\n\n\"which can later be expand to\" ->\n\"which can later be expanded to\""
  },
  {
   "t": "2026-03-03T16:49:34Z",
   "kind": "review",
   "who": "vasild",
   "assoc": "MEMBER",
   "state": "APPROVED",
   "commit": "c37d715c1d32020fe16ddc92f7ca95f585cc6b4b",
   "text": "ACK c37d715c1d32020fe16ddc92f7ca95f585cc6b4b"
  },
  {
   "t": "2026-03-05T19:43:04Z",
   "kind": "review_comment",
   "who": "Sjors",
   "assoc": "MEMBER",
   "path": "src/node/context.h",
   "commit": "c37d715c1d32020fe16ddc92f7ca95f585cc6b4b",
   "in_reply_to": 2878639103,
   "text": "I went for `gbt_result`"
  },
  {
   "t": "2026-03-05T19:43:35Z",
   "kind": "review_comment",
   "who": "Sjors",
   "assoc": "MEMBER",
   "path": "src/node/interfaces.cpp",
   "commit": "9f353d56735293677c1db92e639ef034c615eedd",
   "in_reply_to": 2878715526,
   "text": "Fixed"
  },
  {
   "t": "2026-03-05T19:44:47Z",
   "kind": "review_comment",
   "who": "Sjors",
   "assoc": "MEMBER",
   "path": "src/node/types.h",
   "commit": "c37d715c1d32020fe16ddc92f7ca95f585cc6b4b",
   "in_reply_to": 2878931110,
   "text": "Done both.\n\nAssuming one template per second for two hours (long block interval), less than 10k."
  },
  {
   "t": "2026-03-05T19:56:10Z",
   "kind": "review_comment",
   "who": "Sjors",
   "assoc": "MEMBER",
   "path": "src/node/context.h",
   "commit": "c37d715c1d32020fe16ddc92f7ca95f585cc6b4b",
   "in_reply_to": 2879025033,
   "text": "I took your comment.\n\nIt\u2019s not only about declaration order. The intent is to destroy all BlockTemplate instances, including the one in gbt_result, while template_tx_refs is still alive so destructors can decrement reference counts. Once all templates are gone (and the map is empty), template_tx_refs can be destroyed."
  },
  {
   "t": "2026-03-05T19:58:25Z",
   "kind": "force_push",
   "who": "Sjors",
   "commit": "04553cd6612f08d757fb20287fe111007bfb6db1"
  },
  {
   "t": "2026-03-05T19:58:29Z",
   "kind": "comment",
   "who": "Sjors",
   "assoc": "MEMBER",
   "text": "Rebased after #34422 for easier testing with Rust, see https://github.com/2140-dev/bitcoin-capnp-types/pull/13.\n\nImplemented all of @vasild's nits."
  },
  {
   "t": "2026-03-06T08:55:44Z",
   "kind": "review_comment",
   "who": "vasild",
   "assoc": "MEMBER",
   "path": "src/node/types.h",
   "commit": "c37d715c1d32020fe16ddc92f7ca95f585cc6b4b",
   "in_reply_to": 2878931110,
   "text": "Just mentioning - it is the same for `map` and `unordered_map` when used with `shared_ptr` (or `CTransactionRef`) - they compare pointers. So, two distinct objects that have the same values for all their members will be considered different. I am not sure if this is a problem in our code. Grepping the code for `(map|set).*CTransactionRef`, it looks like this will be the first case in non-test code where we use `CTransactionRef` as a key without providing custom comparator/hasher.\n\nTo illustrate with an explicit example:\n\n```cpp\n    CMutableTransaction mutable_tx;\n    // mutable_tx.vin = ...\n    // mutable_tx.vout = ...\n\n    CTransaction tx1{mutable_tx};\n    CTransaction tx2 = tx1; // tx2 is a copy of tx1, same transaction _logically_\n\n    CTransactionRef tx1_ref{MakeTransactionRef(tx1)};\n    CTransactionRef tx2_ref{MakeTransactionRef(tx2)};\n\n    std::map<CTransactionRef, int> m;\n    assert(m.emplace(tx1_ref, 5).second); // inserted\n    assert(m.emplace(tx2_ref, 6).second); // inserted\n    assert(m.size() == 2); // has 2 elements\n```"
  },
  {
   "t": "2026-03-06T08:57:16Z",
   "kind": "review",
   "who": "vasild",
   "assoc": "MEMBER",
   "state": "APPROVED",
   "commit": "04553cd6612f08d757fb20287fe111007bfb6db1",
   "text": "ACK 04553cd6612f08d757fb20287fe111007bfb6db1\n\nWould be good to figure out if https://github.com/bitcoin/bitcoin/pull/33922#discussion_r2894597519 needs addressing."
  },
  {
   "t": "2026-03-06T11:16:11Z",
   "kind": "review_comment",
   "who": "vasild",
   "assoc": "MEMBER",
   "path": "src/node/types.h",
   "commit": "c37d715c1d32020fe16ddc92f7ca95f585cc6b4b",
   "in_reply_to": 2878931110,
   "text": "If this needs to be resolved, then the below should do it:\n\n```diff\ndiff --git i/src/node/types.h w/src/node/types.h\nindex 164667772a..7bb187ac1c 100644\n--- i/src/node/types.h\n+++ w/src/node/types.h\n@@ -11,21 +11,23 @@\n //! files.\n\n #ifndef BITCOIN_NODE_TYPES_H\n #define BITCOIN_NODE_TYPES_H\n\n #include <consensus/amount.h>\n-#include <cstddef>\n-#include <cstdint>\n-#include <optional>\n #include <policy/policy.h>\n #include <primitives/transaction.h>\n #include <script/script.h>\n-#include <unordered_map>\n #include <uint256.h>\n+#include <util/hasher.h>\n #include <util/time.h>\n+\n+#include <cstddef>\n+#include <cstdint>\n+#include <optional>\n+#include <unordered_map>\n #include <vector>\n\n namespace node {\n enum class TransactionError {\n     OK, //!< No error\n     MISSING_INPUTS,\n@@ -173,11 +175,11 @@ enum class TxBroadcast : uint8_t {\n     NO_MEMPOOL_PRIVATE_BROADCAST,\n };\n\n /**\n  * Map how many templates refer to each transaction reference.\n  */\n-using TxTemplateMap = std::unordered_map<CTransactionRef, size_t>;\n+using TxTemplateMap = std::unordered_map<CTransactionRef, size_t, CTransactionRefSaltedHash, CTransactionRefComp>;\n\n } // namespace node\n\n #endif // BITCOIN_NODE_TYPES_H\ndiff --git i/src/util/hasher.h w/src/util/hasher.h\nindex 02c7703391..d3b77ba72d 100644\n--- i/src/util/hasher.h\n+++ w/src/util/hasher.h\n@@ -114,7 +114,23 @@ private:\n public:\n     SaltedSipHasher();\n\n     size_t operator()(const std::span<const unsigned char>& script) const;\n };\n\n+struct CTransactionRefSaltedHash {\n+    SaltedWtxidHasher m_wtxid_hasher;\n+\n+    size_t operator()(const CTransactionRef& tx) const\n+    {\n+        return m_wtxid_hasher(tx->GetWitnessHash());\n+    }\n+};\n+\n+struct CTransactionRefComp {\n+    bool operator()(const CTransactionRef& a, const CTransactionRef& b) const\n+    {\n+        return a->GetWitnessHash() == b->GetWitnessHash();\n+    }\n+};\n+\n #endif // BITCOIN_UTIL_HASHER_H\n```\n\nUsing a salted hash instead of barely using the first bytes of the transaction id as a hash because somebody may craft a pile of transactions with such ids as to make `unordered_map` lookup time deteriorate from `O(1)` to `O(size)`. Not sure if that is an overkill in the current use case. In `PrivateBroadcast::m_transactions` I used the simpler:\n\n```cpp\n    struct CTransactionRefHash {\n        size_t operator()(const CTransactionRef& tx) const\n        {\n            return static_cast<size_t>(tx->GetWitnessHash().ToUint256().GetUint64(0));\n        }\n    };\n```\nbecause there 1. the transactions are originating locally (do not come from untrusted sources) and 2. the expectation is to store a small number of transactions, so even `O(size)` will not hog the machine."
  },
  {
   "t": "2026-04-06T10:52:35Z",
   "kind": "review",
   "who": "enirox001",
   "assoc": "CONTRIBUTOR",
   "state": "COMMENTED",
   "commit": "04553cd6612f08d757fb20287fe111007bfb6db1",
   "text": "ACK 04553cd\n\nWent through each commit:\n\n- [x] 6f12988 - forward declaration of `BlockTemplate` in `context.h` is necessary, `mining.h` is not in the include chain\n- [x] b22e535 - destruction ordering of `gbt_result` before `template_tx_refs` looks correct. break in `~BlockTemplateImpl` makes sense, and no lock inversion between `template_state_mutex` and `cs_main`\n- [x] 1d7497f - `mempool.cs` is intentionally not held for the full loop to avoid blocking relay, which is well documented\n- [x] 9f4b744 - locking looks consistent with commit 3, `template_state_mutex` guards the map while `mempool.cs` is acquired per `exists()` call\n- [x] 04553cd - `MAX_MONEY` is a good boundary case to have covered\n\nRan interface_ipc_mining.py and all tests passed successfully."
  },
  {
   "t": "2026-04-08T09:25:18Z",
   "kind": "review_comment",
   "who": "Sjors",
   "assoc": "MEMBER",
   "path": "src/node/types.h",
   "commit": "c37d715c1d32020fe16ddc92f7ca95f585cc6b4b",
   "in_reply_to": 2878931110,
   "text": "Sorry I missed this followup earlier.\n\nI ended up using `CTransactionRefSaltedHash`. Unless performance is actually a problem, it's better to err on the side of caution.\n\nIt seems unlikely that someone is going to spend a fortune on grinding 64 bit mempool collisions to marginally slow this function down. But the transactions are not generated locally and with a combination bad mempool weather and a long block interval, the collection can be large.\n\nAlso, since we're exposing this function in `src/util/hasher.h`, where others might reuse it, it seems better to use a safe version."
  },
  {
   "t": "2026-04-08T09:28:48Z",
   "kind": "force_push",
   "who": "Sjors",
   "commit": "430990c0c5bc72f8b64e76056b304b88821b9af0"
  },
  {
   "t": "2026-04-08T09:32:14Z",
   "kind": "comment",
   "who": "Sjors",
   "assoc": "MEMBER",
   "text": "@vasild wrote:\n\n[quoted text omitted]\nThanks for the reminder. I ended up using the salted hasher in a6d4b883ce48ce04721a6dc6160e166bc3a40875.\n\nI also added 430990c0c5bc72f8b64e76056b304b88821b9af0 to delete the default `std::hash` constructor for `CTransactionRef`, for good measure.\n\nDeleting `operator==` would make sense for the same reason, but involves a fair amount of test churn, so I didn't do it here."
  },
  {
   "t": "2026-04-08T09:36:05Z",
   "kind": "force_push",
   "who": "Sjors",
   "commit": "10acf818ed70d4cd2af864278a35a6b64de0bb16"
  },
  {
   "t": "2026-04-09T10:14:53Z",
   "kind": "review_comment",
   "who": "vasild",
   "assoc": "MEMBER",
   "path": "src/primitives/transaction.h",
   "commit": "10acf818ed70d4cd2af864278a35a6b64de0bb16",
   "in_reply_to": null,
   "text": "`<variant>` was added in the last commit 10acf818ed70d4cd2af864278a35a6b64de0bb16 `refactor: disable default std::hash for CTransactionRef`, but I think that it is not needed for the newly added code:\n\n```cpp\n/** Disable default std::hash for CTransactionRef to prevent accidentally\n *  comparing by pointer. Use CTransactionRefSaltedHash or provide a custom\n *  hasher. */\ntemplate<>\nstruct std::hash<CTransactionRef> {\n    size_t operator()(const CTransactionRef&) const = delete;\n};\n```"
  },
  {
   "t": "2026-04-09T10:15:44Z",
   "kind": "review",
   "who": "vasild",
   "assoc": "MEMBER",
   "state": "APPROVED",
   "commit": "10acf818ed70d4cd2af864278a35a6b64de0bb16",
   "text": "ACK 10acf818ed70d4cd2af864278a35a6b64de0bb16"
  },
  {
   "t": "2026-04-14T14:56:16Z",
   "kind": "force_push",
   "who": "Sjors",
   "commit": "d1b9df5805b9219217b7b22eedaf1fcb5704e35d"
  },
  {
   "t": "2026-04-14T18:20:25Z",
   "kind": "comment",
   "who": "Sjors",
   "assoc": "MEMBER",
   "text": "The IWYU linter insists on `#include <variant>`: https://github.com/bitcoin/bitcoin/actions/runs/24406181800/job/71290035323?pr=33922\n\nBut that seems wrong, so I added a commit to override it."
  },
  {
   "t": "2026-04-14T18:24:33Z",
   "kind": "force_push",
   "who": "Sjors",
   "commit": "cd1fce108dca9c02abf76cbeb009ed6c2cfa8cc9"
  },
  {
   "t": "2026-04-14T18:26:09Z",
   "kind": "comment",
   "who": "Sjors",
   "assoc": "MEMBER",
   "text": "Trying a rebase without cd1fce108dca9c02abf76cbeb009ed6c2cfa8cc9 first, to see if #34896 fixed the IWYU false positive."
  },
  {
   "t": "2026-04-14T18:39:33Z",
   "kind": "force_push",
   "who": "Sjors",
   "commit": "e8aaada3f2f8396b47eda9fad576ab89dbdf80ab"
  },
  {
   "t": "2026-04-14T18:42:08Z",
   "kind": "comment",
   "who": "Sjors",
   "assoc": "MEMBER",
   "text": "The workaround is still needed. We can drop it here if #35073 lands."
  },
  {
   "t": "2026-04-14T18:43:20Z",
   "kind": "review_comment",
   "who": "Sjors",
   "assoc": "MEMBER",
   "path": "src/primitives/transaction.h",
   "commit": "10acf818ed70d4cd2af864278a35a6b64de0bb16",
   "in_reply_to": 3057053043,
   "text": "It was an IWYU false positive, see comments below."
  },
  {
   "t": "2026-04-16T13:34:12Z",
   "kind": "review_comment",
   "who": "hebasto",
   "assoc": "MEMBER",
   "path": "src/primitives/transaction.h",
   "commit": "e23a8f3015d8b3c682c45adb3cb39db912f7d1a9",
   "in_reply_to": null,
   "text": "Are we sure about this parameter type? According to the [docs](https://en.cppreference.com/w/cpp/utility/hash/operator().html):\n[quoted text omitted]\n\nShould this be `CTransactionRef` instead of `const CTransactionRef&`?"
  },
  {
   "t": "2026-04-17T13:01:06Z",
   "kind": "force_push",
   "who": "Sjors",
   "commit": "bf49247b35f43ed9bcb769ea0f9a8eba2ce082d5"
  },
  {
   "t": "2026-04-17T13:02:18Z",
   "kind": "force_push",
   "who": "Sjors",
   "commit": "4673836a656a2638292fd02453e5d8ef42cd8eab"
  },
  {
   "t": "2026-04-17T13:10:21Z",
   "kind": "force_push",
   "who": "Sjors",
   "commit": "5094af74bc5280b89835654ff7a7604d57a31d8c"
  },
  {
   "t": "2026-04-17T13:21:17Z",
   "kind": "force_push",
   "who": "Sjors",
   "commit": "ceb5b70a53c43fd31dbaaaf5737e6550c2fe51e6"
  },
  {
   "t": "2026-04-17T13:29:41Z",
   "kind": "force_push",
   "who": "Sjors",
   "commit": "e23a8f3015d8b3c682c45adb3cb39db912f7d1a9"
  },
  {
   "t": "2026-04-17T13:30:22Z",
   "kind": "review_comment",
   "who": "Sjors",
   "assoc": "MEMBER",
   "path": "src/primitives/transaction.h",
   "commit": "e23a8f3015d8b3c682c45adb3cb39db912f7d1a9",
   "in_reply_to": 3093561704,
   "text": "Thanks, I'll look into this after figuring out the iwyu stuff."
  },
  {
   "t": "2026-04-17T13:53:28Z",
   "kind": "review_comment",
   "who": "maflcko",
   "assoc": "MEMBER",
   "path": "src/primitives/transaction.h",
   "commit": "e23a8f3015d8b3c682c45adb3cb39db912f7d1a9",
   "in_reply_to": null,
   "text": "NACK\n\nThis is wrong and harmful, as already explained in https://github.com/bitcoin/bitcoin/pull/35073#issuecomment-4258599969"
  },
  {
   "t": "2026-04-17T13:56:05Z",
   "kind": "review_comment",
   "who": "Sjors",
   "assoc": "MEMBER",
   "path": "src/primitives/transaction.h",
   "commit": "e23a8f3015d8b3c682c45adb3cb39db912f7d1a9",
   "in_reply_to": 3100806462,
   "text": "Open to suggestions that you've actually tried."
  },
  {
   "t": "2026-04-17T14:30:39Z",
   "kind": "review_comment",
   "who": "maflcko",
   "assoc": "MEMBER",
   "path": "src/primitives/transaction.h",
   "commit": "e23a8f3015d8b3c682c45adb3cb39db912f7d1a9",
   "in_reply_to": 3100806462,
   "text": "My suggestion would be either commit 10acf818ed70d4cd2af864278a35a6b64de0bb16 (CI passed IIUC, so I think that counts as \"tried\"?) An alternative would be https://github.com/bitcoin/bitcoin/pull/35073#discussion_r3093983379, which I presume was tried by the author that posted it. I am happy to push that suggestion to CI, if you want me to try it as well."
  },
  {
   "t": "2026-04-17T14:42:01Z",
   "kind": "force_push",
   "who": "Sjors",
   "commit": "79a74da860a557af73788f277306a4aee67bc50a"
  },
  {
   "t": "2026-04-17T14:43:59Z",
   "kind": "review_comment",
   "who": "Sjors",
   "assoc": "MEMBER",
   "path": "src/primitives/transaction.h",
   "commit": "e23a8f3015d8b3c682c45adb3cb39db912f7d1a9",
   "in_reply_to": 3100806462,
   "text": "[quoted text omitted]\n\nThat's fair.\n\n[quoted text omitted]\nI'm trying that again now, this time with `namespace std` that was missing in my earlier attempt."
  },
  {
   "t": "2026-04-17T15:26:55Z",
   "kind": "force_push",
   "who": "Sjors",
   "commit": "b89942d29f1e71429070b2d1140d2792eb33bf47"
  },
  {
   "t": "2026-04-17T15:30:19Z",
   "kind": "review_comment",
   "who": "Sjors",
   "assoc": "MEMBER",
   "path": "src/primitives/transaction.h",
   "commit": "e23a8f3015d8b3c682c45adb3cb39db912f7d1a9",
   "in_reply_to": 3100806462,
   "text": "Unfortunately that leads to a `reference to 'hash' is ambiguous` (`std::__1::hash` vs `std::hash`). Let's see if b89942d29f1e71429070b2d1140d2792eb33bf47 fixes that.\n\n10acf818ed70d4cd2af864278a35a6b64de0bb16 is of course a lot simpler, but also brittle because slightly different builds of IWYU will demand different includes (`<variant>` or `<string_view>`)."
  },
  {
   "t": "2026-04-17T15:42:07Z",
   "kind": "review_comment",
   "who": "maflcko",
   "assoc": "MEMBER",
   "path": "src/primitives/transaction.h",
   "commit": "e23a8f3015d8b3c682c45adb3cb39db912f7d1a9",
   "in_reply_to": 3100806462,
   "text": "[quoted text omitted]\n\nCorrect, but I think this is already true on current master: I think on current master a different build of IWYU will already yield a different result. I know it is not ideal, but I think the current approach is to let the CI spit out the diff when in doubt, then look if the diff has a backdoor or some nasty/wrong stuff, if not, just take the diff.\n\n[quoted text omitted]\nAh. Thx for testing. This looks a bit nasty to work around. Honestly, I'd just go with https://github.com/bitcoin/bitcoin/commit/10acf818ed70d4cd2af864278a35a6b64de0bb16 for now. If you want, I can try https://github.com/bitcoin/bitcoin/pull/35073#discussion_r3094156124 next week or so, to see if it is overall better, but I wouldn't spend too much time on this."
  },
  {
   "t": "2026-04-17T16:01:16Z",
   "kind": "comment",
   "who": "Sjors",
   "assoc": "MEMBER",
   "text": "Waiting for CI to pass. I'm probably going to move 92fd54b259fadce8c14b8207d40431aef60a8c8d and b89942d29f1e71429070b2d1140d2792eb33bf47 in a separate PR. Need to address this too: https://github.com/bitcoin/bitcoin/pull/33922#discussion_r3093561704"
  },
  {
   "t": "2026-04-17T16:07:32Z",
   "kind": "review_comment",
   "who": "Sjors",
   "assoc": "MEMBER",
   "path": "src/primitives/transaction.h",
   "commit": "e23a8f3015d8b3c682c45adb3cb39db912f7d1a9",
   "in_reply_to": 3100806462,
   "text": "I found a nicer variant, will open a fresh PR."
  },
  {
   "t": "2026-04-17T16:34:54Z",
   "kind": "review_comment",
   "who": "maflcko",
   "assoc": "MEMBER",
   "path": "src/primitives/transaction.h",
   "commit": "e23a8f3015d8b3c682c45adb3cb39db912f7d1a9",
   "in_reply_to": 3093561704,
   "text": "[quoted text omitted]\n\nNo, I am sure the docs just refer to the logical type . C.f also e.g. libc++:\n\nhttps://github.com/llvm/llvm-project/blob/25b0ab2d4f7a7a4b165b26d31dd563ef4dde4f17/libcxx/include/string#L3909-L3915"
  },
  {
   "t": "2026-04-17T16:37:53Z",
   "kind": "review_comment",
   "who": "maflcko",
   "assoc": "MEMBER",
   "path": "src/primitives/transaction.h",
   "commit": "e23a8f3015d8b3c682c45adb3cb39db912f7d1a9",
   "in_reply_to": 3100806462,
   "text": "That looks a bit verbose. I'd just go with https://github.com/bitcoin/bitcoin/commit/10acf818ed70d4cd2af864278a35a6b64de0bb16. If you really want, I'd say you can open a follow-up if and when this one is merged. But no strong opinion, up to you."
  },
  {
   "t": "2026-04-17T19:48:50Z",
   "kind": "review_comment",
   "who": "Sjors",
   "assoc": "MEMBER",
   "path": "src/primitives/transaction.h",
   "commit": "e23a8f3015d8b3c682c45adb3cb39db912f7d1a9",
   "in_reply_to": 3100806462,
   "text": "The problem with 10acf818ed70d4cd2af864278a35a6b64de0bb16 is that it only works on our CI. On e.g. my Ubuntu 25.10 with include-what-you-use 0.26, based clang version 22.1.1, that commit fails because it insists on `<string_view>`.\n\nIdeally we shouldn't end up in the same situation as our linter job that can't be run outside a container."
  },
  {
   "t": "2026-04-17T19:49:18Z",
   "kind": "force_push",
   "who": "Sjors",
   "commit": "d37e0fc16c235ff511bd9485ef505f0c5615d9e4"
  },
  {
   "t": "2026-04-17T19:49:19Z",
   "kind": "comment",
   "who": "Sjors",
   "assoc": "MEMBER",
   "text": "The safety commit for `CTransactionRef` and IWYU changes are now in #35101 and dropped from this PR."
  },
  {
   "t": "2026-04-24T09:58:14Z",
   "kind": "review_comment",
   "who": "Sjors",
   "assoc": "MEMBER",
   "path": "src/primitives/transaction.h",
   "commit": "e23a8f3015d8b3c682c45adb3cb39db912f7d1a9",
   "in_reply_to": 3100806462,
   "text": "(this code was changed, and also moved to #35101, so no longer relevant here)"
  },
  {
   "t": "2026-04-24T09:58:44Z",
   "kind": "review_comment",
   "who": "Sjors",
   "assoc": "MEMBER",
   "path": "src/primitives/transaction.h",
   "commit": "e23a8f3015d8b3c682c45adb3cb39db912f7d1a9",
   "in_reply_to": 3093561704,
   "text": "(this was moved to #35101)"
  },
  {
   "t": "2026-04-27T10:04:18Z",
   "kind": "review",
   "who": "vasild",
   "assoc": "MEMBER",
   "state": "APPROVED",
   "commit": "d37e0fc16c235ff511bd9485ef505f0c5615d9e4",
   "text": "ACK d37e0fc16c235ff511bd9485ef505f0c5615d9e4\n\nShow Signature\n\n```\n-----BEGIN PGP SIGNED MESSAGE-----\nHash: SHA256\n\nACK d37e0fc16c235ff511bd9485ef505f0c5615d9e4\n-----BEGIN PGP SIGNATURE-----\n\niQQzBAEBCAAdFiEE5k2NRWFNsHVF2czBVN8G9ktVy78FAmnvNGMACgkQVN8G9ktV\ny79uSyAAmswvwjxbv/vFTrf0BERXNHfG0lEVrvURRQavQzajUq0Q0dSiUpBlklGY\nEc+zt5x6G9vSGkYeo7ZFyjV7uwhLMMKlOGxqmnrKUT4PWHYjiItpnsJPEE8iK7hc\nM2Xpq7OGNiWfc+ZT81KIYYPo6v+dRBKBh+dHwdgJ/5X7nFSMru7OV0+W4uk4wfu1\nxayuZ5A1jWqM/vqYt9jEtmEaPhyVma61CxiMCGoxOIuhsuKGx49gZb+AQi3zuyD0\nGKViOOA+A9krE0Ntr8MZeoXRw/+loj+yDp49s/l9LJ6rG8C3o4CKDMjzTcGSbWp8\nsc1dN0wohyMwOrBToEidkC+G4eN1+uRG4KDbkfy+gpbeNfzLj7lLDppmxJGXimKm\nisCC9sq14Y0caSomDvLGFddtaGgmnq4AoZQLT49j6tleOaQArQv7xWwTgjiVMcG3\nOhqCEHeuJJEDoLHaoVFG4MHSx2TrgukC4UtqRvASCayHslU0z/77RlkeKZD4B/k8\niaHOocAMl0m61r+Cw4ryZ0YfGfRKrOoFJ3PLmF/pcjj3iDE2Eq1vZ0pNq/ECzpSm\nzOiLRt+3r5NsUphE9jm2AROKtQApaklNjCWidK7bUCRoA884y660m/TIZKJhcDj1\np/OPxjz36ZDdTV5YLQI+JOxgdnndfF1HQqjspZIHPsMOH6e+qkIDfyfW0apExHN+\nyDoI1XoEPEIXJv4nsjSFWIUZajSOSTHjV96xrx6/ca3bbE5thix9DqLhhPsvtSHn\nykxzMhbwgUQND3Af2q16YUA9qhjUAo87Ixe99M6Ywnti52gqJ5zRZf4EgWy+A5kk\ntm/YLkN3xdnLl3frNZVrBGHZwEbDMZdu8WwpHgnuGPH5DASjG4HcdJaXE0WhCNpc\nmVq6YZfxJZ9NNGIpcV6pU4RoFALb981XlFfRhgtC+5Nyrjui/uPF0GrXGsiHSG9w\nOzWNsR9ghyBtXyxnZ8iCI+uyX8TVxc6M/vU5PoVZGEoKJaBZqh+NclfgsZLnZqx0\n5iwCLPAPJZjXsabuQ8Ya54ctHHySyk36ciqMpwWRpPPkGMW4Ya3HNMfZGSQmhiYb\nFeaghFsHwtgmjbBgTLznSUCzZH+Ec7qKdk0vw+uPZveYHHIUrvbAnXuNOlbAiN1Y\nXDDpPtLld+wZ89c7XUVM+5tM30fm8/M0w9y5ezDAeELVniU1mcPOnBaqgLBkv570\nmJa7CEmLYOaSMzkVi3gx02sjqbEsRJlx9WAQvlETuljWT/GNggZ5hu6WCndHZ8zN\nhPdARxrVv9D7p4ktAUcFRRcPalbszWwxrqp4/lnSpJbiYnNZDt5V1w2QniHBg6g/\nAdTc9REfGHEi14IqXV3ysK2UMlBDmg==\n=q3ZT\n-----END PGP SIGNATURE-----\n```\n\nvasild's public key is [on openpgp.org](https://keys.openpgp.org/vks/v1/by-fingerprint/850E138BA9C0923881DFD55FCE712013582E2230)"
  },
  {
   "t": "2026-05-22T07:40:04Z",
   "kind": "force_push",
   "who": "Sjors",
   "commit": "9f353d56735293677c1db92e639ef034c615eedd"
  },
  {
   "t": "2026-05-22T07:40:13Z",
   "kind": "comment",
   "who": "Sjors",
   "assoc": "MEMBER",
   "text": "Rebased after #34806 (trivial include conflict)."
  },
  {
   "t": "2026-05-26T16:03:27Z",
   "kind": "force_push",
   "who": "Sjors",
   "commit": "39254e9edf50781fffa613966f886809595aa998"
  },
  {
   "t": "2026-05-26T16:03:28Z",
   "kind": "comment",
   "who": "Sjors",
   "assoc": "MEMBER",
   "text": "Rebased after #33966. Not sure if marking `template_state_mutex` as `mutable` is going in the right direction?"
  },
  {
   "t": "2026-05-27T14:07:01Z",
   "kind": "comment",
   "who": "Sjors",
   "assoc": "MEMBER",
   "text": "Going to mark this draft pending #33421. It seems to be in good shape and will provide a more natural home for memory accounting here."
  },
  {
   "t": "2026-05-28T17:58:47Z",
   "kind": "comment",
   "who": "Sjors",
   "assoc": "MEMBER",
   "text": "Rebased:\n- bumped `getMemoryLoad` to `@8` in `mining.capnp` because #34644 added `submitBlock @7`\n- temporarily added 51dc31db12 `test: refresh MiniWallet after node restart`, cherry-picked from #35403"
  },
  {
   "t": "2026-05-28T17:58:47Z",
   "kind": "force_push",
   "who": "Sjors",
   "commit": "c82ccf896759b0d89a953dfb0c66fda176f22afc"
  },
  {
   "t": "2026-06-24T09:45:43Z",
   "kind": "force_push",
   "who": "Sjors",
   "commit": "3cb6c4779e20f183347c3c1d63d8abb9d2e4c4ee"
  },
  {
   "t": "2026-06-24T09:46:02Z",
   "kind": "comment",
   "who": "Sjors",
   "assoc": "MEMBER",
   "text": "Rebased after #35403.\n\nMeanwhile #33421 was superseded by #35581, which I need to study in order to decide if I want to build on top of it or continue with the existing approach."
  },
  {
   "t": "2026-06-24T19:37:28Z",
   "kind": "force_push",
   "who": "Sjors",
   "commit": "8b4967e3570a7adce2e73c3476bcdd5d676cf090"
  },
  {
   "t": "2026-06-24T19:38:38Z",
   "kind": "comment",
   "who": "Sjors",
   "assoc": "MEMBER",
   "text": "I opened #35598 and dropped 3cb6c4779e20f183347c3c1d63d8abb9d2e4c4ee _test: cover feeThreshold = MAX_MONEY_ from this PR since it's unrelated and distracting.\n\n---\n\nI implemented the same functionality on top of https://github.com/bitcoin/bitcoin/pull/35581  in https://github.com/Sjors/bitcoin/pull/120. It fits well, although I still haven't studied PR 35581 itself. It also appears that I can drop 22f69a10df4afdc4c7b7d97844d8c245158f1ca0 `rpc: move static block_template to node context` in that design.\n\nIf #35581 gets enough support from reviewers, I'll switch this PR over to it. That's preferable to merging this and then having to move things to the `BlockTemplateManager` later, especially since this change isn't urgent."
  },
  {
   "t": "2026-07-08T07:58:27Z",
   "kind": "force_push",
   "who": "Sjors",
   "commit": "837060b034e65ceabed52e35f9e4bcc276a4bafb"
  },
  {
   "t": "2026-07-08T07:58:32Z",
   "kind": "comment",
   "who": "Sjors",
   "assoc": "MEMBER",
   "text": "I switched over to the approach from https://github.com/Sjors/bitcoin/pull/120, so this branch is now based on ~a rebased~ https://github.com/bitcoin/bitcoin/pull/35675. Also had to rebase after #34020.\n\nExpanded the new template manager fuzzer to cover `GetTemplateMemoryUsage()`."
  },
  {
   "t": "2026-07-08T10:19:38Z",
   "kind": "force_push",
   "who": "Sjors",
   "commit": "d1f9b11b40661bb49d19333e9fcc43d5a969eb3f"
  },
  {
   "t": "2026-07-16T13:55:00Z",
   "kind": "force_push",
   "who": "Sjors",
   "commit": "ef901fa30831b99ca1892bf7949e7bd92a42460b"
  },
  {
   "t": "2026-07-16T15:14:19Z",
   "kind": "force_push",
   "who": "Sjors",
   "commit": "239af38f706835a5a5ca10176a4bcda45196d919"
  },
  {
   "t": "2026-07-23T17:37:26Z",
   "kind": "force_push",
   "who": "Sjors",
   "commit": "794a8a04dd6bfeac3553a71c24f21be9d0afa38b"
  },
  {
   "t": "2026-07-23T17:37:32Z",
   "kind": "comment",
   "who": "Sjors",
   "assoc": "MEMBER",
   "text": "Rebased to track the latest https://github.com/bitcoin/bitcoin/pull/35675."
  },
  {
   "t": "2026-07-23T18:04:26Z",
   "kind": "force_push",
   "who": "Sjors",
   "commit": "1f569895ea25814e46ba53f94efa618c7bc9eacc"
  },
  {
   "t": "2026-07-24T13:25:55Z",
   "kind": "force_push",
   "who": "Sjors",
   "commit": "de2c7a8f975f0309bb7eb9c86675ce825342cf4f"
  },
  {
   "t": "2026-08-20T09:23:04Z",
   "kind": "force_push",
   "who": "Sjors",
   "commit": "c10e77f9897ed74ca9f3cf3085cd1eabb956fbe3"
  },
  {
   "t": "2026-09-09T07:44:37Z",
   "kind": "force_push",
   "who": "Sjors",
   "commit": "4259dde8f195b71e0282bb8f82d5009107945aa2"
  },
  {
   "t": "2026-09-14T09:56:27Z",
   "kind": "force_push",
   "who": "Sjors",
   "commit": "11739697d0b6d8015c2746dd3d42866a694bcae3"
  },
  {
   "t": "2026-09-14T12:47:55Z",
   "kind": "force_push",
   "who": "Sjors",
   "commit": "1647b291ccae0c0c5c79f0117adcbb0d73231221"
  }
 ],
 "labels_log": [
  {
   "t": "2025-11-21T15:34:17Z",
   "action": "labeled",
   "label": "Mining",
   "who": "DrahtBot"
  },
  {
   "t": "2025-11-21T16:05:30Z",
   "action": "labeled",
   "label": "CI failed",
   "who": "DrahtBot"
  },
  {
   "t": "2025-11-21T17:20:39Z",
   "action": "unlabeled",
   "label": "CI failed",
   "who": "DrahtBot"
  },
  {
   "t": "2025-11-25T17:22:27Z",
   "action": "labeled",
   "label": "CI failed",
   "who": "DrahtBot"
  },
  {
   "t": "2025-11-25T21:47:49Z",
   "action": "unlabeled",
   "label": "CI failed",
   "who": "DrahtBot"
  },
  {
   "t": "2025-12-05T11:14:26Z",
   "action": "labeled",
   "label": "CI failed",
   "who": "DrahtBot"
  },
  {
   "t": "2025-12-05T12:44:18Z",
   "action": "unlabeled",
   "label": "CI failed",
   "who": "DrahtBot"
  },
  {
   "t": "2025-12-16T15:27:29Z",
   "action": "labeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  },
  {
   "t": "2025-12-19T12:23:42Z",
   "action": "unlabeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  },
  {
   "t": "2026-01-13T13:16:17Z",
   "action": "labeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  },
  {
   "t": "2026-01-14T11:17:58Z",
   "action": "unlabeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  },
  {
   "t": "2026-02-02T23:52:46Z",
   "action": "labeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  },
  {
   "t": "2026-02-03T15:36:04Z",
   "action": "unlabeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  },
  {
   "t": "2026-02-03T15:50:35Z",
   "action": "labeled",
   "label": "CI failed",
   "who": "DrahtBot"
  },
  {
   "t": "2026-02-04T10:04:40Z",
   "action": "unlabeled",
   "label": "CI failed",
   "who": "DrahtBot"
  },
  {
   "t": "2026-02-07T10:42:33Z",
   "action": "labeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  },
  {
   "t": "2026-02-19T11:14:35Z",
   "action": "unlabeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  },
  {
   "t": "2026-02-20T11:11:21Z",
   "action": "labeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  },
  {
   "t": "2026-02-23T12:07:36Z",
   "action": "labeled",
   "label": "CI failed",
   "who": "DrahtBot"
  },
  {
   "t": "2026-02-23T12:38:11Z",
   "action": "unlabeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  },
  {
   "t": "2026-02-24T17:15:28Z",
   "action": "unlabeled",
   "label": "CI failed",
   "who": "DrahtBot"
  },
  {
   "t": "2026-04-08T09:36:40Z",
   "action": "labeled",
   "label": "CI failed",
   "who": "DrahtBot"
  },
  {
   "t": "2026-04-08T10:23:44Z",
   "action": "unlabeled",
   "label": "CI failed",
   "who": "DrahtBot"
  },
  {
   "t": "2026-04-14T15:50:45Z",
   "action": "labeled",
   "label": "CI failed",
   "who": "DrahtBot"
  },
  {
   "t": "2026-04-14T19:30:37Z",
   "action": "unlabeled",
   "label": "CI failed",
   "who": "DrahtBot"
  },
  {
   "t": "2026-04-17T13:03:14Z",
   "action": "labeled",
   "label": "CI failed",
   "who": "DrahtBot"
  },
  {
   "t": "2026-04-17T14:23:53Z",
   "action": "unlabeled",
   "label": "CI failed",
   "who": "DrahtBot"
  },
  {
   "t": "2026-04-17T15:25:32Z",
   "action": "labeled",
   "label": "CI failed",
   "who": "DrahtBot"
  },
  {
   "t": "2026-04-17T16:20:37Z",
   "action": "unlabeled",
   "label": "CI failed",
   "who": "DrahtBot"
  },
  {
   "t": "2026-05-22T04:15:52Z",
   "action": "labeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  },
  {
   "t": "2026-05-22T10:49:57Z",
   "action": "unlabeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  },
  {
   "t": "2026-05-26T13:01:58Z",
   "action": "labeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  },
  {
   "t": "2026-05-26T17:32:49Z",
   "action": "unlabeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  },
  {
   "t": "2026-05-28T15:26:38Z",
   "action": "labeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  },
  {
   "t": "2026-05-28T20:17:18Z",
   "action": "unlabeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  },
  {
   "t": "2026-06-23T23:08:55Z",
   "action": "labeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  },
  {
   "t": "2026-06-24T09:48:00Z",
   "action": "unlabeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  },
  {
   "t": "2026-07-07T21:51:13Z",
   "action": "labeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  },
  {
   "t": "2026-07-08T08:50:44Z",
   "action": "unlabeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  },
  {
   "t": "2026-07-16T15:11:48Z",
   "action": "labeled",
   "label": "CI failed",
   "who": "DrahtBot"
  },
  {
   "t": "2026-07-16T16:28:59Z",
   "action": "unlabeled",
   "label": "CI failed",
   "who": "DrahtBot"
  },
  {
   "t": "2026-07-23T00:55:52Z",
   "action": "labeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  },
  {
   "t": "2026-07-23T18:05:00Z",
   "action": "labeled",
   "label": "CI failed",
   "who": "DrahtBot"
  },
  {
   "t": "2026-07-23T18:51:02Z",
   "action": "unlabeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  },
  {
   "t": "2026-07-23T19:28:51Z",
   "action": "unlabeled",
   "label": "CI failed",
   "who": "DrahtBot"
  },
  {
   "t": "2026-08-04T09:35:00Z",
   "action": "labeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  },
  {
   "t": "2026-08-20T10:24:55Z",
   "action": "unlabeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  },
  {
   "t": "2026-08-21T08:41:42Z",
   "action": "labeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  },
  {
   "t": "2026-09-09T09:19:26Z",
   "action": "unlabeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  },
  {
   "t": "2026-09-09T16:35:15Z",
   "action": "labeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  },
  {
   "t": "2026-09-14T11:06:30Z",
   "action": "unlabeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  },
  {
   "t": "2026-09-14T11:22:06Z",
   "action": "labeled",
   "label": "CI failed",
   "who": "DrahtBot"
  },
  {
   "t": "2026-09-14T14:41:42Z",
   "action": "unlabeled",
   "label": "CI failed",
   "who": "DrahtBot"
  }
 ],
 "state_log": [
  {
   "t": "2026-04-17T14:44:45Z",
   "kind": "convert_to_draft",
   "who": "Sjors"
  },
  {
   "t": "2026-04-17T19:50:51Z",
   "kind": "ready_for_review",
   "who": "Sjors"
  },
  {
   "t": "2026-05-27T14:07:04Z",
   "kind": "convert_to_draft",
   "who": "Sjors"
  }
 ],
 "text_chars": 34494,
 "text_tokens_estimate": 8623,
 "changed_paths": [
  "ci/test/03_test_script.sh",
  "src/CMakeLists.txt",
  "src/init.cpp",
  "src/interfaces/mining.h",
  "src/ipc/capnp/mining.capnp",
  "src/node/block_template_manager.cpp",
  "src/node/block_template_manager.h",
  "src/node/context.cpp",
  "src/node/context.h",
  "src/node/interfaces.cpp",
  "src/node/miner.cpp",
  "src/node/miner.h",
  "src/private_broadcast.h",
  "src/rpc/blockchain.cpp",
  "src/rpc/mining.cpp",
  "src/rpc/server_util.cpp",
  "src/rpc/server_util.h",
  "src/test/fuzz/CMakeLists.txt",
  "src/test/fuzz/block_template_manager.cpp",
  "src/test/fuzz/connect_block.cpp",
  "src/test/fuzz/private_broadcast.cpp",
  "src/test/fuzz/rpc.cpp",
  "src/test/fuzz/utxo_snapshot.cpp",
  "src/test/miner_tests.cpp",
  "src/test/peerman_tests.cpp",
  "src/test/util/mining.cpp",
  "src/test/util/setup_common.cpp",
  "src/test/util/setup_common.h",
  "src/test/util/validation.cpp",
  "src/test/validation_block_tests.cpp",
  "src/test/validation_chainstatemanager_tests.cpp",
  "src/util/hasher.h",
  "src/wallet/test/fuzz/fees.cpp",
  "test/functional/interface_ipc_mining.py"
 ],
 "files": [
  {
   "path": "ci/test/03_test_script.sh",
   "add": 1,
   "del": 1
  },
  {
   "path": "src/CMakeLists.txt",
   "add": 1,
   "del": 0
  },
  {
   "path": "src/init.cpp",
   "add": 8,
   "del": 8
  },
  {
   "path": "src/interfaces/mining.h",
   "add": 15,
   "del": 0
  },
  {
   "path": "src/ipc/capnp/mining.capnp",
   "add": 5,
   "del": 0
  },
  {
   "path": "src/node/block_template_manager.cpp",
   "add": 355,
   "del": 0
  },
  {
   "path": "src/node/block_template_manager.h",
   "add": 139,
   "del": 0
  },
  {
   "path": "src/node/context.cpp",
   "add": 1,
   "del": 1
  },
  {
   "path": "src/node/context.h",
   "add": 3,
   "del": 11
  },
  {
   "path": "src/node/interfaces.cpp",
   "add": 29,
   "del": 26
  },
  {
   "path": "src/node/miner.cpp",
   "add": 0,
   "del": 243
  },
  {
   "path": "src/node/miner.h",
   "add": 0,
   "del": 58
  },
  {
   "path": "src/private_broadcast.h",
   "add": 1,
   "del": 7
  },
  {
   "path": "src/rpc/blockchain.cpp",
   "add": 15,
   "del": 16
  },
  {
   "path": "src/rpc/mining.cpp",
   "add": 36,
   "del": 38
  },
  {
   "path": "src/rpc/server_util.cpp",
   "add": 4,
   "del": 4
  },
  {
   "path": "src/rpc/server_util.h",
   "add": 2,
   "del": 4
  },
  {
   "path": "src/test/fuzz/CMakeLists.txt",
   "add": 1,
   "del": 0
  },
  {
   "path": "src/test/fuzz/block_template_manager.cpp",
   "add": 347,
   "del": 0
  },
  {
   "path": "src/test/fuzz/connect_block.cpp",
   "add": 3,
   "del": 0
  },
  {
   "path": "src/test/fuzz/private_broadcast.cpp",
   "add": 1,
   "del": 7
  },
  {
   "path": "src/test/fuzz/rpc.cpp",
   "add": 4,
   "del": 4
  },
  {
   "path": "src/test/fuzz/utxo_snapshot.cpp",
   "add": 3,
   "del": 0
  },
  {
   "path": "src/test/miner_tests.cpp",
   "add": 20,
   "del": 6
  },
  {
   "path": "src/test/peerman_tests.cpp",
   "add": 5,
   "del": 4
  },
  {
   "path": "src/test/util/mining.cpp",
   "add": 9,
   "del": 8
  },
  {
   "path": "src/test/util/setup_common.cpp",
   "add": 15,
   "del": 8
  },
  {
   "path": "src/test/util/setup_common.h",
   "add": 4,
   "del": 0
  },
  {
   "path": "src/test/util/validation.cpp",
   "add": 3,
   "del": 0
  },
  {
   "path": "src/test/validation_block_tests.cpp",
   "add": 10,
   "del": 9
  },
  {
   "path": "src/test/validation_chainstatemanager_tests.cpp",
   "add": 3,
   "del": 0
  },
  {
   "path": "src/util/hasher.h",
   "add": 16,
   "del": 0
  },
  {
   "path": "src/wallet/test/fuzz/fees.cpp",
   "add": 3,
   "del": 0
  },
  {
   "path": "test/functional/interface_ipc_mining.py",
   "add": 25,
   "del": 0
  }
 ],
 "test_lines": 504,
 "git": {
  "head": "1647b291ccae0c0c5c79f0117adcbb0d73231221",
  "head_matches_backup": true,
  "base": "17817818da3cb67c95320b7a5d4d69bd649c1fbf",
  "commits": [
   {
    "sha": "482a5d2712",
    "subject": "node: introduce BlockTemplateManager",
    "files": 13,
    "add": 110,
    "del": 0
   },
   {
    "sha": "bcdadf2b71",
    "subject": "node: move mining_args to BlockTemplateManager",
    "files": 8,
    "add": 28,
    "del": 23
   },
   {
    "sha": "07964c525d",
    "subject": "miner: move SubmitBlock into BlockTemplateManager",
    "files": 5,
    "add": 79,
    "del": 70
   },
   {
    "sha": "037d3519f2",
    "subject": "node: move tip and wait helpers into BlockTemplateManager",
    "files": 7,
    "add": 250,
    "del": 253
   },
   {
    "sha": "400ac328c9",
    "subject": "interfaces: create block template via BlockTemplateManager",
    "files": 3,
    "add": 8,
    "del": 13
   },
   {
    "sha": "011cbfbcd2",
    "subject": "rpc: route getblocktemplate internals through node",
    "files": 5,
    "add": 28,
    "del": 6
   },
   {
    "sha": "0998c0bbdf",
    "subject": "rpc: build getblocktemplate via BlockTemplateManager",
    "files": 1,
    "add": 6,
    "del": 7
   },
   {
    "sha": "951fac807d",
    "subject": "rpc: do not copy template data in getblocktemplate",
    "files": 1,
    "add": 5,
    "del": 5
   },
   {
    "sha": "38556f817e",
    "subject": "rpc: only copy the header in getblocktemplate",
    "files": 1,
    "add": 11,
    "del": 11
   },
   {
    "sha": "8372721f20",
    "subject": "rpc: build generation templates via BlockTemplateManager",
    "files": 2,
    "add": 11,
    "del": 14
   },
   {
    "sha": "ec4f24ef18",
    "subject": "rpc: wait for tips via BlockTemplateManager",
    "files": 2,
    "add": 18,
    "del": 19
   },
   {
    "sha": "6c71166bcf",
    "subject": "test: create templates via BlockTemplateManager",
    "files": 6,
    "add": 32,
    "del": 32
   },
   {
    "sha": "ffe3a631f3",
    "subject": "node: remove NodeContext::mining and EnsureMining",
    "files": 5,
    "add": 0,
    "del": 21
   },
   {
    "sha": "3d7d190b69",
    "subject": "ci: enforce iwyu for block template manager",
    "files": 1,
    "add": 1,
    "del": 1
   },
   {
    "sha": "e8b283c35a",
    "subject": "test: fuzz BlockTemplateManager",
    "files": 2,
    "add": 330,
    "del": 0
   },
   {
    "sha": "f9d9aac99a",
    "subject": "refactor: move CTransactionRefComp to util/hasher",
    "files": 3,
    "add": 9,
    "del": 14
   },
   {
    "sha": "4b10fc327f",
    "subject": "mining: track non-mempool memory usage",
    "files": 5,
    "add": 76,
    "del": 1
   },
   {
    "sha": "063ae8400a",
    "subject": "mining: add GetTemplateMemoryUsage()",
    "files": 3,
    "add": 61,
    "del": 0
   },
   {
    "sha": "1647b291cc",
    "subject": "ipc: add getMemoryLoad()",
    "files": 4,
    "add": 51,
    "del": 0
   }
  ],
  "patch_truncated": true
 },
 "input_hash": "75fc67876d2bb30b",
 "extracted_at": "2026-09-17T16:15:31+00:00"
}