Skip to content

backport: Merge bitcoin/bitcoin#26326: net: don't lock cs_main while reading blocks#7350

Merged
PastaPastaPasta merged 1 commit into
dashpay:developfrom
thepastaclaw:fix/getblocktxn-recent-disk-read
Jul 7, 2026
Merged

backport: Merge bitcoin/bitcoin#26326: net: don't lock cs_main while reading blocks#7350
PastaPastaPasta merged 1 commit into
dashpay:developfrom
thepastaclaw:fix/getblocktxn-recent-disk-read

Conversation

@thepastaclaw

@thepastaclaw thepastaclaw commented Jun 9, 2026

Copy link
Copy Markdown

backport: Merge bitcoin#26326

Upstream backport

This PR backports bitcoin#26326:

Issue being fixed or feature implemented

Block-serving paths in net_processing were doing disk reads while holding cs_main. A peer can request blocks or block transactions repeatedly, so disk I/O should not extend the validation/global chain lock hold time.

What was done?

  • Capture the requested block's disk position while holding cs_main.
  • Release cs_main before reading the block from disk.
  • Preserve the upstream GETBLOCKTXN invariant that recent blocks cannot be pruned before the post-lock disk read.
  • Apply the sibling upstream ProcessGetBlockData behavior: if the post-lock disk read fails because the block was pruned or cannot be loaded, log the condition, disconnect the peer, and return instead of asserting.
  • Capture CanDirectFetch() and the current tip while holding cs_main and use those cached values after the disk read.

Dash note: upstream Bitcoin also has a witness-block raw-data fast path in ProcessGetBlockData; Dash does not have the corresponding MSG_WITNESS_BLOCK path here, so this backport adapts the shared full, filtered, and compact block-serving path.

Backport prerequisite notes

How Has This Been Tested?

Tested on macOS arm64.

  • git diff --check upstream/develop...HEAD
  • test/lint/lint-whitespace.py
  • ./autogen.sh
  • ./configure --without-gui --disable-bench --disable-fuzz-binary
  • make -j$(sysctl -n hw.ncpu) src/dashd

Breaking Changes

None.

Checklist

  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have added or updated relevant unit/integration/functional/e2e tests
  • I have made corresponding changes to the documentation
  • I have assigned this pull request to a milestone

@thepastaclaw

Copy link
Copy Markdown
Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jun 9, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai

coderabbitai Bot commented Jun 9, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

This PR adds a compile-time check that MAX_BLOCKTXN_DEPTH does not exceed MIN_BLOCKS_TO_KEEP. It also updates ProcessGetBlockData and GETBLOCKTXN handling to read deep blocks from stored disk positions, verify the returned hash matches the requested block hash, and use the computed tip state for compact-block and continuation-inventory handling.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Peer
  participant NetProcessing
  participant Chainstate
  participant Disk
  Peer->>NetProcessing: request block data
  NetProcessing->>Chainstate: get tip, block position, direct-fetch state
  NetProcessing->>Disk: ReadBlockFromDisk(block_pos)
  Disk-->>NetProcessing: block data
  NetProcessing->>NetProcessing: compare returned hash to requested hash
  NetProcessing-->>Peer: serve block response or disconnect
Loading

Possibly related PRs

  • dashpay/dash#7398: Changes overlap with src/net_processing.cpp compact-block and GETBLOCKTXN block-serving logic, including disk/block hash verification.

Suggested reviewers: knst, PastaPastaPasta, UdjinM6

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title clearly summarizes the main change as a backport fixing cs_main lock scope during block reads.
Description check ✅ Passed The description is directly about the same backport and explains the block-serving lock-scope changes in detail.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions

github-actions Bot commented Jun 9, 2026

Copy link
Copy Markdown

✅ No Merge Conflicts Detected

This PR currently has no conflicts with other open PRs.

@thepastaclaw thepastaclaw force-pushed the fix/getblocktxn-recent-disk-read branch from 6440dea to 97af883 Compare June 9, 2026 02:38
@thepastaclaw

thepastaclaw commented Jun 9, 2026

Copy link
Copy Markdown
Author

✅ Review complete (commit bd3446f)

@thepastaclaw thepastaclaw marked this pull request as ready for review June 9, 2026 04:52

@thepastaclaw thepastaclaw left a comment

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

