Skip to content

Evict non-validator replicated blocks from the block cache once finalized - #516

Draft
samliok wants to merge 1 commit into
mainfrom
fix/nonvalidator-cachedstorage-prune
Draft

Evict non-validator replicated blocks from the block cache once finalized#516
samliok wants to merge 1 commit into
mainfrom
fix/nonvalidator-cachedstorage-prune

Conversation

@samliok

@samliok samliok commented Aug 14, 2026

Copy link
Copy Markdown
Collaborator

What was wrong

The non-validator's EpochAwareStorage wrapped the raw storage (instance.go:160) instead of the instance's CachedStorage, unlike the validator path (instance.go:487). Blocks replicated by a non-validator are cached as unfinalized when verified (adapters.go:86), and CachedStorage.Index (adapters.go:138) is the only place cache entries are deleted, so the non-validator's indexing never evicted them.

Consequence

While a node runs as a non-validator, the cache grows by one entry per replicated block and is never pruned, holding the entire replicated chain in memory. Retrieving one of these finalized blocks by digest returns it with a nil finalization, violating the documented cache invariant (adapters.go:119). The stale entries survive into the validator role after promotion until the first block is indexed there.

Fix

Wire the non-validator's EpochAwareStorage to the block cache, matching the validator path, so indexing a finalized block evicts it and everything older.

Verification

TestInstanceNonValidatorEvictsFinalizedBlocks (instance_test.go): failed before the fix (finalized block at seq 1 served without its finalization), passes after. TestInstanceNonValidatorBootstraps and TestInstanceMixedNodeType still pass.

Found while debugging TestInstanceNonValidatorBootstraps on fix/cachedstorage-seq-only-lookup, where the stale entries became reachable by finality-sensitive callers.

🤖 Generated with Claude Code

…finalized

The non-validator's storage wrapped the raw storage instead of the block
cache, so blocks cached at verification were never evicted at indexing.
The cache grew with every replicated block and served finalized blocks
without their finalization.
Comment thread instance.go
epoch: epochNum,
Storage: i.Config.Storage,
epoch: epochNum,
// Index through the cache so blocks inserted upon verification are evicted once finalized.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

// Index through the cache so blocks inserted upon verification are evicted once finalized.

This is a weird place to place this comment.

I think if we want to comment this, it should be above the struct description and not here.

Comment thread instance_test.go

// TestInstanceNonValidatorEvictsFinalizedBlocks asserts that a non-validator serves replicated
// blocks with their finalization once they are finalized. Blocks are cached as unfinalized upon
// verification, so indexing must evict them (instance.go:161) or they are served without a

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

we should not reference line numbers in comments. There is no way line numbers won't change.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

This comment is for all line numbers going forward

Comment thread instance_test.go
block, ok := storage2.blockAt(seq)
require.True(t, ok)
digest := (&ParsedBlock{StateMachineBlock: block}).BlockHeader().Digest
_, finalization, err := nonValidatorInstance.cs.Retrieve(seq, digest)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

What does this prove? We could still be retrieving this from the storage right?

I think we can just empty the dependency of the storage of the non-validator and see that it can still retrieve blocks.

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.

2 participants