{
 "number": 36244,
 "repo": "bitcoin/bitcoin",
 "url": "https://github.com/bitcoin/bitcoin/pull/36244",
 "title": "validation, net: Process blocks asynchronously and reduce cs_main contention",
 "author": "w0xlt",
 "author_association": "CONTRIBUTOR",
 "created_at": "2026-09-14T07:42:00Z",
 "updated_at": "2026-09-16T07:24:28Z",
 "age_days": 3,
 "draft": true,
 "labels": [],
 "milestone": null,
 "base": "master",
 "head_sha": "5922474112a133138fa377ff1c2ab97d32b0af91",
 "head_ref": "validation/async-block-processing",
 "head_repo": "w0xlt/bitcoin",
 "head_history": [
  {
   "t": "2026-09-14T08:02:30Z",
   "sha": "34d9d3d6ee600198a5520bb9112571cd66b3cd70"
  },
  {
   "t": "2026-09-15T01:11:43Z",
   "sha": "5922474112a133138fa377ff1c2ab97d32b0af91"
  }
 ],
 "additions": 3134,
 "deletions": 294,
 "changed_files": 41,
 "commit_count": 20,
 "size_bucket": "XL",
 "mergeable_state": "clean",
 "bot": {
  "drahtbot": {
   "present": true,
   "reviews": {},
   "conflicts": [
    {
     "number": 36167,
     "title": "[RFC] Enable `-Wunused`",
     "author": "fanquake"
    },
    {
     "number": 36109,
     "title": "test: harden arbitrary-parent block creation",
     "author": "l0rinc"
    },
    {
     "number": 36098,
     "title": "fuzz: add corpus reachability checks",
     "author": "HowHsu"
    },
    {
     "number": 36002,
     "title": "txindex: allow running in pruned mode",
     "author": "andrewtoth"
    },
    {
     "number": 35936,
     "title": "net: reject oversized locators before allocating",
     "author": "l0rinc"
    },
    {
     "number": 35906,
     "title": "First steps towards a stateless, side-effect free validation library",
     "author": "purpleKarrot"
    },
    {
     "number": 35675,
     "title": "mining: add block template manager",
     "author": "ismaelsadeeq"
    },
    {
     "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": 35570,
     "title": "refactor: Change some validation.cpp methods to return BlockValidationState",
     "author": "optout21"
    },
    {
     "number": 35474,
     "title": "node: move index ownership to NodeContext",
     "author": "w0xlt"
    },
    {
     "number": 35229,
     "title": "refactor: Use CBlockIndex parameters as reference",
     "author": "optout21"
    },
    {
     "number": 34520,
     "title": "refactor: Add [[nodiscard]] to functions returning bool+mutable ref",
     "author": "maflcko"
    },
    {
     "number": 34374,
     "title": "kernel: use struct-based logging and simplify logging interface",
     "author": "stickies-v"
    },
    {
     "number": 33922,
     "title": "mining: add getMemoryLoad() and track template non-mempool memory footprint",
     "author": "Sjors"
    },
    {
     "number": 29700,
     "title": "kernel, refactor: return error status on all fatal errors",
     "author": "ryanofsky"
    },
    {
     "number": 28690,
     "title": "build: Introduce internal kernel library",
     "author": "sedited"
    },
    {
     "number": 27052,
     "title": "test: rpc: add last block announcement time to getpeerinfo result",
     "author": "LarryRuane"
    }
   ]
  }
 },
 "acks_parsed": {},
 "acks_tally": {
  "ack": 0,
  "stale_ack": 0,
  "concept_ack": 0,
  "approach_ack": 0,
  "nack": 0,
  "concept_nack": 0,
  "approach_nack": 0
 },
 "reviews": {
  "approved": 0,
  "changes_requested": 0,
  "distinct_reviewers": [
   "andrewtoth"
  ]
 },
 "signals": {
  "needs_rebase": false,
  "ci_failed": false,
  "mergeable_state": "clean",
  "last_author_activity": "2026-09-15T01:30:43Z",
  "last_reviewer_activity": "2026-09-15T00:05:14Z",
  "last_reviewer": "andrewtoth",
  "author_silent_days": 2,
  "waiting_on_author_days": 0,
  "days_since_update": 1
 },
 "refs": {
  "mentioned": [
   16324,
   18963
  ],
  "depends_on": [],
  "fixes": [],
  "linked_issues": [],
  "references": [
   {
    "number": 18963,
    "type": "pull",
    "state": "closed",
    "merged": false,
    "merged_at": null,
    "title": "[WIP] rebase: Call ProcessNewBlock() asynchronously"
   },
   {
    "number": 16324,
    "type": "pull",
    "state": "closed",
    "merged": false,
    "merged_at": null,
    "title": "Get cs_main out of the critical path in ProcessMessages"
   }
  ],
  "conflicts": [
   36167,
   36109,
   36098,
   36002,
   35936,
   35906,
   35675,
   35671,
   35646,
   35581,
   35570,
   35474,
   35229,
   34520,
   34374,
   33922,
   29700,
   28690,
   27052
  ]
 },
 "stack": {
  "shares_commits_with": [],
  "based_on": [],
  "base_for": []
 },
 "review_paths": [],
 "body": "The shared P2P message thread currently waits for block processing to finish before it can process messages from other peers.\n\nThis PR moves block processing to a dedicated worker after the initial checks, following the approach of #18963 and #16324:\n\n- Initial checks still run on the P2P message thread and decide whether a block should enter the processing queue.\n- A single worker processes queued blocks one at a time, in the order they are added to the queue.\n- Each peer can have only one block queued or being processed at a time. The node handles the processing result and any required peer penalties before processing that peer\u2019s next incoming message.\n- Tracking block requests and reconstructing blocks from compact-block transaction responses no longer require `cs_main`, the chain lock.\n- When `cs_main` is busy, `SendMessages()` defers work such as requesting headers, blocks or transactions and announcing new blocks or transactions. This allows the P2P message thread to move on to other peers.\n\nA controlled 10,000-block IBD benchmark showed these response-time improvements, measured as the median of four per-run medians:\n\n| Probe | Download connections | Baseline \u2192 This branch | Reduction |\n|---|---:|---:|---:|\n| PING/PONG | 1 | 41.8 \u2192 0.77 ms | 98% |\n| Block serving | 1 | 39.0 \u2192 26.5 ms | 32% |\n| Block serving | 4 | 107.0 \u2192 58.5 ms | 45% |\n\nWith four download connections, the median time to download and validate the 10,000 tested blocks during IBD fell by approximately *5%*, from 473.6 s to 450.3 s.\n\nThe comparison used matching Clang 18 Release builds of baseline `4519933391dd` and this branch, mainnet blocks 910,489 - 920,488, one local source node, and `-assumevalid=0 -blocksonly=1`. Each setup ran four times per build. PINGs ran at 10/s; the block probe requested the same previously validated block after warmup, at most once per second, timing receipt of the full block.\n\nThese results apply to this controlled IBD workload; they do not establish gains for other services, hardware, or network conditions. Performance outside IBD was not measured.\n\nTests and test infrastructure account for approximately 67% of the diff. Production code and build integration account for 1,132 changed lines (883 additions and 249 deletions).\n\nI\u2019m opening this PR as a draft primarily to gather feedback on the overall approach.",
 "commits": [
  {
   "sha": "438c40fc5efa1b3bfe2ccf80a2c2423978f0b6b8",
   "date": "2026-09-15T01:07:51Z",
   "message": "validation: Make block check caches atomic\n\nGroup the three successful block-check caches in a CBlock-specific,\nvalue-copyable type. Use atomic loads and stores so immutable blocks can\nbe checked and copied concurrently with independent validation states.\nKeep the payload copy and move operations compiler-generated.\n\nThe bits memoize successful checks; they do not publish payload changes\nor guarantee exactly-once checking. Callers must keep block contents and\neffective consensus parameters unchanged while sharing a block. Copies\nmay observe the independently valid success bits at different times.\n\nKeep the initial ProcessNewBlock lock placement unchanged."
  },
  {
   "sha": "9c80b0d9a1173b4990376e43eb02be6f7e88d4cc",
   "date": "2026-09-15T01:07:51Z",
   "message": "validation: Check blocks before taking cs_main\n\nSerialize the initial CheckBlock call with a private manager mutex and\nrelease it before waiting for cs_main. Keep initial rejection handling\nand synchronous validation notifications under cs_main, with master\nacceptance, storage, import and activation locking unchanged.\n\nThis narrows the initial checking lock; it does not unlock acceptance or\nblock-file writes or promise FIFO acceptance for concurrent callers."
  },
  {
   "sha": "d8caa9be9074faadec31ba080c9b9600d068d036",
   "date": "2026-09-15T01:07:51Z",
   "message": "refactor: Separate block processing completion\n\nSeparate ProcessNewBlock execution from subsequent peer-state updates,\nwhile continuing to call both synchronously at all three submission sites.\n\nKeep processing success distinct from new_block. Only new_block controls\nthe existing timestamp and request housekeeping, including write errors.\nMove optimistic compact reconstruction's additional transaction-valid\nrequest cleanup into the continuation, using a fresh index lookup under\ncs_main. Other submission paths do not gain that cleanup."
  },
  {
   "sha": "08560026f36bc3ab788fa7b78a182ac10c5eab6c",
   "date": "2026-09-15T01:07:51Z",
   "message": "refactor: Extract block storage admission"
  },
  {
   "sha": "7aa04600e3c4d64c50b6be5a7da02327683370b2",
   "date": "2026-09-15T01:07:51Z",
   "message": "refactor: Separate block admission from persistence\n\nMove header acceptance, storage policy, block/contextual checks, and\ninvalid-block handling into PreWriteCheckBlock(). Return admission success\nseparately from whether block data should be stored, distinguishing\nrejections, successful no-ops, and blocks eligible for persistence.\n\nKeep AcceptBlock() responsible for synchronous persistence with its\nexisting locking and new_block semantics. Preserve ProcessNewBlock()'s\ninitial check, notification ordering, and chain activation."
  },
  {
   "sha": "2768e46d4c4b1b7e01dc018097a2188cd139f109",
   "date": "2026-09-15T01:07:51Z",
   "message": "refactor: Extract block persistence\n\nMove block notifications, disk writes, index updates and flushing into\nStoreBlock(), called synchronously by AcceptBlock() after admission.\nPreserve cs_main locking, the existing disk-position import path, and\nnew_block assignment before storage.\n\nThis exposes the persistence stage for reuse by a future validation worker."
  },
  {
   "sha": "2550bfd70d72cbae85698b3b3a498300bd8ba1a8",
   "date": "2026-09-15T01:07:51Z",
   "message": "refactor: Expose initial block validation state\n\nPass a caller-owned BlockValidationState through ProcessNewBlock's\nCheckBlock and AcceptBlock stages, keeping chain-activation states local.\nUpdate callers to supply fresh states while preserving synchronous\nBlockChecked delivery, processing success, and new_block semantics.\n\nCover initial rejection, valid and duplicate submissions, and a block\nthat passes admission but fails validation when connected. This prepares\ncallers to distinguish initial validation results from future completion,\nfollowing the API preparation in PR #18963."
  },
  {
   "sha": "41a4d5b45d0a329d98ae26de160fa074621b0bca",
   "date": "2026-09-15T01:07:51Z",
   "message": "refactor: Return block processing outcomes together\n\nMove BlockProcessingResult from PeerManagerImpl into the validation API\nand return it from ProcessNewBlock instead of returning bool and writing\nnew_block through an output parameter. Update all callers while keeping\nvalidation, notifications, and peer completion synchronous.\n\nPreserve both outcomes independently, including new_block remaining true\non a write failure. Neither field implies full consensus validity.\nExtend the initial-state regression test to check both result fields and\nexercise a real block-file write failure. Capture and assert its expected\nerror notification to keep successful test output clear.\n\nThis prepares the API for a future carrying both completion outcomes."
  },
  {
   "sha": "c63ca2494263e3f657ddcaf1f394fb8ec5dade4a",
   "date": "2026-09-15T01:07:51Z",
   "message": "refactor: Return block processing outcomes through a future\n\nWrap BlockProcessingResult in a future, fulfilling its promise at each\nexisting return. Keep validation synchronous and fulfill successful\ncompletion after active and historical chainstate activation.\n\nUpdate callers to consume the ready future before their existing\ncompletion actions, preserving initial-state reporting, both result\nfields, and notification ordering. Explicitly discard unused test\nresults for libc++ compatibility. Check future validity and immediate\nreadiness in the existing outcome regression scenarios."
  },
  {
   "sha": "e279781dd298f95bdf169af64d337ff73b15e7ad",
   "date": "2026-09-15T01:07:51Z",
   "message": "net: Track pending block processing per peer\n\nRetain completion futures for full blocks, completed compact blocks,\nand optimistic reconstruction. Poll without waiting, pausing new-message\ndequeuing and the normal send loop for the submitting peer while its\ncompletion is pending. Continue servicing previously queued getdata and\norphan work before checking for pending block processing.\n\nKeep records in the peer manager by peer ID and poll them even when no\npeers remain, so download cleanup survives source disconnection. Preserve\nnewer source attribution, check optimistic transaction validity at\ncompletion, and apply punishment before dequeuing another message.\nHandle failed futures without letting exceptions escape the message loop.\n\nAdd controlled-future coverage for peer pause/resumption, queued getdata\nwork, ordinary messages from other peers, disconnection, completion\nordering, and errors. Validation still executes synchronously and returns\nready futures."
  },
  {
   "sha": "d8f943642dddddf6c71a3a108017f1d064216d2b",
   "date": "2026-09-15T01:07:51Z",
   "message": "validation: Add block processing queue\n\nAdd a single-worker FIFO with owned blocks, processing callbacks, and\ncompletion futures. Accept submissions while running and complete futures\nwith either a result or the callback's exception. Report inactive or\nstopping queues without retaining the submitted work.\n\nMake ChainstateManager own the queue. Support explicit startup, interruption,\nand draining shutdown, and stop before node and test dependencies are\nremoved. Keep the kernel context alive throughout manager destruction.\nMove BlockProcessingResult into the queue header without changing its API.\n\nAdd tests covering lifecycle, ownership, exceptions, FIFO processing,\nconcurrent producers and shutdown, and callback submission. Production\nstartup leaves the worker inactive and ProcessNewBlock remains synchronous;\nvalidation admission, worker processing, and completion wakeups follow\nseparately."
  },
  {
   "sha": "6a3c026472a27bf1ded7a3ab2b3b56bf60ceeeb5",
   "date": "2026-09-15T01:07:51Z",
   "message": "net: Account for blocks pending processing\n\nExclude received blocks awaiting processing completion from automatic\ndownload selection and compact-block reconstruction. Avoid attributing\ndownload stalls to peers when local processing holds back or advances the\ndownload window."
  },
  {
   "sha": "1482d026883f9baab136d706b2b27860c413327c",
   "date": "2026-09-15T01:07:51Z",
   "message": "validation: Route admitted blocks through the processing queue\n\nRun initial validation and admission on the caller, then submit blocks needing\nstorage for persistence and chain activation. Retain inline execution before\nthe queue is started for kernel, fuzz, and other standalone callers.\n\nReturn initial errors directly and deferred cached-invalid outcomes through the\nfuture so peer attribution remains tied to each submission. Notify listeners\nwhen completions become available and adapt blocking callers to the split\nresult contract."
  },
  {
   "sha": "5e80fc10b1d1021e5caacc1965be96569ff6e72c",
   "date": "2026-09-15T01:07:51Z",
   "message": "validation: Process admitted blocks on a worker\n\nStart the block-processing queue during node and ordinary test setup. Keep fuzz\nand kernel callers on the inline path, and stop the worker before its callback,\nnetworking, mempool, and index dependencies are destroyed.\n\nAdd coverage for queued parent invalidation, duplicate rejection attribution,\npending downloads and stalling, disconnected sources, and worker-gate and\nsubscriber lifetimes."
  },
  {
   "sha": "29c606c8189e295c874867868370e9a29a60fea5",
   "date": "2026-09-15T01:07:51Z",
   "message": "validation: Queue BlockChecked notifications\n\nDeliver BlockChecked through the validation task runner, retaining the\nblock and validation state until delivery. Keep peer completions pending\nuntil a queued marker has run so validation feedback precedes source\ncleanup and message processing resumption.\n\nWait for queued results before unregistering mining catchers. Adapt the\nnetwork fuzz targets to a scoped scheduler and serial runner, with\nexplicit callback and completion draining between messages, so callbacks\ncan acquire cs_main without blocking the emitter under that lock.\n\nCover queued ownership, callback ordering, peer teardown, and the fuzz\nrunner's deferred delivery."
  },
  {
   "sha": "6bdf4d1023e740c3b474d75673f88a42a4eb20a1",
   "date": "2026-09-15T01:07:51Z",
   "message": "net: Protect block sources with a dedicated mutex\n\nMove mapBlockSource from cs_main to a PeerManager bookkeeping mutex,\nfollowing the source-attribution change in PR #18963. Source insertion and\nordinary completion cleanup can run while validation holds cs_main.\n\nAcquire cs_main before the new mutex where chain state is also needed,\nmatching the modern PeerManager lock order. Preserve source ownership,\ncompact-block punishment exceptions, and callback ordering. Add a\nregression that completes source cleanup while another thread holds\ncs_main."
  },
  {
   "sha": "3cc92b706ee15c8bd4cee88f035f5fe66f3c5cce",
   "date": "2026-09-15T01:07:51Z",
   "message": "net: Move block download tracking into Peer\n\nMove per-peer in-flight blocks and download/stalling timers out of\nCNodeState, following PR #16324. Protect them, mapBlocksInFlight, and the\ndownloading-peer count with the block bookkeeping mutex.\n\nSerialize request registration and cleanup with peer removal, retaining\nthe Peer until its request entries are cleared. Keep cs_main for chain\ndependent reads and preserve request selection, limits, and timeouts.\n\nWhen new_block is true, skip the redundant optimistic validity recheck\nand its chain-lock acquisition after request cleanup. Retain the recheck\nfor completions with new_block=false.\n\nAdd a regression that registers and completes requests for both full\nblocks and optimistic reconstructions while another thread holds\ncs_main. Freeze its node clock so the completion timestamp assertion\ncannot race a wall-clock second boundary."
  },
  {
   "sha": "db1c6c303d189930d285aa34cc0ad44f5831ff12",
   "date": "2026-09-15T01:07:51Z",
   "message": "net: Avoid unnecessary cs_main waits in message processing\n\nSkip taking the chain lock when a peer has no orphan transactions to\nreconsider. Defer the remaining send work when cs_main is unavailable so\nthe shared message handler can service other peers.\n\nKeep fee-filter calculation inside the successful chain-lock scope so\nblock validation cannot acquire the mempool lock before the calculation.\nRequire cs_main in the helper's lock annotation.\n\nAdd a regression covering PING/PONG output, punishment, and deferred\nheader requests while another thread holds cs_main."
  },
  {
   "sha": "82385fb3c230976f942ccbdd675d1409826a7ade",
   "date": "2026-09-15T01:07:51Z",
   "message": "net: Remove cs_main from blocktxn reconstruction\n\nUse the validated header already stored with the download request to\ndetermine SegWit activation. This lets BLOCKTXN bookkeeping and\nreconstruction proceed under m_block_mutex while another block is being\nvalidated. Release the lock before the existing admission checks.\n\nAdd a regression covering unexpected responses and reconstruction\nfailures while another thread holds cs_main, including full-block\nfallback."
  },
  {
   "sha": "5922474112a133138fa377ff1c2ab97d32b0af91",
   "date": "2026-09-15T01:07:51Z",
   "message": "net: Clear optimistic block requests after admission\n\nClear other peers' requests after successful initial admission of an\noptimistically reconstructed compact block, following #16324. Pending\nprocessing still suppresses automatic downloads and pauses the source\nuntil its completion and validation callbacks have been handled.\n\nRemove the optimistic flag from pending completions and the remaining\ncompletion-time validity recheck under cs_main. Cover admission with a\nparked worker, queued duplicates, source disconnection, initial rejection,\nand interrupted submission.\n\nValidation: 41 unit tests passed in regular and ThreadSanitizer builds;\nsix compact-block, invalid-block and unrequested-block functional tests\npassed."
  }
 ],
 "timeline": [
  {
   "t": "2026-09-14T08:02:30Z",
   "kind": "force_push",
   "who": "w0xlt",
   "commit": "34d9d3d6ee600198a5520bb9112571cd66b3cd70"
  },
  {
   "t": "2026-09-15T00:05:14Z",
   "kind": "comment",
   "who": "andrewtoth",
   "assoc": "MEMBER",
   "text": "The PR description describes IBD speedup. But, wouldn't the point of something like this be that we could process messages while validating at steady-state, so a block that takes a long time to validate does not hold up responding to compact block transaction requests or other messages? And eventually we could also process competing sibling blocks in parallel?"
  },
  {
   "t": "2026-09-15T01:11:43Z",
   "kind": "force_push",
   "who": "w0xlt",
   "commit": "5922474112a133138fa377ff1c2ab97d32b0af91"
  },
  {
   "t": "2026-09-15T01:30:43Z",
   "kind": "comment",
   "who": "w0xlt",
   "assoc": "CONTRIBUTOR",
   "text": "@andrewtoth Yes, keeping other peers responsive during block validation, including at the tip, is the main motivation. I used IBD as a repeatable workload with sustained validation to measure that benefit. The shorter IBD time was a secondary observation; the main measured gains were faster PING/PONG and block-serving responses, as shown in the table.\n\nYour compact-block example fits. `getblocktxn` already has a path that serves missing transactions from the recent block cache without taking `cs_main`. This PR moves block processing onto a separate worker, allowing that handler to respond to other peers while validation continues. Other handlers that need `cs_main` can still wait.\n\nParallel validation of competing sibling blocks would require further work on shared chainstate and synchronization. This PR keeps a single worker processing blocks serially.\n\nI see this separation of networking and block processing, along with fewer unnecessary waits for cs_main, as a starting point for further concurrency improvements."
  }
 ],
 "labels_log": [
  {
   "t": "2026-09-14T15:47:46Z",
   "action": "labeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  },
  {
   "t": "2026-09-15T02:53:24Z",
   "action": "unlabeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  }
 ],
 "state_log": [
  {
   "t": "2026-09-14T12:25:47Z",
   "kind": "convert_to_draft",
   "who": "w0xlt"
  }
 ],
 "text_chars": 15356,
 "text_tokens_estimate": 3839,
 "changed_paths": [
  "src/CMakeLists.txt",
  "src/bench/blockencodings.cpp",
  "src/blockencodings.h",
  "src/init.cpp",
  "src/kernel/CMakeLists.txt",
  "src/kernel/bitcoinkernel.cpp",
  "src/kernel/chainstatemanager_opts.h",
  "src/net.cpp",
  "src/net.h",
  "src/net_processing.cpp",
  "src/net_processing.h",
  "src/node/miner.cpp",
  "src/primitives/block.h",
  "src/rpc/mining.cpp",
  "src/test/CMakeLists.txt",
  "src/test/baseindex_tests.cpp",
  "src/test/blockfilter_index_tests.cpp",
  "src/test/coinstatsindex_tests.cpp",
  "src/test/fuzz/cmpctblock.cpp",
  "src/test/fuzz/process_messages.cpp",
  "src/test/fuzz/util/net.h",
  "src/test/peerman_tests.cpp",
  "src/test/txindex_tests.cpp",
  "src/test/txospenderindex_tests.cpp",
  "src/test/util/mining.cpp",
  "src/test/util/net.h",
  "src/test/util/setup_common.cpp",
  "src/test/util/validation.cpp",
  "src/test/util/validation.h",
  "src/test/validation_block_tests.cpp",
  "src/test/validation_chainstate_tests.cpp",
  "src/test/validation_chainstatemanager_tests.cpp",
  "src/test/validation_queue_tests.cpp",
  "src/test/validation_tests.cpp",
  "src/test/validationinterface_tests.cpp",
  "src/validation.cpp",
  "src/validation.h",
  "src/validation_queue.cpp",
  "src/validation_queue.h",
  "src/validationinterface.cpp",
  "src/validationinterface.h"
 ],
 "files": [
  {
   "path": "src/CMakeLists.txt",
   "add": 1,
   "del": 0
  },
  {
   "path": "src/bench/blockencodings.cpp",
   "add": 4,
   "del": 2
  },
  {
   "path": "src/blockencodings.h",
   "add": 10,
   "del": 4
  },
  {
   "path": "src/init.cpp",
   "add": 6,
   "del": 0
  },
  {
   "path": "src/kernel/CMakeLists.txt",
   "add": 1,
   "del": 0
  },
  {
   "path": "src/kernel/bitcoinkernel.cpp",
   "add": 16,
   "del": 7
  },
  {
   "path": "src/kernel/chainstatemanager_opts.h",
   "add": 1,
   "del": 0
  },
  {
   "path": "src/net.cpp",
   "add": 2,
   "del": 0
  },
  {
   "path": "src/net.h",
   "add": 3,
   "del": 0
  },
  {
   "path": "src/net_processing.cpp",
   "add": 320,
   "del": 144
  },
  {
   "path": "src/net_processing.h",
   "add": 6,
   "del": 0
  },
  {
   "path": "src/node/miner.cpp",
   "add": 21,
   "del": 15
  },
  {
   "path": "src/primitives/block.h",
   "add": 37,
   "del": 7
  },
  {
   "path": "src/rpc/mining.cpp",
   "add": 14,
   "del": 6
  },
  {
   "path": "src/test/CMakeLists.txt",
   "add": 1,
   "del": 0
  },
  {
   "path": "src/test/baseindex_tests.cpp",
   "add": 6,
   "del": 1
  },
  {
   "path": "src/test/blockfilter_index_tests.cpp",
   "add": 10,
   "del": 3
  },
  {
   "path": "src/test/coinstatsindex_tests.cpp",
   "add": 2,
   "del": 0
  },
  {
   "path": "src/test/fuzz/cmpctblock.cpp",
   "add": 11,
   "del": 1
  },
  {
   "path": "src/test/fuzz/process_messages.cpp",
   "add": 11,
   "del": 1
  },
  {
   "path": "src/test/fuzz/util/net.h",
   "add": 2,
   "del": 0
  },
  {
   "path": "src/test/peerman_tests.cpp",
   "add": 1229,
   "del": 2
  },
  {
   "path": "src/test/txindex_tests.cpp",
   "add": 5,
   "del": 0
  },
  {
   "path": "src/test/txospenderindex_tests.cpp",
   "add": 2,
   "del": 0
  },
  {
   "path": "src/test/util/mining.cpp",
   "add": 11,
   "del": 8
  },
  {
   "path": "src/test/util/net.h",
   "add": 7,
   "del": 0
  },
  {
   "path": "src/test/util/setup_common.cpp",
   "add": 5,
   "del": 1
  },
  {
   "path": "src/test/util/validation.cpp",
   "add": 103,
   "del": 0
  },
  {
   "path": "src/test/util/validation.h",
   "add": 71,
   "del": 6
  },
  {
   "path": "src/test/validation_block_tests.cpp",
   "add": 272,
   "del": 7
  },
  {
   "path": "src/test/validation_chainstate_tests.cpp",
   "add": 3,
   "del": 1
  },
  {
   "path": "src/test/validation_chainstatemanager_tests.cpp",
   "add": 1,
   "del": 0
  },
  {
   "path": "src/test/validation_queue_tests.cpp",
   "add": 319,
   "del": 0
  },
  {
   "path": "src/test/validation_tests.cpp",
   "add": 3,
   "del": 3
  },
  {
   "path": "src/test/validationinterface_tests.cpp",
   "add": 167,
   "del": 3
  },
  {
   "path": "src/validation.cpp",
   "add": 144,
   "del": 60
  },
  {
   "path": "src/validation.h",
   "add": 79,
   "del": 9
  },
  {
   "path": "src/validation_queue.cpp",
   "add": 120,
   "del": 0
  },
  {
   "path": "src/validation_queue.h",
   "add": 88,
   "del": 0
  },
  {
   "path": "src/validationinterface.cpp",
   "add": 13,
   "del": 3
  },
  {
   "path": "src/validationinterface.h",
   "add": 7,
   "del": 0
  }
 ],
 "test_lines": 2284,
 "git": {
  "head": "5922474112a133138fa377ff1c2ab97d32b0af91",
  "head_matches_backup": true,
  "base": "51ddab532cb38213e2258c24c492bc8a392ffc90",
  "commits": [
   {
    "sha": "438c40fc5e",
    "subject": "validation: Make block check caches atomic",
    "files": 8,
    "add": 74,
    "del": 32
   },
   {
    "sha": "9c80b0d9a1",
    "subject": "validation: Check blocks before taking cs_main",
    "files": 2,
    "add": 13,
    "del": 4
   },
   {
    "sha": "d8caa9be90",
    "subject": "refactor: Separate block processing completion",
    "files": 1,
    "add": 41,
    "del": 21
   },
   {
    "sha": "08560026f3",
    "subject": "refactor: Extract block storage admission",
    "files": 2,
    "add": 36,
    "del": 21
   },
   {
    "sha": "7aa04600e3",
    "subject": "refactor: Separate block admission from persistence",
    "files": 2,
    "add": 37,
    "del": 9
   },
   {
    "sha": "2768e46d4c",
    "subject": "refactor: Extract block persistence",
    "files": 2,
    "add": 20,
    "del": 0
   },
   {
    "sha": "2550bfd70d",
    "subject": "refactor: Expose initial block validation state",
    "files": 13,
    "add": 136,
    "del": 23
   },
   {
    "sha": "41a4d5b45d",
    "subject": "refactor: Return block processing outcomes together",
    "files": 13,
    "add": 84,
    "del": 65
   },
   {
    "sha": "c63ca24942",
    "subject": "refactor: Return block processing outcomes through a future",
    "files": 13,
    "add": 62,
    "del": 35
   },
   {
    "sha": "e279781dd2",
    "subject": "net: Track pending block processing per peer",
    "files": 7,
    "add": 397,
    "del": 17
   },
   {
    "sha": "d8f943642d",
    "subject": "validation: Add block processing queue",
    "files": 14,
    "add": 517,
    "del": 10
   },
   {
    "sha": "6a3c026472",
    "subject": "net: Account for blocks pending processing",
    "files": 1,
    "add": 27,
    "del": 6
   },
   {
    "sha": "1482d02688",
    "subject": "validation: Route admitted blocks through the processing queue",
    "files": 15,
    "add": 382,
    "del": 111
   },
   {
    "sha": "5e80fc10b1",
    "subject": "validation: Process admitted blocks on a worker",
    "files": 14,
    "add": 689,
    "del": 8
   },
   {
    "sha": "29c606c818",
    "subject": "validation: Queue BlockChecked notifications",
    "files": 14,
    "add": 354,
    "del": 34
   },
   {
    "sha": "6bdf4d1023",
    "subject": "net: Protect block sources with a dedicated mutex",
    "files": 2,
    "add": 49,
    "del": 27
   },
   {
    "sha": "3cc92b706e",
    "subject": "net: Move block download tracking into Peer",
    "files": 2,
    "add": 148,
    "del": 88
   },
   {
    "sha": "db1c6c303d",
    "subject": "net: Avoid unnecessary cs_main waits in message processing",
    "files": 2,
    "add": 106,
    "del": 8
   },
   {
    "sha": "82385fb3c2",
    "subject": "net: Remove cs_main from blocktxn reconstruction",
    "files": 2,
    "add": 82,
    "del": 6
   },
   {
    "sha": "5922474112",
    "subject": "net: Clear optimistic block requests after admission",
    "files": 3,
    "add": 176,
    "del": 65
   }
  ],
  "patch_truncated": true
 },
 "input_hash": "1baf905440535b42",
 "extracted_at": "2026-09-17T16:15:31+00:00"
}