Targeted change narrows the cs_main hold window in GETBLOCKTXN by capturing the block file position under the lock and performing the disk read outside it, with a hash check that fails closed on stale/pruned/mismatched reads. Both agents concur the change is correct; only a minor log-granularity nitpick remains.

💬 1 nitpick(s)

Comment thread src/net_processing.cpp Outdated
@PastaPastaPasta

Copy link
Copy Markdown
Member

Is this not code we inherited from bitcoin? it is rare we want to accept a "fix" in their code.

@thepastaclaw

Copy link
Copy Markdown
Author

Good question. I checked this against upstream Bitcoin: the change is actually bringing this path back in line with the current inherited Bitcoin pattern, not inventing a Dash-only behavior.

Bitcoin master already copies the recent block position under cs_main, releases the lock, then reads the block from disk outside cs_main and serves BLOCKTXN. This PR does the same for Dash, with the Dash-local ReadBlockFromDisk API/hash check shape.

So I agree with the general rule — we should be cautious about “fixing” inherited Bitcoin code — but in this case the safer path is to follow the upstream Bitcoin fix rather than keep Dash on the older wider-lock version.

@PastaPastaPasta

Copy link
Copy Markdown
Member

@thepastaclaw

Bitcoin master already copies the recent block position under cs_main, releases the lock, then reads the block from disk outside cs_main and serves BLOCKTXN. This PR does the same for Dash, with the Dash-local ReadBlockFromDisk API/hash check shape.

Hmm; it seems then, that there may be a backport that we should backport instead of doing this adhoc?

@thepastaclaw

Copy link
Copy Markdown
Author

Yep — I traced it more precisely and there is an exact upstream Bitcoin commit for this:

That commit adds the same MAX_BLOCKTXN_DEPTH <= MIN_BLOCKS_TO_KEEP assertion and moves the GETBLOCKTXN disk read out from under cs_main. This PR is effectively that backport adapted to Dash's current ReadBlockFromDisk shape / block hash validation.

So I agree with your process concern: this should be treated as a Bitcoin backport, not as an ad-hoc Dash-only fix. If you prefer, I can close this PR and re-run it through the normal backport flow; otherwise I can update the PR metadata/commit message to explicitly cite the upstream commit.

@github-actions

Copy link
Copy Markdown

This pull request has conflicts, please rebase.

@thepastaclaw thepastaclaw force-pushed the fix/getblocktxn-recent-disk-read branch from 97af883 to c6ccbc6 Compare June 27, 2026 12:04
@github-actions

Copy link
Copy Markdown

This pull request has conflicts, please rebase.

@thepastaclaw

Copy link
Copy Markdown
Author

Rebased this onto current develop and pushed c6ccbc6. GitHub now reports the PR branch as mergeable and predict_conflicts passed. The remaining check_merge failure is the repository-level master/develop fast-forward check, not a conflict in this PR branch.

@thepastaclaw thepastaclaw left a comment

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

Cumulative review at c6ccbc6: the GETBLOCKTXN lock-scope reduction is correct — FlatFilePos is captured under cs_main, disk I/O runs lock-free, and the post-read hash check fails closed on stale/mismatched reads. No new in-scope defects in the latest delta. Carrying forward the prior nitpick about the log message conflating read failure with hash mismatch (already tracked in an unresolved inline thread).

💬 1 nitpick(s)

Note: GitHub does not allow me to submit APPROVE on my own PR, so this is posted as a COMMENT while preserving the verified non-blocking findings.

