Hold the epoch lock while restoring from the WAL - #509
Open
samliok wants to merge 2 commits into
Open
Conversation
… restoring from the WAL
samliok
marked this pull request as ready for review
August 13, 2026 23:22
yacovm
approved these changes
Aug 14, 2026
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.
Fixes a data race caught by CI in
TestReplicatedNotarizationRestart: https://github.com/ava-labs/Simplex/actions/runs/31749442819/job/94611614678Epoch.Start()runs the WAL restore without holding the epoch lock. Restoring can schedule the block building task and arm monitor and timeout callbacks, all of which acquire the lock and mutate epoch state from other goroutines while the restore is still reading it. In the failing test, the restarted node recovers a notarized round from the WAL, becomes leader of the next round mid-restore, and the scheduled block building task writes the rounds map instoreProposalwhile the restore path reads it inhandleFinalizeVoteMessage.Every internal handler assumes the lock is held:
HandleMessagetakes it before dispatching, butrestoreFromWalcalled the same handlers without it.Start()now holds the lock until the restore completes and the epoch is ready to receive messages, so scheduled tasks block until then.broadcastReplicationSyncacquires the lock itself and stays outside the locked region.