diff --git a/internal/consensus/state.go b/internal/consensus/state.go index a157907f8..cac49793a 100644 --- a/internal/consensus/state.go +++ b/internal/consensus/state.go @@ -1345,7 +1345,15 @@ func (cs *State) defaultDoPrevote(height int64, round int32) { } if cs.Proposal.POLRound == -1 && cs.LockedRound == -1 && !cs.proposalIsTimely() { - logger.Debug("prevote step: ProposalBlock is not timely; prevoting nil") + logger.Debug("prevote step: Proposal is not timely; prevoting nil - ", + "proposed", + tmtime.Canonical(cs.Proposal.Timestamp).Format(time.RFC3339Nano), + "received", + tmtime.Canonical(cs.ProposalReceiveTime).Format(time.RFC3339Nano), + "msg_delay", + cs.state.ConsensusParams.Timing.MessageDelay, + "precision", + cs.state.ConsensusParams.Timing.Precision) cs.signAddVote(tmproto.PrevoteType, nil, types.PartSetHeader{}) return } diff --git a/types/proposal.go b/types/proposal.go index d32ab65dd..d0c8b0425 100644 --- a/types/proposal.go +++ b/types/proposal.go @@ -87,6 +87,8 @@ func (p *Proposal) ValidateBasic() error { // localtime >= proposedBlockTime - Precision // localtime <= proposedBlockTime + MsgDelay + Precision // +// Note: If the proposal is for the `initialHeight` the second inequality is not checked. This is because +// the timestamp in this case is set to the preconfigured genesis time. // For more information on the meaning of 'timely', see the proposer-based timestamp specification: // https://github.com/tendermint/spec/tree/master/spec/consensus/proposer-based-timestamp func (p *Proposal) IsTimely(recvTime time.Time, tp TimingParams, initialHeight int64) bool { @@ -95,12 +97,11 @@ func (p *Proposal) IsTimely(recvTime time.Time, tp TimingParams, initialHeight i // rhs is `proposedBlockTime + MsgDelay + Precision` in the second inequality rhs := p.Timestamp.Add(tp.MessageDelay).Add(tp.Precision) - recvTimeAfterOrEqLHS := recvTime.After(lhs) || recvTime.Equal(lhs) - recvTimeBeforeOrEqRHS := recvTime.Before(rhs) || recvTime.Equal(rhs) - if recvTimeAfterOrEqLHS && (p.Height == initialHeight || recvTimeBeforeOrEqRHS) { - return true + if recvTime.Before(lhs) || (p.Height != initialHeight && recvTime.After(rhs)) { + return false } - return false + + return true } // String returns a string representation of the Proposal.