diff --git a/types/proposal.go b/types/proposal.go index 3c806f657..a6d33ff22 100644 --- a/types/proposal.go +++ b/types/proposal.go @@ -99,6 +99,12 @@ func (p *Proposal) IsTimely(recvTime time.Time, sp SynchronyParams, round int32) roundModifier := time.Duration(math.Exp2(float64(round / 10))) msgDelay := sp.MessageDelay * roundModifier + if msgDelay <= 0 { + // In the case that messaeg delay overflows after applying the round modifier, use the maximum + // duration instead. + msgDelay = time.Nanosecond * math.MaxInt64 + } + // lhs is `proposedBlockTime - Precision` in the first inequality lhs := p.Timestamp.Add(-sp.Precision) // rhs is `proposedBlockTime + MsgDelay + Precision` in the second inequality diff --git a/types/proposal_test.go b/types/proposal_test.go index abfff8e7f..b8b8b3a67 100644 --- a/types/proposal_test.go +++ b/types/proposal_test.go @@ -266,6 +266,17 @@ func TestIsTimely(t *testing.T) { expectTimely: true, round: 10, }, + { + // check that values that overflow time.Duration still correctly register + // as timely when round relaxation applied. + name: "message delay fixed to not overflow time.Duration", + proposalTime: genesisTime, + recvTime: genesisTime.Add(4 * time.Nanosecond), + precision: time.Nanosecond * 2, + msgDelay: time.Nanosecond, + expectTimely: true, + round: 5000, + }, } for _, testCase := range testCases {