Skip to content

Purge previous epoch blocks from replication state in non-validators - #668

Merged
yacovm merged 2 commits into
mainfrom
651
Oct 28, 2026
Merged

yacovm merged 2 commits into
mainfrom
651

Conversation

@yacovm

@yacovm yacovm commented Oct 27, 2026 •

Copy link
Copy Markdown
Collaborator

A non-validator can receive a finalized Telock of the old epoch at seq k+2, where k is the sealing block, before it indexes k+1. The old epoch is still known at that point, so the Telock is verified and kept in the replication state.

Indexing block k+1, the first block of the new epoch, removes the old epoch. The non-validator then picks the stale Telock as the next seq to commit and tries to verify its finalization QC. The old epoch is gone, so this fails with
"expected epoch to have been validated", and the non-validator halts.

This commit tracks the epoch of the last committed block, restored from storage on startup. When a block of a newer epoch is indexed, every block of an older epoch is purged from the replication state. A stale Telock can then no longer take the place of the new epoch's block at the same seq.

This commit purges blocks from previous epochs from the replication state when indexing a block of a new epoch.

Signed-off-by: Yacov Manevich <[email protected]>
@samliok

samliok commented Oct 28, 2026

Copy link
Copy Markdown
Collaborator

I think you mentioned this to me, but maybe a short summary of the issue would help so I don't need to re-read mythos slop? could we also update the other prs as well

@yacovm

yacovm commented Oct 28, 2026

Copy link
Copy Markdown
Collaborator Author

I think you mentioned this to me, but maybe a short summary of the issue would help so I don't need to re-read mythos slop? could we also update the other prs as well

Done

@samliok

samliok commented Oct 28, 2026 •

Copy link
Copy Markdown
Collaborator

Indexing block k+1, the first block of the new epoch, removes the old epoch.

I thought indexing K removes the old epoch?

@yacovm

yacovm commented Oct 28, 2026

Copy link
Copy Markdown
Collaborator Author

Indexing block k+1, the first block of the new epoch, removes the old epoch.

I thought indexing K removes the old epoch?

n.removeOldSequencesAndEpochs(md.Seq, md.Epoch) is what removes the old epoch and it can only cause this by being called with the new epoch.

@samliok samliok left a comment

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.

I think there is a simpler way to do this than add to the replication struct + nonvalidator.

What if we just do

epoch, ok := n.epochs[block.BlockHeader().Epoch]
	if !ok {
		n.Logger.Debug("Next sequence to commit is from an unknown epoch", zap.Uint64("epoch", block.BlockHeader().Epoch))
		n.sequenceReplicator.ResendFinalizationRequest(block.BlockHeader().Seq, n.Comm.Validators().NodeIDs())
		return nil
	}

I think this would be the only necessary prod change

@yacovm
yacovm merged commit 8fd5709 into main Oct 28, 2026
7 checks passed
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.

Stale Telock quorum round permanently halts non-validator after epoch change

2 participants