Skip to content

Land verified index and snapshot stack - #1696

Merged
metaphoric-dev merged 20 commits into
mainfrom
stack/06-index-snapshots
Oct 28, 2026
Merged

metaphoric-dev merged 20 commits into
mainfrom
stack/06-index-snapshots

Conversation

@metaphoric-dev

@metaphoric-dev metaphoric-dev commented Oct 28, 2026 •

Copy link
Copy Markdown
Collaborator

Draft subsystem stack split from PR #1687.

Base: f024fc3
Tip: 80be603
Full repository gate: native-gate-20261027T194739Z-194405 (scripts/ci-pr.sh all, exit 0).

Scope: index and snapshots (portable bundles, restore, query).
This is a verified stack tip. Do not rebase or reparent it
without owner approval.

No better-than-Core claim. No mainnet qualification.

See also: #1687

RetriggerView in GreptileConfidence Score: 4/5

Do not merge until the observer lock regression is fixed and the explicit repository requirements are met.

Findings

  1. P1 Observer calls can deadlock ▶
  2. P2 Seed reopen can block application ▶
  3. P2 Required sync evidence is missing ▶
  4. P2 Private tests bypass required layout ▶

Summary

Adds portable transaction-index bundles, snapshot-backed ScriptLive seeding, and covered-prefix queries for embedders.

  • Operators can move verified TxLookup bundles between nodes.
  • ScriptLive seeds from a verified snapshot and catches up from its height.
  • Historical index queries return the chain point that covers each answer.
  • Block flows carry decoded blocks together with their exact bytes.
  • Checkpoint artifacts retain replayable side branches as well as the active chain.
  • The block downloader replans a body after its peer says it is unavailable.

Diagram

%%{init: {'theme': 'neutral'}}%%
flowchart TD
  A[Checkpoint or snapshot activation] --> B[Witnessed snapshot file]
  B --> C[Worker seed slot]
  C --> D[Write live rows in bounded batches]
  D --> E[Check complete snapshot digest]
  E --> F[Commit live watermark]
  F --> G[Reconcile with active chain]
  H[Portable bundle] --> I[Check records against local blocks]
  I --> J[Import rows and commit transaction watermark]
  J --> G
  G --> K[Strict or covered-prefix queries]
Loading

Reviews (4) · Last reviewed commit: "Adapt merged sync tests to branch owners..." · Reviewed by Greptile

Synchronization impact

(a) This PR does not touch an authoritative synchronization, validation, or commit path. It changes index bundle export and restore caching and paging, and index-side seed traversal cancellation. It consumes existing chain views and does not alter scheduling, validation, or commit ownership.

(b) No SYNC-* clause is affected.

(c) The smallest existing behavioral proof is cargo test -p bitcoin-rs-index --features fjall --test portable_bundle (8 tests) and cargo test -p bitcoin-rs-index --lib portable (25 tests). These exercise export and restore against the current chain view and do not cross a synchronization contract boundary.

metaphorics added 3 commits October 28, 2026 01:40
Use one historical error mapper and one complete-scan admission path while preserving every error variant.
Use one strict BodyReader resolver for export and restore, rejecting embedded serializations and incomplete bundle positions without changing the format.

@amazon-q-developer amazon-q-developer Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Review Summary

This PR lands the verified index and snapshot stack, introducing ~21k lines of new code primarily in crates/index. The new subsystem implements portable bundle export/restore for the TxLookup family, a reconciliation state machine, and associated storage operations.

Assessment: The implementation is well-engineered and ready to merge.

After a deep review of the core new subsystem — the bundle pipeline (export.rs, restore.rs, artifact.rs, manifest.rs, chain.rs), the reconciliation state machine (reconciliation.rs), and startup/namespace management (startup.rs) — no blocking defects were found.

Key correctness properties verified:

  • Tamper resistance: The two-pass (validate → apply) restore pipeline re-hashes the artifact file before the final watermark commit, so a file altered between validation and apply is refused before readiness is stamped.
  • Atomicity: Rows without a TxLookup watermark stay invisible to queries; readiness appears in one final fenced commit that writes both rows and watermark atomically.
  • Partial-import cleanup: discard_partial_rows correctly escalates to IndexBundleError::Index on reset failure, preventing partial rows from mixing with derived rows.
  • Path traversal prevention: artifact.name is validated against the exact constant BundleFamily::TxLookup.file_name() in validate(), refusing names like "../escape.dat". The create_new file creation provides the actual atomic protection against races.
  • Locator verification: The strict top-level-span rule (is_top_level_span) correctly prevents embedded transaction serializations (inside scripts/witnesses) from resolving locators.
  • Namespace poisoning (IDX-07): Abandoned opens (timeout/stop) poison their namespace key for the process lifetime, preventing a detached open thread from racing with a new worker on the same store.

No blocking issues identified. The code ships with thorough unit tests for every described invariant.


You can now have the agent implement changes and create commits directly on your pull request's source branch. Simply comment with /q followed by your request in natural language to ask the agent to make changes.


⚠️ This PR contains more than 30 files. Amazon Q is better at reviewing smaller PRs, and may miss issues in larger changesets.

Comment thread crates/index/src/portable/chain.rs Outdated
Comment thread crates/index/src/index/snapshot.rs Outdated
Comment thread crates/utxo/src/snapshot.rs Outdated
gormes-agent Bot and others added 2 commits October 28, 2026 05:52
Port the bounded page API and export stream, clear interrupted imports with one bounded probe, and buffer UTXO seed reads. The remote branch already retains parsed bundle block spans.
@metaphoric-dev
metaphoric-dev marked this pull request as ready for review October 28, 2026 09:12
metaphorics added 3 commits October 28, 2026 21:35
Merge origin/main (Tor/I2P overlay #1684, public listener #1685) into the
index-snapshot lane. Branch intent preserved: BlockPayload unification,
index bundle snapshot config/tests, and layered config coverage.

Resolutions:
- crates/node/src/config.rs: union; keep validate_index_bundle (branch)
  and p2p.overlay.validate (main), one call each.
- crates/p2p/src/listener.rs send_block: main PeerRemote param
  (impl Into<PeerRemote> + into()) with branch BlockPayload body; all nine
  merged call sites pass payload, so main-only (block, serialized) would
  break every caller and the already-merged forward_block payload form.
- crates/p2p/src/listener.rs handle_compact_outcome: main PeerRemote
  param with branch Option<(Hash256, Message)> flow; the merged caller in
  process_compact_wire_message destructures Some((hash, follow_up)), so
  main-only bool would break it. No ListenerRole restored.
- crates/p2p/src/listener/aggregate_budget_tests.rs: main PeerEndpoint
  addr with branch .is_none() assertion.
- crates/rpc/tests/core_compat.rs: main ipv4/ipv6/onion/i2p networks
  pin (replaces stale len==3 the branch had dropped); branch BlockPayload
  test changes kept via automerge.
Merge origin/main at fa187f9 (scan ranged and multipath public
descriptors #1676; compact-block scan scoping #1677) into the
index-snapshot lane. Clean automerge; prior main-merge resolution
(2609ba4: overlay validators, PeerRemote/BlockPayload listener hybrid,
PeerEndpoint tests, four-network RPC pin) preserved untouched.
Main compact-sync tests called record_owned_body_fetch,
which the branch replaced with enqueue_owned_body_fetch.
The NotFoundFixture fields also kept SocketAddr after
current_source and test_addr moved to PeerRemote.

- Add the missing SocketAddr import.
- Store owner and alternate as PeerRemote.
- Mark the owned fetch through enqueue_owned_body_fetch.
@metaphoric-dev

Copy link
Copy Markdown
Collaborator Author

@codex review

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 28, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-28T17:23:26.592468Z 73ec7d5 Manual request
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 37460754ee

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread crates/index/src/portable/restore.rs Outdated
Comment thread crates/mempool/src/gateway.rs Outdated
Comment thread crates/chainstate/src/checkpoint/publisher.rs Outdated
Comment thread crates/node/src/sync.rs
Comment thread crates/index/src/runtime.rs Outdated
metaphorics added 4 commits October 28, 2026 22:11
…ount cache

Stored locator order is txid order, so consecutive records usually name
different heights and a one-body memo reloaded and reparsed a block per
record. The LRU keeps recently used parsed bodies resident across
interleaved lookups (8 bodies, ~32 MiB worst case). Counts observed on
load are retained after eviction so the completeness pass reuses the
first parse instead of re-reading every body.
Each page is scanned through a fresh snapshot that must still show the
captured base watermark and floor, then dropped before body I/O. A long
export no longer pins one KV snapshot across the whole family; a moved
watermark aborts stale before any manifest is published.
Block headers are shared identity kept when any capability cursor
remains, so a restore onto a node with other capabilities rewrote every
covered header. A point lookup per header skips present ones with no
extra memory; overwriting stays idempotent for absent ones.
@metaphoric-dev

Copy link
Copy Markdown
Collaborator Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. What shall we delve into next?

Reviewed commit: 0c5bd5b7ad

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@metaphoric-dev

Copy link
Copy Markdown
Collaborator Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Hooray!

Reviewed commit: 0c5bd5b7ad

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

metaphorics added 4 commits October 29, 2026 00:07
Resolutions (branch LRU/paged fixes kept; main contracts kept): export.rs keeps branch per-page short-lived snapshots plus height-grouped LRU staging and adds main ExportTooLarge cap; drops main shared-snapshot helper and paged tests (superseded; same bounded-paging behavior). restore.rs keeps branch BodyReader LRU for all body I/O plus main height-grouped pending drain, RestoreTooLarge cap, and mismatch-before-incomplete fault order; drops main ParsedBlock-direct paths (equivalent strict-span rule and metadata reuse via BodyReader). snapshot.rs combines branch bounded 64KiB buffering with main below-tee layering; keeps main VARINT ordering.
@metaphoric-dev

Copy link
Copy Markdown
Collaborator Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 1cc9ca1087

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread crates/index/src/portable/export.rs Outdated
Export sorted only within each 1,024-row page, so one block's transactions
scattered across pages and the 8-body LRU reloaded whole bodies about 1.86M
times for 4,096 blocks. The export now stages every stored row into an
anonymous temp file, sorts the staging file by (height, sequence), resolves
the height-ordered rows so each covered body is read and parsed once, then
re-sorts the resolved rows by sequence and emits them in stored order. The
artifact keeps its strictly ascending record order while body I/O stays
height-local.

Bounded pages, bounded sort runs, and one row held at a time keep export
memory flat in family size; per-page snapshot watermark/floor checks and the
end-to-end fenced watermark compare are unchanged, and cancellation is
polled every 4,096 scanned, resolved, or emitted rows.

Adds a regression test over 16 blocks and multiple pages proving each block
body is loaded exactly once and the bundle restores like a backfilled index.
@metaphoric-dev

Copy link
Copy Markdown
Collaborator Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: bf642edd25

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread crates/index/src/portable/export.rs
Comment thread crates/index/src/portable/export.rs
metaphorics added 3 commits October 29, 2026 02:13
# Conflicts:
#	crates/index/src/portable/chain.rs
#	crates/index/src/portable/export.rs
#	crates/index/src/portable/restore.rs
#	crates/utxo/src/snapshot.rs
@metaphoric-dev

Copy link
Copy Markdown
Collaborator Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. 🎉

Reviewed commit: 73ec7d588f

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@metaphoric-dev
metaphoric-dev merged commit 9611fcc into main Oct 28, 2026
11 of 16 checks passed
@metaphoric-dev
metaphoric-dev deleted the stack/06-index-snapshots branch October 28, 2026 17:44
metaphoric-dev added a commit that referenced this pull request Oct 28, 2026
## Summary

Follow-up to #1696 for two review findings that arrived after the merge.

- `external_sort`, run generation, merge, and copy now poll the
cancellation probe every bounded chunk, so shutdown does not wait for a
multi-million-row sort.
- Enumeration now validates positions and charges the shared
4,194,304-position budget before writing or sorting, returning
`ExportTooLarge` before temporary-storage growth.

## Verification

- `cargo test -p bitcoin-rs-index --lib export::tests --locked` (9
passed)
- `cargo test -p bitcoin-rs-index --lib portable --locked` (26 passed)
- `cargo test -p bitcoin-rs-index --features fjall --test
portable_bundle --locked` (9 passed)
- `cargo check --workspace --all-targets --locked`

## Synchronization impact

No authoritative sync, validation, or commit path changes. The changes
are limited to index bundle export cancellation and staging. No `SYNC-*`
clause is affected.
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