-
Notifications
You must be signed in to change notification settings - Fork 780
Description
Originally posted by @cason in #2018 (comment):
A note to remember: we are forcing a `Proposal` to be received to run the prevote logic. While this is necessary when POLRound == -1, it might not be otherwise.
The PBTS-enabled consensus code adds the requirement of receiving and accepting a Proposal to precommit a block:
cometbft/internal/consensus/state.go
Lines 1619 to 1621 in 1733219
| if cs.Proposal == nil || cs.ProposalBlock == nil { | |
| logger.Debug("precommit step; did not receive proposal, precommitting nil") | |
| cs.signAddVote(types.PrecommitType, nil, types.PartSetHeader{}, nil) |
This requirement is not present in the original code, in the main branch, where the absence of a valid proposal (cs.Proposal) does not cause the node to precommit nil. The reason for which is that a node may realize that a proposal block has become valid, because it received a Polka, in the case the blockID in the following code:
cometbft/internal/consensus/state.go
Lines 2374 to 2376 in 1733219
| if !cs.ProposalBlockParts.HasHeader(blockID.PartSetHeader) { | |
| cs.ProposalBlockParts = types.NewPartSetFromHeader(blockID.PartSetHeader) | |
| } |
What happens here is that the node starts "looking" for this block, by updating its cs.ProposalBlockParts field. There are two possibilities to consider here:
- The node received a
Proposalfor a block that doesn't match theblockIDthat became valid. This happens when a Byzantine proposer produces multiple proposals in a round. This is not the case considered int this issue, since thecs.Proposalshould be set, probably for a different block, but the code doesn't care. - The node has not received any valid
Proposal, so it is not building any block. This is the scenario addressed here.
The general point here is that if we received a Polka for a block, it does not matter the (first valid) Proposal we received, not even if we have not received any Proposal. This block has been deemed valid by 2/3+ validators, so there is no reason for not precommiting it. Note that we use the same rationale in PBTS when we receive a Proposal backed by a Polka in a POLRound: we don't check the block time again, as it was accepted by a quorum of validators.
With this in mind, this additional check added to the precommit round step does not make sense:
cometbft/internal/consensus/state.go
Lines 1625 to 1628 in 1733219
| // If the proposal time does not match the block time, precommit nil. | |
| if !cs.Proposal.Timestamp.Equal(cs.ProposalBlock.Header.Time) { | |
| logger.Debug("precommit step: proposal timestamp not equal; precommitting nil") | |
| cs.signAddVote(types.PrecommitType, nil, types.PartSetHeader{}, nil) |
While it is probably the only reason for requiring cs.Proposal != nil to get to this point. My proposal is then:
- Remove the
cs.Proposal != nilcondition to precommit a block (cs.enterPrecommit) - Remove the
cs.Proposal.Timestamp.Equal(cs.ProposalBlock.Header.Time)check at the same step