fix(simplex/batcher): handle weighted scheme assembly failure without stall - #4539
Open
Sertug17 wants to merge 1 commit into
Open
fix(simplex/batcher): handle weighted scheme assembly failure without stall#4539Sertug17 wants to merge 1 commit into
Sertug17 wants to merge 1 commit into
Conversation
Sertug17
force-pushed
the
fix/simplex-batcher-weighted-assembly
branch
from
August 19, 2026 18:20
705b731 to
1fb0266
Compare
Sertug17
force-pushed
the
fix/simplex-batcher-weighted-assembly
branch
from
August 19, 2026 18:34
1fb0266 to
eb64032
Compare
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using high effort and found 2 potential issues.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit eb64032. Configure here.
… 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
force-pushed
the
fix/simplex-batcher-weighted-assembly
branch
from
August 19, 2026 19:06
eb64032 to
b9fa1e5
Compare
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.

Closes #4409. Supersedes #4526.
Problem
try_construct_certificatepanics and after #4526, stalls whenScheme::assemblereturnsNonedespite a participant-count quorum being met. This happens with weighted / threshold schemes (e.g. stake distribution[7, 1, 1, 1]with a share threshold of 8): the three minority participants verify,verified.len() >= quorumtriggerstry_complete(), which consumes the votes and sets state toComplete, then assembly fails because only 3 shares are available (not 8).After that:
.expect("verified … quorum must assemble")→ panicComplete, so thehigh-weight signer's vote arrives and is silently dropped → permanent stall
should_verify()also gates onverified.len() < self.quorumand neverre-admits pending votes, even when a higher-weight signer is waiting
Fix
Certification<V>assembly_failed: boolfieldtry_complete()guard: allow re-attempts whenassembly_failedis set, even ifverified.len() < self.quorumrevert_complete(votes): resets state fromCompleteback toIncompleteand setsassembly_failed = trueshould_verify(): returntruewhenassembly_failed && !pending.is_empty(), bypassing the participant-count quorum gatetry_construct_certificate.expect(…)from assembly callsoffloadclosure so they can be restored on failurerevert_complete(backup)when assembly returnsNoneTesting
cargo test -p commonware-consensus simplex::actors::batcher
96 passed; 0 failed