Skip to content

Do not restore a proposal that a sync already delivered - #753

Merged
pfi79 merged 1 commit into
hyperledger:mainfrom
HagarMeir:fix/restore-stale-proposed-record
Nov 4, 2026
Merged

pfi79 merged 1 commit into
hyperledger:mainfrom
HagarMeir:fix/restore-stale-proposed-record

Conversation

@HagarMeir

Copy link
Copy Markdown
Contributor

Fixes #752.

Problem

recoverProposed restored the trailing pre-prepare as in flight without checking its sequence. A sync delivers decisions without writing to the WAL, so a node that persisted a pre-prepare and then caught up by syncing can restart with a WAL that ends with a proposal it has already delivered.

The restored view then re-broadcasts a prepare for that proposal and rejects every prepare of the next sequence as a wrong digest. The node misses that sequence and catches up only through a later sync. No wrong value is delivered.

recoverPrepared and the view-record path from #748 already skip a proposal below the sequence the view starts at; recoverProposed was the only restore path without that check.

Change

Tests

Both fail without the change to recoverProposed.

Run locally: golangci-lint (pinned version, 0 issues), go vet ./..., go test -race -count=1 ./... including the integration suite, and 10 runs each of the new integration test (with -race), TestTryCommittedSequenceTwice and TestRestartKeepsViewAndInFlightProposal.

Written by Claude (AI assistant) on behalf of Hagar Meir.

🤖 Generated with Claude Code

recoverProposed restored the trailing pre-prepare as in flight without
comparing its sequence with the sequence the view starts at. A sync
delivers decisions without writing to the WAL, so a node that persisted a
pre-prepare and then caught up by syncing could restart with a proposal it
had already delivered. The restored view re-broadcast a prepare for it and
rejected every prepare of the next sequence as a wrong digest, so the node
missed that sequence and caught up only through a later sync.

Skip the record when the view already starts after it, as recoverPrepared
and the view-record path do.

TestRestartKeepsViewAndInFlightProposal restarted with a sync, which
delivered the very proposal the test expects to find in flight. Restart it
without a sync, as its description intends.

Fixes hyperledger#752

Written by Claude (AI assistant) on behalf of Hagar Meir.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Hagar Meir <hagar.meir@ibm.com>
@pfi79
pfi79 merged commit 8883d03 into hyperledger:main Nov 4, 2026
6 checks passed
@HagarMeir
HagarMeir deleted the fix/restore-stale-proposed-record branch November 4, 2026 12:19
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.

Restored in-flight proposal below the checkpoint causes wrong-digest rejections after a restart

2 participants