Skip to content

Commit ef4b114

Browse files
committed
Removed invalid state for VoteCollector
1 parent 7e0964b commit ef4b114

File tree

3 files changed

+1
-56
lines changed

3 files changed

+1
-56
lines changed

consensus/hotstuff/vote_collector.go

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,6 @@ const (
3232
// VoteCollectorStatusVerifying is for the status when the block has been received,
3333
// and is able to process all votes for it.
3434
VoteCollectorStatusVerifying
35-
36-
// VoteCollectorStatusInvalid is for the status when the block has been verified and
37-
// is invalid. All votes to this block will be collected to slash the voter.
38-
VoteCollectorStatusInvalid
3935
)
4036

4137
// VoteCollector collects votes for the same block, produces QC when enough votes are collected

consensus/hotstuff/votecollector/statemachine.go

Lines changed: 1 addition & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -243,9 +243,7 @@ func (m *VoteCollector) processVote(vote *model.Vote) error {
243243
// Informally, the state transition will happen _after_ we cached the vote.
244244
// * Case (c): `currentState` = [VoteCollectorStatusCaching] while `m.Status()` = [VoteCollectorStatusVerifying].
245245
// In this scenario, the vote is being fed into the [NoopProcessor] first, before we realize that the state has changed. However,
246-
// since the status has changed, the check below will trigger a repeat of the processing, which will then enter case (a)
247-
// (or leave the happy path by transitioning to [VoteCollectorStatusInvalid], implying we are dealing with a byzantine proposer, in which
248-
// case we may drop all votes anyway).
246+
// since the status has changed, the check below will trigger a repeat of the processing, which will then enter case (a).
249247
// We have shown that all votes will reach the [VerifyingVoteProcessor] on the happy path.
250248
//
251249
// CAUTION: In the proof, we utilized that reading the `votesCache` happens before writing to it (case b). It is important to emphasize that
@@ -283,8 +281,6 @@ func (m *VoteCollector) View() uint64 {
283281
// equal to `expectedValue`. The implementation only allows the transitions
284282
//
285283
// CachingVotes → VerifyingVotes
286-
// CachingVotes → Invalid
287-
// VerifyingVotes → Invalid
288284
//
289285
// No errors are expected during normal operation (Byzantine edge cases handled via notifications internally).
290286
func (m *VoteCollector) ProcessBlock(proposal *model.SignedProposal) error {
@@ -339,13 +335,6 @@ func (m *VoteCollector) ProcessBlock(proposal *model.SignedProposal) error {
339335
return fmt.Errorf("while processing block %v, found that VoteProcessor reports status %s but has an incompatible implementation type %T",
340336
proposal.Block.BlockID, proc.Status(), verifyingProc)
341337
}
342-
if verifyingProc.Block().BlockID != proposal.Block.BlockID {
343-
m.terminateVoteProcessing()
344-
}
345-
346-
// Vote processing for this view has already been terminated. Note: proposal equivocation
347-
// is handled by hotstuff.Forks, so we don't have anything to do here.
348-
case hotstuff.VoteCollectorStatusInvalid: /* no op */
349338

350339
default:
351340
return fmt.Errorf("while processing block %v, found that VoteProcessor reported unknown status %s", proposal.Block.BlockID, proc.Status())
@@ -404,41 +393,6 @@ func (m *VoteCollector) caching2Verifying(proposal *model.SignedProposal) error
404393
return nil
405394
}
406395

407-
// terminateVoteProcessing atomically transitions the VoteCollector into state
408-
// `VoteCollectorStatusInvalid`. if it wasn't already in this state.
409-
func (m *VoteCollector) terminateVoteProcessing() {
410-
currentProcWrapper := m.votesProcessor.Load().(*atomicValueWrapper)
411-
if currentProcWrapper.processor.Status() == hotstuff.VoteCollectorStatusInvalid {
412-
return
413-
}
414-
415-
newProcWrapper := &atomicValueWrapper{
416-
processor: NewNoopCollector(hotstuff.VoteCollectorStatusInvalid),
417-
}
418-
419-
// We now have an optimistically-constructed `newProcWrapper` that represents the desired new state (happy path). We must ensure
420-
// that writing the `newProcWrapper` to `m.votesProcessor` happens ATOMICALLY if and only if the current state is not
421-
// `VoteCollectorStatusInvalid`. The "Compare-And-Swap Loop" (CAS LOOP) is an efficient pattern to implement this:
422-
// (i) We first retrieved the current state (above) and checked whether it is different from `VoteCollectorStatusInvalid`.
423-
// (ii) If so, we attempt to compare-and-swap the current with the new state.
424-
// Note that (i) and (ii) are separate operations. However, the CAS in (ii) ensures that the write only happens if the current state
425-
// is still the same as what we observed in (i). If another thread changed the state in between (i) and (ii), we have worked with
426-
// an outdated view of the current state, and should repeat the attempt to update the state (hence the "loop" in CAS LOOP).
427-
// Since we are storing a pointer in the atomic.Value the value compared will be the reference to the object.
428-
for {
429-
stateUpdateSuccessful := m.votesProcessor.CompareAndSwap(currentProcWrapper, newProcWrapper)
430-
if stateUpdateSuccessful {
431-
return
432-
}
433-
// the `currentProcWrapper` we worked with was stale:
434-
// reload, check if invalid target state has already been reached, and repeat if not
435-
currentProcWrapper = m.votesProcessor.Load().(*atomicValueWrapper)
436-
if currentProcWrapper.processor.Status() == hotstuff.VoteCollectorStatusInvalid {
437-
return
438-
}
439-
}
440-
}
441-
442396
// processCachedVotes feeds all cached votes into the VoteProcessor
443397
func (m *VoteCollector) processCachedVotes(block *model.Block) {
444398
cachedVotes := m.votesCache.All()

consensus/hotstuff/votecollector/statemachine_test.go

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -96,11 +96,6 @@ func (s *StateMachineTestSuite) TestStatus_StateTransitions() {
9696
err := s.collector.ProcessBlock(proposal)
9797
require.NoError(s.T(), err)
9898
require.Equal(s.T(), hotstuff.VoteCollectorStatusVerifying, s.collector.Status())
99-
100-
// after submitting double proposal we should transfer into invalid state
101-
err = s.collector.ProcessBlock(makeSignedProposalWithView(s.view))
102-
require.NoError(s.T(), err)
103-
require.Equal(s.T(), hotstuff.VoteCollectorStatusInvalid, s.collector.Status())
10499
}
105100

106101
// TestStatus_FactoryErrorPropagation verifies that errors from the injected

0 commit comments

Comments
 (0)