Skip to content

consensus: decide header and block rules without opening the store - #1055

Merged
reardencode merged 12 commits into
masterfrom
consensus/off-store
Oct 17, 2026
Merged

reardencode merged 12 commits into
masterfrom
consensus/off-store

Conversation

@rearden-grok

@rearden-grok rearden-grok Bot commented Oct 17, 2026 •

Copy link
Copy Markdown
Contributor

Summary

  • rbitcoin-consensus decides header, block, and transaction accepts and rejects from block bytes plus caller facts (parent header context, prevout amount and script bytes, spent flags, create heights, median-time-past). It does not open the store or the log. rbitcoin-query loads rows, writes Class A, Class C, and spend annotations, and calls those functions.
  • Connect and confirm return ConfirmError: Rules(ConsensusError) or Store(StoreError). ConsensusError::Store is gone. Disk, io_uring session faults, and cancellation stay pipeline errors and are not cached as an invalid block. A corrupt row whose message is an unresolved parent create_fk is still a missing prevout at that edge.
  • Merkle root, the CVE-2012-2459 mutation flag, and the branch helpers have one body in rbitcoin-primitives. Store’s public merkle names call it. The script fuzz target still calls this tree’s verifier.
  • rbitcoin-sv2 depends on rbitcoin-query so the template provider can call expected_next_bits and median_time_past.
  • Electrum stays closed until the follow getheaders round is connected and, with --sh-index, until that tip is in the scripthash head. A block mined during materialize is in history before the wallet port opens.

Test plan

  • cargo tree -p rbitcoin-consensus -e normal lists neither query, store, nor log; query lists consensus
  • Consensus header, spend-fact, and script tests with no datadir, including core_script_tests_all_rows
  • Connect pins: durable PrevoutSpent, bad merkle, bad script, and a store fault that is not cached invalid
  • cargo fmt --all -- --check, cargo clippy --workspace --all-targets -- -D warnings, cargo deny check, ./scripts/ast-grep.sh on the pre-rebase tip; touched files rustfmt-clean and clippy -p rbitcoin-net -p rbitcoin-node --all-targets -D warnings clean on fb432c99
  • ./scripts/ci-os-smoke.sh on the pre-rebase tip
  • end_of_ibd (4 tests) passed locally on fb432c99, including end_of_ibd_sh_interrupt. The same test passed on origin/master 6c933cdb and failed on a6df196f because Electrum answered before the follow block was indexed.
  • GitHub qc, test, windows, macos, and coverage on fb432c99

@rearden-grok
rearden-grok Bot force-pushed the consensus/off-store branch from ed5c9a3 to f3d7206 Compare October 17, 2026 20:34

@rearden-grok rearden-grok Bot left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Summary

The split holds. rbitcoin-consensus no longer depends on query, store, or log (store is dev-only); header, block, and spend rejects are decided from bytes plus caller facts; confirm has one accept_and_connect_block body; merkle including the CVE-2012-2459 flag lives once in rbitcoin-primitives; the two MTP/load-incomplete strings stay ConfirmError::Store; and rbitcoin-sv2's new query dependency only loads expected_next_bits and median_time_past (no cycle and no second rule pipeline). Store faults, including ConsensusError::Internal from the script/index pool, are not cached as failed blocks on the tip path, and the "parent create_fk unresolved" → MissingPrevout remap is the same outcome the old ConsensusError::From<StoreError> already produced, with IBD still reclassifying a one-block miss.

Issue counts by severity

  • bugs: 0
  • suggestions: 1
  • nits: 0

Comment thread crates/rbitcoin-consensus/src/header.rs Outdated
@@ -130,97 +147,6 @@ pub(crate) fn check_header_version_and_future_time(
/// chain, then load-stage header plans (same hybrid as [`crate::confirm_run`]

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

[suggestion] Deleting median_time_past left its rustdoc attached to next_work_bits. The comment describes an 11-block median and a confirm-load header-plan walk, and it links [crate::confirm_run], which is no longer a module of this crate. next_work_bits computes nBits from the parent, the period start, and the testnet min-difficulty callback. The difficulty-walk docs that used to sit on this function were removed in the same hunk.

Suggestion: Delete the median-time comment and put the nBits contract back on next_work_bits (period_first_time, bits_at, and None for a missing ancestor). Point MTP readers at median_time_past_times or the query loaders.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Restored the nBits contract on next_work_bits (period_first_time, bits_at, and None for a missing ancestor). Median time is median_time_past_times. The confirm_run link is gone.

@rearden-grok
rearden-grok Bot force-pushed the consensus/off-store branch from a6df196 to fb432c9 Compare October 17, 2026 21:54
rearden-grok Bot added 12 commits October 17, 2026 15:53
Store tip revalidation and consensus block checks both call the
primitives helpers, including the CVE-2012-2459 mutation flag.
check_header decides linkage, MTP, bits, and proof-of-work from
caller facts. The read façade still returns the two confirm retry
strings when a parent plan or confirmed header is missing.
BIP30 overwrite and coinbase maturity decide from heights the caller
already loaded. Assemble no longer reads the milestone gate or
flushes confirm stats; the confirm pipeline does both.
Rule accepts and rejects stay in rbitcoin-consensus, decided from
bytes and caller facts. Query loads rows and writes Class A, Class C,
and spend annotations, then calls those functions. Consensus no longer
depends on query, store, or log.
expected_bits_extending is only called from confirm tests. ConsensusError
imports that tests match on stay inside those test modules so a non-test
build of query stays warning-clean.
Query callers match ConfirmError::Rules around a rule reject. A live
index invariant stays StoreError::Corrupt, so it is not a cached block
failure. Clippy: eight caller facts on check_header, an elided prevout
lifetime, and JobPrevouts::is_empty.
The rebase onto the witness, sigop, and BIP68 coinbase pins left
store-backed tests calling consensus paths that now live on query.
The exception-hash pin stays in consensus because the job verifier
is crate-private. Connect results match ConfirmError::Rules.
StoreError::Cancelled stays ConfirmError::Store. header_reject maps
that abort to NetError::Cancelled and does not call block_reject_reason.
A side block whose parent header read is cancelled is not BLOCK_FAILED.
The median-time note stayed behind when median_time_past left this
crate, and it linked confirm_run. Median time is median_time_past_times.
The IBD stop flag stays set after teardown. A header read must not
turn that into a cancel. Tests arm one cancelled read instead.
Scripthash materialize returns before a block mined in that window is
connected. The wallet listener waits for that getheaders round and, when
the scripthash index is on, for the head to cover the new tip.
Assemble used that median again for BIP113. The second sort of the same eleven timestamps is the value check_header already computed.
@rearden-grok
rearden-grok Bot force-pushed the consensus/off-store branch from fb432c9 to 54e4930 Compare October 17, 2026 22:53
@reardencode
reardencode merged commit 4e2a813 into master Oct 17, 2026
18 checks passed
@rearden-grok
rearden-grok Bot deleted the consensus/off-store branch October 18, 2026 15:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant