refactor(archiver)!: data-store, block API, and genesis cleanup#22891
Closed
spalladino wants to merge 3 commits into
Closed
refactor(archiver)!: data-store, block API, and genesis cleanup#22891spalladino wants to merge 3 commits into
spalladino wants to merge 3 commits into
Conversation
Replace the KVArchiverDataStore wrapper with a plain ArchiverDataStores bundle exposing substores directly. Cross-store helpers move to free functions. Function-name caching becomes its own class. The ContractDataSource adapter is now a named class. - archiver: delete KVArchiverDataStore; add ArchiverDataStores bundle (blocks/logs/messages/contractClasses/contractInstances/db/function-name cache) and createArchiverDataStores. getArchiverSynchPoint and backupArchiverDataStores move to free functions. - archiver (function names): extract FunctionNamesCache class. - archiver (contract data source): extract ArchiverContractDataSourceAdapter class; createContractDataSource is a thin factory. - archiver (substores): BlockStore.getBlocks/getCheckpointedBlocks/ getBlockHeaders return arrays (iterator variants renamed iterate*); contract substores expose batch add*/delete* helpers. - archiver (tests): split kv_archiver_store.test.ts into per-substore test files. - node-lib, prover-node, txe, validator-client, end-to-end: update call sites to reach for the relevant substore directly.
Consolidate the block-related lookup surface on L2BlockSource from
~17 narrow methods returning ~9 different shapes down to 4 methods
returning 2 shapes (L2Block and BlockData). Replace the per-shape
getters with discriminated query objects that carry both the lookup
discriminant and a single onlyCheckpointed filter, removing the
parallel Checkpointed* API and the throwaway wrapper types.
L2BlockSource exposes 4 methods that take query objects:
getBlock(query: BlockQuery): Promise<L2Block | undefined>
getBlocks(query: BlocksQuery): Promise<L2Block[]>
getBlockData(query: BlockQuery): Promise<BlockData | undefined>
getBlocksData(query: BlocksQuery): Promise<BlockData[]>
type BlockQuery = ({number} | {hash} | {archive}) & { onlyCheckpointed?: boolean }
type BlocksQuery = ({from, limit} | {epoch}) & { onlyCheckpointed?: boolean }
On-disk format is unchanged.
Wire-level: AztecNode.getCheckpointedBlocks element type goes
CheckpointedL2Block[] -> BlockResponse[]. CheckpointedL2Block and
BlockDataWithCheckpointContext are deleted entirely. Callers that
previously read .l1 / .attestations off these now do
getBlockData(...) followed by getCheckpointData(blockData.checkpointNumber)
and read those fields off CheckpointData.
- stdlib: BlockQuery / BlocksQuery types + Zod schemas next to
L2BlockSource. CheckpointedL2Block file deleted;
BlockDataWithCheckpointContext removed from block_data.ts.
ArchiverApiSchema and MockArchiver shrunk.
- archiver: BlockStore consolidates to four query-object reads plus
iterators. data_source_base.ts adds resolveBlocksQuery that
translates {epoch} -> {from, limit}. Mocks honor onlyCheckpointed.
- aztec-node: server.ts keeps the public RPC method names but
delegates to the new query methods. getCheckpointedBlocks adds a
per-call cache to avoid an N+1.
- consumer migrations: world-state, txe, p2p block-txs handler,
validator-client, pxe block-stream source, prover-node,
sequencer-client, telemetry-client, aztec/testing, L2BlockStream
in stdlib.
The Aztec rollup has an implicit "block zero" whose state is captured
in an initial block header computed by NativeWorldStateService.
Previously the archiver returned undefined for any query that
resolved to genesis, forcing every consumer (aztec-node, prover-node,
p2p, sequencer, PXE, sentinel) to reach into
worldStateSynchronizer.getCommitted().getInitialHeader() and synthesize
a fake block 0 themselves. Worse, components disagreed on the genesis
hash whenever genesisTimestamp or prefilled state diverged from the
default, because some used worldState.getInitialHeader().hash()
(dynamic) and others used the protocol constant
GENESIS_BLOCK_HEADER_HASH (static).
Construct world-state first, capture nativeWs.getInitialHeader(), and
pass it into the archiver at construction. The archiver returns a
synthetic L2Block.empty(initialHeader) for single-block queries that
resolve to genesis - by number, hash, archive, or tag. Range queries
explicitly do not prepend. L2TipsCache, world-state synchronizer's
getL2Tips, stdlib's L2TipsStoreBase, P2PClient/L2TipsKVStore, PXE,
and sentinel all switched to the dynamic initialHeader.hash().
Genesis special-casing was deleted from aztec-node, prover-node,
p2p_client, sequencer (the all-zeros escape hatch), and stdlib's
areBlockHashesEqualAt.
- archiver: synthetic genesis block in data_source_base (with archive
set to new AppendOnlyTreeSnapshot(genesisArchiveRoot, 1)),
initialHeader plumbing through factory / constructor, L2TipsCache
uses dynamic genesis hash, MockL2BlockSource synthesizes block 0
+ exposes getInitialHeader/setInitialHeader/setGenesisArchiveRoot,
NoopL1Archiver accepts initialHeader.
- world-state: createWorldState exported as a public factory, new
createWorldStateSynchronizerOverNative that wraps a pre-built native
instance, getL2Tips reports initialHeader.hash() and BlockNumber.ZERO
for genesis tips.
- aztec-node: server.ts reorders wiring so world-state is built first;
getBlock, getBlockHeader, resolveBlockNumber, getPrivateLogsByTags,
getPublicLogsByTagsFromContract no longer special-case genesis.
buildGenesisBlockResponse deleted. Sentinel re-creates its
L2TipsMemoryStore in init() with the archiver's block-0 hash.
- stdlib: L2TipsStoreBase accepts initialBlockHash (default
GENESIS_BLOCK_HEADER_HASH for back-compat). areBlockHashesEqualAt
no longer short-circuits at block 0. L2BlockStream's reorg-search
loop refuses to walk past block 0.
- p2p: P2PClient / createP2PClient accept and forward
initialBlockHash; aztec-node passes the archiver's genesis hash.
- pxe: fetches node.getBlock(0) at startup and seeds L2TipsKVStore
with that hash.
- sequencer-client: deleted the all-zeros escape hatch in getStatus.
- prover-node: gatherPreviousBlockHeader calls
l2BlockSource.getBlockData({number:0}) uniformly.
- tests: new archiver/src/modules/data_source_base.test.ts covering
genesis-query semantics; world-state and validator-client integration
tests thread db.getInitialHeader() and genesisArchiveRoot to the
archiver/mock; new l2_block_stream.test.ts case asserting the
genesis-hash-mismatch error path.
This was referenced Apr 30, 2026
PhilWindle
pushed a commit
that referenced
this pull request
May 1, 2026
> **Note:** This PR is stacked together with #22818, #22809, and #22870 into combined PR #22891 (targeting `merge-train/spartan`) for easier merging. The combined PR has each of these as a separate commit, so reviewers can either review here or on the combined PR. ## Motivation `KVArchiverDataStore` was a thick pass-through wrapper that re-exported the same methods as the substores it owned (`BlockStore`, `LogStore`, `MessageStore`, `ContractClassStore`, `ContractInstanceStore`), forcing every API change to be plumbed through three layers. Removing it brings the archiver one step closer to a clean, query-object-based data source API and makes substore boundaries explicit at every call site. ## Approach Replace the wrapper with a plain `ArchiverDataStores` bundle that exposes the substores directly, and move cross-store helpers to free functions on the bundle. Substores absorb the array/iterator helpers that previously lived on the wrapper. Function-name caching becomes its own small class, and the `ContractDataSource` adapter is now a named class instead of an inline object literal so that re-prover tools and tests can reach for it without depending on `data_stores.ts` internals. ## Changes - **archiver**: Delete `KVArchiverDataStore`; add `ArchiverDataStores` bundle (`BlockStore`, `LogStore`, `MessageStore`, `ContractClassStore`, `ContractInstanceStore`, db, function-name cache) and `createArchiverDataStores`. Cross-store helpers (`getArchiverSynchPoint`, `backupArchiverDataStores`) move to free functions. - **archiver (renames)**: `ArchiverDataStores` fields use plural form: `blocks`, `logs`, `messages`, `contractClasses`, `contractInstances`. Substore class names and individual store classes are unchanged. - **archiver (function names)**: Extract `FunctionNamesCache` class (replaces `Map<string, string>` plus the `registerContractFunctionSignatures`/`getDebugFunctionName` free functions). - **archiver (contract data source)**: Extract `ArchiverContractDataSourceAdapter` class implementing `ContractDataSource`; `createContractDataSource` is now a thin factory. - **archiver (substores)**: `BlockStore.getBlocks`/`getCheckpointedBlocks`/`getBlockHeaders` return arrays (iterator variants renamed `iterate*`); contract substores expose batch `add*`/`delete*` helpers. - **archiver (tests)**: Split the 4286-line `kv_archiver_store.test.ts` into per-substore test files (`block_store.test.ts`, `log_store.test.ts`, `message_store.test.ts`, `contract_class_store.test.ts`, `contract_instance_store.test.ts`). - **node-lib, prover-node, txe, validator-client, end-to-end**: Update call sites to reach for the relevant substore on `ArchiverDataStores` directly.
Contributor
Author
|
Closing as the first PR in the stack (#22818) was merged individually. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Bundles three stacked archiver/node refactor PRs into a single PR for ease of merging into
merge-train/spartan. Each commit is the rebased, squashed equivalent of one of the original PRs.Reviewers should review each commit individually — they were originally separate PRs and the changes within each are tightly scoped.
Commits
1.
refactor(archiver): remove KVArchiverDataStore pass-through— #22818Replaces the
KVArchiverDataStorewrapper with a plainArchiverDataStoresbundle that exposes substores directly. Cross-store helpers move to free functions;FunctionNamesCacheandArchiverContractDataSourceAdapterbecome named classes; per-substore tests split out from the monolithickv_archiver_store.test.ts.2.
refactor(node-rpc)!: simplify L2BlockSource block lookups— #22809Consolidates
L2BlockSourcefrom ~17 narrow methods returning ~9 shapes down to 4 query-object methods returning 2 shapes (L2Block/BlockData). DeletesCheckpointedL2BlockandBlockDataWithCheckpointContext;AztecNode.getCheckpointedBlockselement type goesCheckpointedL2Block[]→BlockResponse[](wire-level breaking change). On-disk format unchanged.3.
refactor: centralize block-zero handling in archiver— #22870Threads the dynamic initial block header from
NativeWorldStateServicethrough the archiver. The archiver now returns a syntheticL2Block.empty(initialHeader)for genesis single-block queries; consumers (aztec-node, prover-node, p2p, sequencer, PXE, sentinel) drop their genesis special-casing and use the dynamic genesis hash uniformly. Eliminates divergence betweenworldState.getInitialHeader().hash()callers andGENESIS_BLOCK_HEADER_HASHcallers.Reviewing the originals
For convenience, reviewers who prefer the per-PR view can read the individual stacked PRs:
spl/remove-kv-storespl/internal-archiver-api-reviewspl/archiver-knows-genesisThe originals will be closed once this PR merges.
Rebase notes
Only one rebase fixup vs.
merge-train/spartanwas needed:epochs_high_tps_block_building.test.tshad a new assertion added onmerge-train/spartan(in #22846) that used the oldb.block.bodyshape — migrated tob.body!to match the newBlockResponsetype from commit 2.