Skip to content

fix: clamp finalized block to oldest available in world-state#21643

Merged
PhilWindle merged 2 commits intomerge-train/spartanfrom
claudebox/fix-finalized-block-pruning
Mar 17, 2026
Merged

fix: clamp finalized block to oldest available in world-state#21643
PhilWindle merged 2 commits intomerge-train/spartanfrom
claudebox/fix-finalized-block-pruning

Conversation

@AztecBot
Copy link
Collaborator

Summary

PR #21597 increased the finalized block lookback from epochDuration*2 to epochDuration*2*4, which caused the finalized block number to jump backwards past blocks already pruned from world-state. The native advance_finalized_block then failed trying to read pruned block data, crashing the block stream with:

Error: Unable to advance finalized block: 15370. Failed to read block data. Tree name: NullifierTree

Two fixes:

  • TypeScript (server_world_state_synchronizer.ts): Clamp the finalized block number to oldestHistoricalBlock before calling setFinalized, so we never request a pruned block.
  • C++ (cached_content_addressed_tree_store.hpp): Reorder checks in advance_finalized_block to check the no-op condition (finalizedBlockHeight >= blockNumber) before attempting read_block_data. This makes the native layer resilient to stale finalized block numbers.

Full analysis: https://gist.github.com/AztecBot/6221fb074ed7bbd8a753ec3602133b42

ClaudeBox log: https://claudebox.work/s/8e97449f22ba9343?run=1

PR #21597 increased the finalized block lookback from epochDuration*2
to epochDuration*2*4. This caused the finalized block number to jump
backwards past blocks that had already been pruned from world-state,
causing advance_finalized_block to fail with 'Failed to read block data'.

Two fixes:
1. TypeScript: clamp blockNumber to oldestHistoricalBlock before calling
   setFinalized, so we never request a pruned block.
2. C++: reorder checks in advance_finalized_block to check the no-op
   condition (already finalized past this block) before attempting to
   read block data. This makes the native layer resilient to receiving
   a stale finalized block number.
@AztecBot AztecBot added the claudebox Owned by claudebox. it can push to this PR. label Mar 17, 2026
…uned blocks

Tests that handleBlockStreamEvent with chain-finalized for a block
older than the oldest available block does not throw, validating
the clamping fix in handleChainFinalized.
@spalladino spalladino marked this pull request as ready for review March 17, 2026 01:51
@PhilWindle PhilWindle merged commit 79bf4c4 into merge-train/spartan Mar 17, 2026
24 of 28 checks passed
@PhilWindle PhilWindle deleted the claudebox/fix-finalized-block-pruning branch March 17, 2026 08:39
AztecBot pushed a commit that referenced this pull request Mar 17, 2026
## Summary

PR #21597 increased the finalized block lookback from `epochDuration*2`
to `epochDuration*2*4`, which caused the finalized block number to jump
backwards past blocks already pruned from world-state. The native
`advance_finalized_block` then failed trying to read pruned block data,
crashing the block stream with:
```
Error: Unable to advance finalized block: 15370. Failed to read block data. Tree name: NullifierTree
```

Two fixes:
- **TypeScript** (`server_world_state_synchronizer.ts`): Clamp the
finalized block number to `oldestHistoricalBlock` before calling
`setFinalized`, so we never request a pruned block.
- **C++** (`cached_content_addressed_tree_store.hpp`): Reorder checks in
`advance_finalized_block` to check the no-op condition
(`finalizedBlockHeight >= blockNumber`) before attempting
`read_block_data`. This makes the native layer resilient to stale
finalized block numbers.

Full analysis:
https://gist.github.com/AztecBot/6221fb074ed7bbd8a753ec3602133b42

ClaudeBox log: https://claudebox.work/s/8e97449f22ba9343?run=1
@AztecBot
Copy link
Collaborator Author

✅ Successfully backported to backport-to-v4-staging #21651.

PhilWindle added a commit that referenced this pull request Mar 17, 2026
…21656)

## Summary

Follow-up to #21643.
The clamping fix avoided the `setFinalized` error, but the method
continued into the pruning logic where `removeHistoricalBlocks` failed
with:
```
Unable to remove historical blocks to block number 15812, blocks not found. Current oldest block: 15812
```

Two changes:
- When the finalized block is older than `oldestHistoricalBlock`, return
early instead of clamping and continuing. There's nothing useful to do —
world-state is already finalized past this point.
- Guard `removeHistoricalBlocks` against being called with a block `<=
oldestHistoricalBlock`, which the C++ layer rejects.

The C++ reorder fix from #21643 is preserved.

ClaudeBox log: https://claudebox.work/s/8e97449f22ba9343?run=4
AztecBot pushed a commit that referenced this pull request Mar 17, 2026
…21656)

## Summary

Follow-up to #21643.
The clamping fix avoided the `setFinalized` error, but the method
continued into the pruning logic where `removeHistoricalBlocks` failed
with:
```
Unable to remove historical blocks to block number 15812, blocks not found. Current oldest block: 15812
```

Two changes:
- When the finalized block is older than `oldestHistoricalBlock`, return
early instead of clamping and continuing. There's nothing useful to do —
world-state is already finalized past this point.
- Guard `removeHistoricalBlocks` against being called with a block `<=
oldestHistoricalBlock`, which the C++ layer rejects.

