Skip to content

Commit

Permalink
use create_justification, as in the informal spec
Browse files Browse the repository at this point in the history
  • Loading branch information
konnov committed Nov 27, 2024
1 parent c586f85 commit aafa601
Showing 1 changed file with 42 additions and 6 deletions.
48 changes: 42 additions & 6 deletions spec/protocol-spec/replica.qnt
Original file line number Diff line number Diff line change
Expand Up @@ -601,7 +601,7 @@ module replica {

| Some(qc) => {
val self1 = self.process_commit_qc(Some(qc))
start_new_view(id, self1, signed_vote.vote.view + 1, Commit(qc))
start_new_view(id, self1, signed_vote.vote.view + 1)
}
},

Expand Down Expand Up @@ -678,7 +678,7 @@ module replica {
...self.process_commit_qc(qc.high_commit_qc),
high_timeout_qc: max_timeout_qc(qc_opt, self.high_timeout_qc)
}
start_new_view(id, self1, signed_vote.vote.view + 1, Timeout(qc)),
start_new_view(id, self1, signed_vote.vote.view + 1),
}
},
// unchanged variables
Expand Down Expand Up @@ -711,7 +711,7 @@ module replica {
}

if (new_view_view > self.view) {
start_new_view(id, self1, new_view_view, new_view.justification)
start_new_view(id, self1, new_view_view)
} else {
all {
replica_state' = replica_state,
Expand All @@ -731,7 +731,8 @@ module replica {
// A step by the proposer for replica_id.
// We pass new_block, which is used a substitute for: self.create_proposal(block_number).
action proposer_step(replica_id: ReplicaId, new_block: Block): bool = all {
val replica_state_view = replica_state.get(replica_id).view
val replica = replica_state.get(replica_id)
val replica_state_view = replica.view
val proposer_state_view = proposer_view.get(replica_id)
all {
// Check if we are in a new view and we are the leader.
Expand All @@ -745,7 +746,7 @@ module replica {
// Get the justification for this view. If we have both a commit QC
// and a timeout QC for this view (highly unlikely), we should prefer
// to use the commit QC.
val justification = ghost_justifications.get((replica_id, replica_state_view))
val justification = replica.create_justification()
// Get the block number and check if this must be a reproposal.
val block_and_hash = justification.get_implied_block()
val block_number = block_and_hash._1
Expand Down Expand Up @@ -798,8 +799,9 @@ module replica {
}

// a correct replica changes to a new view
action start_new_view(id: ReplicaId, self: ReplicaState, view: ViewNumber, justification: Justification): bool = {
action start_new_view(id: ReplicaId, self: ReplicaState, view: ViewNumber): bool = {
// make sure that we do not go out of bounds with the new view
val justification = self.create_justification()
all {
VIEWS.contains(view),
// switch to the Prepare phase
Expand Down Expand Up @@ -1016,6 +1018,26 @@ module replica {
}
}

def create_justification(self: ReplicaState): Justification = {
// We always have a timeout QC, at least, for the view 0.
// However, the type checker needs a well-typed value. Hence, use empty_tqc.
val empty_tqc: TimeoutQC = {
votes: Map(), agg_sig: Set(), high_commit_qc: None, ghost_view: 0
}
val high_tqc = self.high_timeout_qc.unwrap_or(empty_tqc)
match (self.high_commit_qc) {
| None =>
Timeout(high_tqc)

| Some(cqc) =>
if (cqc.vote.view >= high_tqc.ghost_view) {
Commit(cqc)
} else {
Timeout(high_tqc)
}
}
}

def justification_verify(justification: Justification): bool = {
match (justification) {
| Timeout(qc) =>
Expand Down Expand Up @@ -1675,4 +1697,18 @@ module replica {
val views_over_2_example = CORRECT.forall(id => {
replica_state.get(id).view <= 2
})

// check this falsy invariant to see an example of a replica having
// both a high commit QC and a timeout QC for the same view
val high_commit_and_timeout_qc_example = CORRECT.forall(id => {
val self = replica_state.get(id)
match (self.high_commit_qc) {
| None => true
| Some(cqc) =>
match (self.high_timeout_qc) {
| None => true
| Some(tqc) => cqc.vote.view != tqc.ghost_view
}
}
})
}

0 comments on commit aafa601

Please sign in to comment.