Introduction
In the section CometBFT’s expected behaviour, we presented the most common behaviour, usually referred to as the good case. However, the grammar specified in the same section is more general and covers more scenarios that an Application designer needs to account for. In this section, we give more information about these possible scenarios. We focus on methods introduced by ABCI++:PrepareProposal and ProcessProposal. Specifically, we concentrate
on the part of the grammar presented below.
- network asynchrony, and
- a Byzantine process being the proposer.
- Call
PrepareProposaland/orProcessProposalfor block . - Call
PrepareProposaland/orProcessProposalfor block . - Does not call
PrepareProposaland/orProcessProposal.
PrepareProposal call is always followed by the
ProcessProposal call. The reason is that the process also broadcasts the proposal to itself, which is locally delivered and triggers the ProcessProposal call.
The proposal processed by ProcessProposal is the same as what was returned by any of the preceding PrepareProposal invoked for the same height and round.
While in the absence of restarts there is only one such preceding invocations, if the proposer restarts there could have been one extra invocation to PrepareProposal for each restart.
As the number of rounds the consensus algorithm needs to decide in a given run is a priori unknown, the
application needs to account for any number of rounds, where each round can exhibit any of these three
behaviours. Recall that the application is unaware of the internals of consensus and thus of the rounds.
Possible scenarios
The unknown number of rounds we can have when following the consensus algorithm yields a vast number of scenarios we can expect. Listing them all is unfeasible. However, here we give several of them and draw the main conclusions. Specifically, we will show that before block is decided:- On a correct node,
PrepareProposalmay be called multiple times and for different blocks (Scenario 1). - On a correct node,
ProcessProposalmay be called multiple times and for different blocks (Scenario 2). - On a correct node,
PrepareProposalandProcessProposalfor block may not be called (Scenario 3). - On a correct node,
PrepareProposalandProcessProposalmay not be called at all (Scenario 4).
Basic information
Each scenario is presented from the perspective of a process . More precisely, we show what happens in each round’s of the Tendermint consensus algorithm. While in practice the consensus algorithm works with respect to voting power of the validators, in this document we refer to number of processes (e.g., , , ) for simplicity. The legend is below:Round X
- Propose: Describes what happens while .
- Prevote: Describes what happens while .
- Precommit: Describes what happens while .
Scenario 1
callsProcessProposal many times with different values.
Round 0
- Propose: The proposer of this round is a Byzantine process, and it chooses not to send the proposal
message. Therefore, ‘s expires, it sends for , and it does not call
ProcessProposal. All correct processes do the same. - Prevote: eventually receives messages for and starts . When expires it sends for .
- Precommit: eventually receives messages for and starts . When it expires, it moves to the next round.
Round 1
- Propose: A correct process is the proposer in this round. Its is , and it is free
to generate and propose a new block . Process receives this proposal in time, calls
ProcessProposalfor block , and broadcasts a message for it. - Prevote: Due to network asynchrony less than processes send for this block. Therefore, does not update in this round.
- Precommit: Since less than processes send , no correct process will lock on this block and send message. As a consequence, does not decide on .
Round 2
- Propose: Same as in Round 1, just another correct process is the proposer, and it
proposes another value . Process receives the proposal on time, calls
ProcessProposalfor new block , and broadcasts a message for it. - Prevote: Same as in Round 1.
- Precommit: Same as in Round 1.
ProcessProposal
anymore for this height.
Scenario 2
callsPrepareProposal many times with different values.
Round 0
- Propose: Process is the proposer in this round. Its is , and it is free to
generate and propose new block . Before proposing, it calls
PrepareProposalfor . After that, it broadcasts the proposal, delivers it to itself, callsProcessProposaland broadcasts for it. - Prevote: Due to network asynchrony less than processes receive the proposal on time and send for it. Therefore, does not update in this round.
- Precommit: Since less than processes send , no correct process will lock on this block and send non- message. As a consequence, does not decide on .
PrepareProposal again but for a different value. When it reaches round
some process will propose block and if receives messages, it will decide on this
value.
Scenario 3
callsPrepareProposal and ProcessProposal for many values, but decides on a value for which it did
not call PrepareProposal or ProcessProposal.
In this scenario, in all rounds before we can have any round presented in Scenario 1 or
Scenario 2. What is important is that:
-
no proposer proposed block or if it did, process , due to asynchrony, did not receive it in time,
so it did not call
ProcessProposal, and - if was the proposer it proposed some other value .
Round
- Propose: A correct process is the proposer in this round, and it proposes block .
Due to asynchrony, the proposal message arrives to process after its
expires and it sends for . Consequently, process does not call
ProcessProposalfor block . However, the same proposal arrives at other processes before their expires, and they send for this proposal. - Prevote: Process receives messages for proposal , updates correspondingly its and and sends message. All correct processes do the same.
- Precommit: Finally, process receives messages, and decides on block .
Scenario 4
Scenario 3 can be translated into a scenario where does not callPrepareProposal and
ProcessProposal at all. For this, it is necessary that process is not the proposer in any of the
rounds and that due to network asynchrony or Byzantine proposer, it does not receive the
proposal before expires. As a result, it will enter round without calling
PrepareProposal and ProcessProposal before it, and as shown in Round of Scenario 3 it
will decide in this round. Again without calling any of these two calls.