The C++ reorder fix from #21643 is preserved.

ClaudeBox log: https://claudebox.work/s/8e97449f22ba9343?run=4
alexghr added a commit that referenced this pull request Mar 17, 2026
BEGIN_COMMIT_OVERRIDE
fix(aztec-nr): return Option from decode functions and fix event
commitment capacity (backport #21264) (#21360)
fix: backport #21271 — handle bad note lengths on
compute_note_hash_and_nullifier (#21364)
fix: not reusing tags of partially reverted txs (#20817)
chore: revert accidental backport of #20817 (#21583)
feat: Implement commit all and revert all for world state checkpoints
(#21532)
cherry-pick: fix: dependabot alerts (#21531)
fix: dependabot alerts (backport #21531 to v4) (#21592)
fix: backport #21443 — Don't update state if we failed to execute
sufficient transactions (v4) (#21610)
chore: Fix msgpack serialisation (#21612)
fix(p2p): fall back to maxTxsPerCheckpoint for per-block tx validation
(#21605)
chore: merge v4 into backport-to-v4-staging (#21618)
fix(revert): avm sim uses event loop again (#21138) (#21630)
fix(e2e): remove historic/finalized block checks from epochs_multiple
test (#21642)
fix: clamp finalized block to oldest available in world-state (#21643)
fix: skip handleChainFinalized when block is behind oldest available
(#21656)
chore: demote finalized block skip log to trace (#21661)
fix: off-by-1 in getBlockHashMembershipWitness archive snapshot
(backport #21648) (#21663)
fix: capture txs not available error reason in proposal handler (#21670)
chore: add L1 inclusion time to stg public (#21665)
END_COMMIT_OVERRIDE

---------

Co-authored-by: Jan Beneš <janbenes1234@gmail.com>
Co-authored-by: PhilWindle <60546371+PhilWindle@users.noreply.github.com>
Co-authored-by: Phil Windle <philip.windle@gmail.com>
Co-authored-by: Santiago Palladino <santiago@aztecprotocol.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: ludamad <adam.domurad@gmail.com>
Co-authored-by: Alex Gherghisan <alexghr@users.noreply.github.com>
github-merge-queue bot pushed a commit that referenced this pull request Mar 18, 2026
BEGIN_COMMIT_OVERRIDE
fix(p2p): fall back to maxTxsPerCheckpoint for per-block tx validation
(#21605)
chore: fixing M3 devcontainer builds (#21611)
fix: clamp finalized block to oldest available in world-state (#21643)
chore: fix proving logs script (#21335)
fix: (A-649) tx collector bench test (#21619)
fix(validator): process block proposals from own validator keys in HA
setups (#21603)
fix: add bounds when allocating arrays in deserialization (#21622)
fix: skip handleChainFinalized when block is behind oldest available
(#21656)
chore: demote finalized block skip log to trace (#21661)
fix: skip -march auto-detection for cross-compilation presets (#21356)
chore: revert "add bounds when allocating arrays in deserialization"
(#21622) (#21666)
fix: capture txs not available error reason in proposal handler (#21670)
fix: estimate gas in bot and make BatchCall.simulate() return
SimulationResult (#21676)
fix: prevent HA peer proposals from blocking equivocation in duplicate
proposal test (#21673)
fix(p2p): penalize peers for errors during response reading (#21680)
feat(sequencer): add build-ahead config and metrics (#20779)
chore: fixing build on mac (#21685)
fix: HA deadlock for last block edge case (#21690)
fix: process all contract classes in storeBroadcastedIndividualFunctions
(A-683) (#21686)
chore: add slack success post on nightly scenario (#21701)
fix(builder): persist contractsDB across blocks within a checkpoint
(#21520)
fix: only delete logs from rolled-back blocks, not entire tag (A-686)
(#21687)
chore(p2p): lower attestation pool per-slot caps to 2 (#21709)
chore(p2p): remove unused method (#21678)
fix(p2p): penalize peer on tx rejected by pool (#21677)
fix(test): workaround slow mock creation (#21708)
fix(sequencer): fix checkpoint budget redistribution for multi-block
slots (#21692)
fix: batch checkpoint unwinding in handleEpochPrune (A-690) (#21668)
fix(sequencer): add missing opts arg to checkpoint_builder tests
(#21733)
fix: race condition in fast tx collection (#21496)
fix: increase default postgres disk size from 1Gi to 10Gi (#21741)
fix: update batch_tx_requester tests to use RequestTracker (#21734)
chore: replace dead BOOTSTRAP_TO env var with bootstrap.sh build arg
(#21744)
fix(sequencer): extract gas and blob configs from valid requests only
(A-677) (#21747)
fix: deflake attempt for l1_tx_utils (#21743)
fix(test): fix flaky keystore reload test (#21749)
fix(test): fix flaky duplicate_attestation_slash test (#21753)
feat(pipeline): introduce pipeline views for building (#21026)
END_COMMIT_OVERRIDE
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backport-to-v4 claudebox Owned by claudebox. it can push to this PR.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants