Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 15 additions & 8 deletions gpbft/gpbft.go
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,7 @@ func (i *instance) Receive(msg *GMessage) error {
}

func (i *instance) ReceiveAlarm() error {
if err := i.tryCompletePhase(); err != nil {
if err := i.tryCurrentPhase(); err != nil {
return fmt.Errorf("failed completing protocol phase: %w", err)
}

Expand Down Expand Up @@ -274,8 +274,16 @@ func (i *instance) receiveOne(msg *GMessage) error {
if i.phase == TERMINATED_PHASE {
return nil // No-op
}
round := i.roundState(msg.Vote.Round)
// Ignore QUALITY messages after exiting the QUALITY phase.
// Ignore CONVERGE and PREPARE messages for prior rounds.
forPriorRound := msg.Vote.Round < i.round
if (msg.Vote.Step == QUALITY_PHASE && i.phase != QUALITY_PHASE) ||
(forPriorRound && msg.Vote.Step == CONVERGE_PHASE) ||
(forPriorRound && msg.Vote.Step == PREPARE_PHASE) {
return nil
}

round := i.roundState(msg.Vote.Round)
switch msg.Vote.Step {
case QUALITY_PHASE:
// Receive each prefix of the proposal independently.
Expand Down Expand Up @@ -309,17 +317,18 @@ func (i *instance) receiveOne(msg *GMessage) error {
i.log("unexpected message %v", msg)
}

// Try to complete the current phase.
// Every COMMIT phase stays open to new messages even after the protocol moves on to
// a new round. Late-arriving COMMITS can still (must) cause a local decision, *in that round*.
// Try to complete the COMMIT phase for the round specified by the message.
if msg.Vote.Step == COMMIT_PHASE && i.phase != DECIDE_PHASE {
return i.tryCommit(msg.Vote.Round)
}
return i.tryCompletePhase()
// Try to complete the current phase in the current round.
return i.tryCurrentPhase()
}

// Attempts to complete the current phase and round.
func (i *instance) tryCompletePhase() error {
func (i *instance) tryCurrentPhase() error {
i.log("try step %s", i.phase)
switch i.phase {
case QUALITY_PHASE:
Expand Down Expand Up @@ -363,8 +372,6 @@ func (i *instance) validateMessage(msg *GMessage) error {

// Check phase-specific constraints.
switch msg.Vote.Step {
case INITIAL_PHASE:
return xerrors.Errorf("invalid vote step: %v", INITIAL_PHASE)
case QUALITY_PHASE:
if msg.Vote.Round != 0 {
return xerrors.Errorf("unexpected round %d for quality phase", msg.Vote.Round)
Expand Down Expand Up @@ -392,7 +399,7 @@ func (i *instance) validateMessage(msg *GMessage) error {
case PREPARE_PHASE, COMMIT_PHASE:
// No additional checks for PREPARE and COMMIT.
default:
return xerrors.Errorf("unknown vote step: %d", msg.Vote.Step)
return xerrors.Errorf("invalid vote step: %d", msg.Vote.Step)
}

// Check vote signature.
Expand Down
4 changes: 2 additions & 2 deletions gpbft/participant_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -433,7 +433,7 @@ func TestParticipant_ValidateMessage(t *testing.T) {
},
}
},
wantErr: "invalid vote step: INITIAL",
wantErr: "invalid vote step: 0",
},
{
name: "unknown vote step is error",
Expand All @@ -446,7 +446,7 @@ func TestParticipant_ValidateMessage(t *testing.T) {
},
}
},
wantErr: "unknown vote step: 42",
wantErr: "invalid vote step: 42",
},
{
name: "QUALITY with non-zero vote round is error",
Expand Down