diff --git a/internal/consensus/state.go b/internal/consensus/state.go index 7d31af906..2cee22972 100644 --- a/internal/consensus/state.go +++ b/internal/consensus/state.go @@ -1402,7 +1402,7 @@ func (cs *State) proposalIsTimely() bool { MessageDelay: cs.state.ConsensusParams.Synchrony.MessageDelay, } - return cs.Proposal.IsTimely(cs.ProposalReceiveTime, sp) + return cs.Proposal.IsTimely(cs.ProposalReceiveTime, sp, cs.Round) } func (cs *State) defaultDoPrevote(ctx context.Context, height int64, round int32) { @@ -2590,7 +2590,7 @@ func (cs *State) calculateProposalTimestampDifferenceMetric() { MessageDelay: cs.state.ConsensusParams.Synchrony.MessageDelay, } - isTimely := cs.Proposal.IsTimely(cs.ProposalReceiveTime, tp) + isTimely := cs.Proposal.IsTimely(cs.ProposalReceiveTime, tp, cs.Round) cs.metrics.ProposalTimestampDifference.With("is_timely", fmt.Sprintf("%t", isTimely)). Observe(cs.ProposalReceiveTime.Sub(cs.Proposal.Timestamp).Seconds()) } diff --git a/types/proposal.go b/types/proposal.go index 87171ff46..a4009eea2 100644 --- a/types/proposal.go +++ b/types/proposal.go @@ -3,6 +3,7 @@ package types import ( "errors" "fmt" + "math/bits" "time" "github.com/tendermint/tendermint/internal/libs/protoio" @@ -89,11 +90,26 @@ func (p *Proposal) ValidateBasic() error { // // 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, sp SynchronyParams) bool { +func (p *Proposal) IsTimely(recvTime time.Time, sp SynchronyParams, round int32) bool { + // The message delay values are scaled as rounds progress. + // Every 10 rounds, the message delay is doubled to allow consensus to + // proceed in the case that the chosen value was too small for the given network conditions. + // For more information and discussion on this mechanism, see the relevant github issue: + // https://github.com/tendermint/spec/issues/371 + maxShift := bits.LeadingZeros64(uint64(sp.MessageDelay)) - 1 + nShift := int((round / 10)) + + if nShift > maxShift { + // if the number of 'doublings' would would overflow the size of the int, use the + // maximum instead. + nShift = maxShift + } + msgDelay := sp.MessageDelay * time.Duration(1<