Comment thread src/net_processing.cpp Outdated
Comment on lines 4495 to 4497
if (!hash || *hash != req.blockhash) {
LogPrint(BCLog::NET, "Peer %d sent us a getblocktxn for a block we could not read\n", pfrom.GetId());
return;

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💬 Nitpick: Log line conflates disk read failure with hash mismatch

After cs_main is released, two operationally distinct failures share one log line: ReadBlockFromDisk returning std::nullopt (OpenBlockFile failure, deserialization error, PoW header check failure — typically pruning or corruption) and a successful read whose *hash != req.blockhash (the FlatFilePos captured under cs_main no longer points at the requested block, e.g. a race with reorg/prune/reindex in the very window this PR introduces). Splitting these into two messages would make the new lock-scope reduction easier to diagnose if it surfaces in the wild. Purely diagnostic quality; behavior is correct. Existing unresolved thread: #7350 (comment).

source: ['claude', 'codex']

@PastaPastaPasta

Copy link
Copy Markdown
Member

Claw; please update this to actually be a backport, if it should so be instead of an adhoc change that doesn't accomplish / get shown in history as a backport

@thepastaclaw thepastaclaw force-pushed the fix/getblocktxn-recent-disk-read branch from c6ccbc6 to 037d040 Compare June 27, 2026 14:03
@thepastaclaw thepastaclaw changed the title fix: reduce GETBLOCKTXN disk read lock scope backport: partial Merge bitcoin/bitcoin#26326: net: reduce LOCK(cs_main) scope in GETBLOCKTXN Jun 27, 2026
@thepastaclaw

Copy link
Copy Markdown
Author

Updated. I amended the PR head so the commit history now records this as a partial backport of bitcoin#26326, specifically bitcoin/bitcoin@613a45c (net: reduce LOCK(cs_main) scope in GETBLOCKTXN). I also updated the PR title/body to make the backport source explicit. The tree is unchanged from the previously reviewed/rebased head; this push is metadata/history only.

@thepastaclaw thepastaclaw left a comment

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

Cumulative review at 037d040. Source tree is unchanged from c6ccbc6; the push only rewrote commit metadata into proper Dash partial-backport form. The GETBLOCKTXN lock-scope reduction is correct: FlatFilePos captured under cs_main, disk read runs lock-free, post-read hash check fails closed on mismatch/missing/pruned. Only carried-forward finding is a low-confidence log-diagnostic nitpick about line 4496 conflating two distinct failure modes.

💬 1 nitpick(s)

Carried-forward findings already raised (1)

These findings were not re-posted as new inline comments because an existing review thread already covers them.

  • [NITPICK] (deduped existing open thread) src/net_processing.cpp:4495-4497: Log message conflates I/O failure with hash mismatch — Two operationally distinct failures share one log message: ReadBlockFromDisk returning std::nullopt (OpenBlockFile failure, deserialization error, PoW header check failure — typically pruning/corruption) and a successful read whose *hash != req.blockhash (the FlatFilePos captured under cs_m...

Note: GitHub does not allow me to approve my own PR, so this is posted as a COMMENT while preserving the verified nonblocking finding.

@thepastaclaw

Copy link
Copy Markdown
Author

@PastaPastaPasta @UdjinM6 this is ready for human Core review. The PR history/title/body now identify it as a partial backport of bitcoin#26326, the branch is mergeable against develop, and predict_conflicts is green. The remaining prior check_merge noise was the repo-level develop -> master fast-forward check, not this PR branch.

@PastaPastaPasta PastaPastaPasta requested a review from knst July 7, 2026 14:31
…blocks

613a45c net: reduce LOCK(cs_main) scope in GETBLOCKTXN (Andrew Toth)

75d27fe net: reduce LOCK(cs_main) scope in ProcessGetBlockData (Andrew Toth)

Pull request description:

  Inspired by bitcoin#11913 and bitcoin#26308.

  cs_main doesn't need to be locked while reading blocks. This removes the locks in net_processing.

Dash notes:

  This backports bitcoin#26326. The upstream witness-block raw-data fast path is not present in Dash, so the ProcessGetBlockData adaptation applies to Dash's existing full, filtered, and compact block serving path.
@thepastaclaw thepastaclaw force-pushed the fix/getblocktxn-recent-disk-read branch from 037d040 to bd3446f Compare July 7, 2026 15:18
@thepastaclaw thepastaclaw changed the title backport: partial Merge bitcoin/bitcoin#26326: net: reduce LOCK(cs_main) scope in GETBLOCKTXN backport: Merge bitcoin/bitcoin#26326: net: don't lock cs_main while reading blocks Jul 7, 2026
@thepastaclaw

thepastaclaw commented Jul 7, 2026

Copy link
Copy Markdown
Author

Updated this into a full backport of bitcoin#26326 instead of the prior partial GETBLOCKTXN-only form. The branch now includes both upstream commits: 613a45c (GETBLOCKTXN) and 75d27fe (ProcessGetBlockData). GETBLOCKTXN now preserves the upstream assert invariant; the log/disconnect behavior is only in the sibling ProcessGetBlockData commit where upstream intentionally made that behavior change.

Validation: git diff --check upstream/develop...HEAD, test/lint/lint-whitespace.py, ./autogen.sh, ./configure --without-gui --disable-bench --disable-fuzz-binary, and make -j$(sysctl -n hw.ncpu) src/dashd.

@thepastaclaw

Copy link
Copy Markdown
Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 7, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@thepastaclaw thepastaclaw left a comment

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

Source: reviewer lanes attempted: opus general/commit-history/backport-reviewer all failed with extra-usage limit (resets Jul 10, 8am America/Chicago); gpt-5.5 general, gpt-5.5 dash-core-commit-history, and gpt-5.5 backport-reviewer completed. Verifier: gpt-5.5 after opus verifier failed with the same usage limit.

Prior reconciliation: the prior 037d040a nitpick about GETBLOCKTXN logging is FIXED at bd3446f6; the shared log branch was removed and the current path asserts hash && *hash == req.blockhash after the captured-position read.

Carried-forward prior findings: none.

New findings in latest delta: one backport-prerequisite finding was reported by the backport reviewer and promoted by the deterministic policy gate. The verifier otherwise found no general correctness or commit-history issues.

Note: posted as a COMMENT review because GitHub does not allow me to submit REQUEST_CHANGES on my own PR; the verified blocking finding is preserved below.

🔴 1 blocking

🤖 Prompt for all review comments with AI agents
These findings are from an automated code review. Verify each finding against the current code and only fix it if needed.

In `src/net_processing.cpp`:
- [BLOCKING] src/net_processing.cpp:2745-2747: Missing prerequisite: bitcoin#27125
  Upstream bitcoin#26326's starting state already had bitcoin#27125's BlockManager disk-read methods, and the upstream changed lines call `m_chainman.m_blockman.ReadBlockFromDisk(*pblockRead, block_pos)` in ProcessGetBlockData and GETBLOCKTXN. Dash's starting state does not have that API; it still exposes namespace-level `node::ReadBlockFromDisk(CBlock&, FlatFilePos, Consensus::Params)` and this backport adapts the changed lines to that older helper. The missing upstream API was introduced by f0bb1021f0 in merge c2f2abd0a4 (`Merge bitcoin/bitcoin#27125: refactor, kernel: Decouple ArgsManager from blockstorage`), which is not an ancestor of this Dash head. This is a soft prerequisite gap: Dash has an equivalent local helper that returns the read block hash, so the conflict resolution looks correct and should preserve the intended post-lock disk-read validation, but the upstream dependency chain is incomplete relative to the modified section.

---
**Policy gate (backport-prereq-restore):** For full upstream backport PRs, a missing prerequisite is blocking unless the finding is explicitly allowlisted (e.g. `intentional_exclusion: true` or a matching entry in `policy_overrides`). The agent's original evidence above is the basis for this block; either backport the prerequisite or annotate the intentional exclusion in the PR description.

@thepastaclaw

Copy link
Copy Markdown
Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 7, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@thepastaclaw

Copy link
Copy Markdown
Author

Follow-up on my self-review note at #7350 (review):

Handled by documenting the prerequisite decision in the PR body under "Backport prerequisite notes":

  • intentional_exclusion: bitcoin/bitcoin#27125

The reason is that upstream bitcoin#26326 uses the BlockManager ReadBlockFromDisk(..., FlatFilePos) API from bitcoin#27125, while Dash already has the local node::ReadBlockFromDisk(CBlock&, FlatFilePos, Consensus::Params) helper returning the read block hash. This PR intentionally adapts the changed lines to that existing Dash helper and keeps the post-lock hash validation instead of importing the broader bitcoin#27125 BlockManager refactor.

No branch/code change needed for this follow-up; current CI is green.

@knst knst left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM bd3446f

@PastaPastaPasta PastaPastaPasta merged commit f2ae9f0 into dashpay:develop Jul 7, 2026
52 checks passed
@UdjinM6 UdjinM6 added this to the 24 milestone Jul 7, 2026
@thepastaclaw

Copy link
Copy Markdown
Author

CI triage note for the old linux64_ubsan-test failure in run 28288653526: the red test was feature_asset_locks.py timing out while waiting for quorum list propagation in test_v24_fork / mine_quorum_2_nodes. The failing PR head c6ccbc6 changed only src/net_processing.cpp, so the failure was unrelated to this PR's GETBLOCKTXN/block-serving backport. I added this occurrence to the existing flaky-test issue #7310. The later final PR head bd3446f passed linux64_ubsan-test, and the PR is now merged, so no branch change is needed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants