Commit b204aed
feat(iota-core): backfill epochs_v2 and seed it on snapshot restore (#11697)
# Description of change
Makes a gRPC fullnode's `epochs_v2` index complete since genesis on
every bootstrap path and enforces it at startup: the node closes any gap
before services start, or refuses to run instead of silently serving an
incomplete index — the consumer side of #11453's `EPOCH_INFO` file. No
object/`previous_transaction_checkpoint` backfill: the
snapshot-publisher node resyncs from genesis instead, enforced by the
writer's existing refusal of `None` rows.
- **Synchronous startup backfill (`iota-node`, `iota-config`).** A node
that detects a gap (`epochs_v2_gap`: index short of the last executed
closed epoch) fetches only MANIFEST + `EPOCH_INFO` from the new
`state_snapshot_read_config`, seeds `[0, snapshot_epoch]`, closes any
residual above it from local history, seeds the open epoch's row, and
re-checks; a remaining gap — or no configured source — aborts startup.
Runs before live indexing exists, so the watermark has one writer at a
time and the previous design's background task, retry/backoff, and
`epoch_watermark_lock` are gone.
- **Local indexing fallback (`iota-core`).** When the latest published
snapshot lags local execution (delayed snapshot pipeline),
`index_missing_epochs_locally` replays only the missing epochs' closing
checkpoints, located via the never-pruned `epoch_last_checkpoint_map`;
best-effort up to the pruning horizon.
- **Atomic `EpochIndexed` advance (`iota-core`).** The live path
advances the watermark in the same batch as the close-of-epoch row
(gap-aware `try_advance_epoch_indexed_watermark`);
`reconcile_epoch_indexed_watermark` remains only to jump across a seeded
prefix.
- **Restore builds the whole gRPC index store (`iota-tool`,
`iota-snapshot`, `iota-core`).** `download_formal_snapshot` tees the
restored object stream into the live-state indexers
(`RestoreWithGrpcIndexes`), seeds the epoch rows, and finalizes the
store (`Watermark::Indexed`, then `meta` — a crash before `meta` leaves
a store the next open wipes and re-inits). The node opens it in place
instead of re-indexing the whole restored state; opt out with
`--skip-grpc-indexes`. `init` and the restore share one indexing
implementation (`GrpcLiveObjectRestorer`; `ParMakeLiveObjectIndexer` is
lifetime-generic now).
- **Chain-identity gate (`iota-snapshot`).**
`verify_and_restore_epoch_info` rejects a snapshot whose manifest
`chain_id` differs from this node's chain before writing any row.
- **`RestoreEpochInfo` trait (`iota-snapshot`).** Separate single-method
trait instead of a new `Restore` method: the two cover different
snapshot payloads with different targets, so each call site requires
exactly the capability it uses; the unified indexer (#11023) can
implement both.
- **No `epochs` migration (`iota-core`).** The deprecated `epochs` CF is
dropped without migration: its rows lack the end-of-epoch fields, so
they could never satisfy `EpochIndexed` and the backfill would overwrite
them anyway.
- **Open-epoch seeding (`iota-core`).** `initialize_current_epoch_info`
keys off the open epoch (`open_epoch_of`): a restore lands on a closing
checkpoint, and seeding that checkpoint's own (closed) epoch would leave
the open epoch's row permanently missing and wedge the watermark. Its
start checkpoint derives from `epoch_last_checkpoint_map` (new seq-only
`CheckpointStore` accessor; the backwards scan over prunable summaries
is deleted).
- **Default snapshot source (`setups`).** Fullnode setups for
mainnet/testnet/devnet ship a default `state-snapshot-read-config`
pointing at the IOTA Foundation buckets; ignored unless the gRPC API is
enabled and the index is incomplete.
- **Misc.** Uploader honors `state_snapshot_write_config.concurrency`
(default still 20); `get_latest_available_epoch` delegates to
`iota_snapshot::reader::latest_available_epoch`; `snapshots.mdx`
documents the restore flag and the backfill setup.
## Links to any relevant issues
follow-up (PR-2) of #11453 · part of #11023
## How the change has been tested
- [x] Basic tests (linting, compilation, formatting, unit/integration
tests)
- [x] Patch-specific tests (correctness, functionality coverage)
- [ ] I have added tests that prove my fix is effective or that my
feature works
- [ ] I have checked that new and existing unit tests pass locally with
my changes
---------
Co-authored-by: muXxer <git@muxxer.de>1 parent fad8412 commit b204aed
21 files changed
Lines changed: 2046 additions & 372 deletions
File tree
- crates
- iota-config/src
- iota-core/src
- checkpoints
- iota-e2e-tests
- tests
- iota-node/src
- iota-snapshot/src
- iota-storage/src/object_store
- iota-swarm-config/src
- iota-tool/src
- docs/content/operator/common
- setups/fullnode
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
193 | 193 | | |
194 | 194 | | |
195 | 195 | | |
| 196 | + | |
| 197 | + | |
| 198 | + | |
| 199 | + | |
| 200 | + | |
| 201 | + | |
196 | 202 | | |
197 | 203 | | |
198 | 204 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
802 | 802 | | |
803 | 803 | | |
804 | 804 | | |
805 | | - | |
| 805 | + | |
806 | 806 | | |
807 | 807 | | |
808 | 808 | | |
809 | 809 | | |
810 | 810 | | |
811 | 811 | | |
812 | 812 | | |
| 813 | + | |
| 814 | + | |
| 815 | + | |
| 816 | + | |
| 817 | + | |
| 818 | + | |
| 819 | + | |
| 820 | + | |
| 821 | + | |
| 822 | + | |
813 | 823 | | |
814 | 824 | | |
815 | 825 | | |
| |||
0 commit comments