Skip to content

fix(simplex): retry certificate assembly after quorum - #4526

Open
pekkahcut wants to merge 1 commit into
commonwarexyz:mainfrom
pekkahcut:fix-batcher-assemble-none-retry
Open

fix(simplex): retry certificate assembly after quorum#4526
pekkahcut wants to merge 1 commit into
commonwarexyz:mainfrom
pekkahcut:fix-batcher-assemble-none-retry

Conversation

@pekkahcut

Copy link
Copy Markdown

Fixes #4409

Certificate recovery currently treats vote-count quorum as sufficient for certificate assembly. Some certificate schemes may still return None from assemble() at that point, which causes the batcher to panic and discard the verified votes.

This keeps verified votes buffered until assembly actually succeeds. If assembly returns None, later verified votes can trigger another recovery attempt.

Changes:

  • keep verified quorum votes available until successful certificate construction
  • only mark a certification complete after assembly succeeds
  • cover the case where vote-count quorum is reached before the scheme's assembly threshold

Validation:

  • cargo test -p commonware-consensus
  • cargo clippy -p commonware-consensus --all-targets -- -D warnings
  • git diff --check

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Want fixes drafted automatically? Bugbot Autofix can create code changes for findings. A team admin can enable Autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit b5690a0. Configure here.

if let Some(finalization) = finalization {
self.finalize.complete();
return Some(Certificate::Finalization(finalization));
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pending votes stall after failed assembly

Medium Severity

Certificate recovery now leaves a kind Incomplete after vote-count quorum when assemble returns None, but should_verify still stops once verified reaches quorum. Later network votes stay in pending and never join the set that verified_quorum clones, so a retry cannot pick up the extra shares the scheme still needs.

Additional Locations (2)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit b5690a0. Configure here.

@Sertug17

Copy link
Copy Markdown

The fix correctly removes the panic, but should_verify still gates on verified >= quorum (verifier.rs L100-107). After a failed assembly, new votes arriving later stay stuck in pending and can never flow into the verified set to trigger a retry. The fix also needs should_verify to keep returning true while kind is still Incomplete, so shares that missed the initial quorum cutoff can still complete assembly.

Sertug17 added a commit to Sertug17/monorepo that referenced this pull request Aug 19, 2026
… stall

When Scheme::assemble returns None despite a participant-count quorum
(e.g. weighted schemes where minority participants meet the count but
not the share threshold), try_construct_certificate used to panic via
.expect() — and after PR commonwarexyz#4526, silently stall because try_complete()
set state to Complete with no certificate, causing all subsequent votes
to be dropped.

Fix:
- Add assembly_failed: bool to Certification<V>
- Loosen try_complete() guard to allow re-attempts after failed assembly
- Add revert_complete(votes) that resets state from Complete back to
  Incomplete and sets assembly_failed = true
- Update should_verify() to return true when assembly_failed is set and
  pending votes exist, bypassing the participant-count quorum gate
- Clone votes before the offload closure in try_construct_certificate
  so they can be restored on failure; call revert_complete() on None

Closes commonwarexyz#4409. Supersedes commonwarexyz#4526.
Sertug17 added a commit to Sertug17/monorepo that referenced this pull request Aug 19, 2026
… stall

When Scheme::assemble returns None despite a participant-count quorum
(e.g. weighted schemes where minority participants meet the count but
not the share threshold), try_construct_certificate used to panic via
.expect() — and after PR commonwarexyz#4526, silently stall because try_complete()
set state to Complete with no certificate, causing all subsequent votes
to be dropped.

Fix:
- Add assembly_failed: bool to Certification<V>
- Loosen try_complete() guard to allow re-attempts after failed assembly
- Add revert_complete(votes) that resets state from Complete back to
  Incomplete and sets assembly_failed = true
- Update should_verify() to return true when assembly_failed is set and
  pending votes exist, bypassing the participant-count quorum gate
- Clone votes before the offload closure in try_construct_certificate
  so they can be restored on failure; call revert_complete() on None

Closes commonwarexyz#4409. Supersedes commonwarexyz#4526.
Sertug17 added a commit to Sertug17/monorepo that referenced this pull request Aug 19, 2026
… stall

When Scheme::assemble returns None despite a participant-count quorum
(e.g. weighted schemes where minority participants meet the count but
not the share threshold), try_construct_certificate used to panic via
.expect() — and after PR commonwarexyz#4526, silently stall because try_complete()
set state to Complete with no certificate, causing all subsequent votes
to be dropped.

Fix:
- Add assembly_failed: bool to Certification<V>
- Loosen try_complete() guard to allow re-attempts after failed assembly
- Add revert_complete(votes) that resets state from Complete back to
  Incomplete and sets assembly_failed = true
- Update should_verify() to return true when assembly_failed is set and
  pending votes exist, bypassing the participant-count quorum gate
- Clone votes before the offload closure in try_construct_certificate
  so they can be restored on failure; call revert_complete() on None

Closes commonwarexyz#4409. Supersedes commonwarexyz#4526.
Sertug17 added a commit to Sertug17/monorepo that referenced this pull request Aug 19, 2026
… stall

When Scheme::assemble returns None despite a participant-count quorum
(e.g. weighted schemes where minority participants meet the count but
not the share threshold), try_construct_certificate used to panic via
.expect() — and after PR commonwarexyz#4526, silently stall because try_complete()
set state to Complete with no certificate, causing all subsequent votes
to be dropped.

Fix:
- Add assembly_failed: bool to Certification<V>
- Loosen try_complete() guard to allow re-attempts after failed assembly
- Add revert_complete(votes) that resets state from Complete back to
  Incomplete and sets assembly_failed = true
- Update should_verify() to return true when assembly_failed is set and
  pending votes exist, bypassing the participant-count quorum gate
- Clone votes before the offload closure in try_construct_certificate
  so they can be restored on failure; call revert_complete() on None

Closes commonwarexyz#4409. Supersedes commonwarexyz#4526.
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.

simplex/batcher: certificate recovery panics on schemes where assemble legally returns None

2 participants