state: add an IsTimely function to implement the check for timely in proposer-based timestamps

This commit is contained in:
William Banfield
2021-10-27 16:23:46 +02:00
parent fe2ed68718
commit c76c0781a0
2 changed files with 69 additions and 0 deletions
+18
View File
@@ -304,6 +304,24 @@ func MedianTime(commit *types.Commit, validators *types.ValidatorSet) time.Time
return weightedMedian(weightedTimes, totalVotingPower)
}
// IsTimely validates that the passed in block timestamp is 'timely' according to the proposer-based timestamp algorithm.
// To evaluate if a timestamp is timely, it is compared to the local time of the validator along with the configured
// Precision and MsgDelay parameters.
// Specifically, a proposed block timestamp is considered timely if it is satisfies the following inequalities:
//
// proposedBlockTime < validatorLocalTime + Precision + MsgDelay && proposedBlockTime > validatorLocaltime - Precision.
//
// 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 IsTimely(bt time.Time, lt time.Time, precision time.Duration, msgDelay time.Duration) bool {
lhs := lt.Add(-precision).UnixMilli()
rhs := lt.Add(precision).Add(msgDelay).UnixMilli()
if lhs < bt.UnixMilli() && bt.UnixMilli() < rhs {
return true
}
return false
}
//------------------------------------------------------------------------
// Genesis
+51
View File
@@ -5,6 +5,7 @@ import (
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
tmtime "github.com/tendermint/tendermint/libs/time"
)
@@ -55,3 +56,53 @@ func TestWeightedMedian(t *testing.T) {
assert.Equal(t, true, (median.After(t1) || median.Equal(t1)) &&
(median.Before(t4) || median.Equal(t4)))
}
func TestIsTimely(t *testing.T) {
genesisTime, err := time.Parse(time.RFC3339, "2019-03-13T23:00:00Z")
require.NoError(t, err)
testCases := []struct {
name string
blockTime time.Time
localTime time.Time
precision time.Duration
msgDelay time.Duration
expectTimely bool
}{
{
// Checking that the following inequality evaluates to true:
// 1 - 2 < 0 < 1 + 2 + 1
name: "basic timely",
blockTime: genesisTime,
localTime: genesisTime.Add(1 * time.Millisecond),
precision: time.Millisecond * 2,
msgDelay: time.Millisecond,
expectTimely: true,
},
{
// Checking that the following inequality evaluates to false:
// 3 - 2 < 0 < 3 + 2 + 1
name: "local time too large",
blockTime: genesisTime,
localTime: genesisTime.Add(3 * time.Millisecond),
precision: time.Millisecond * 2,
msgDelay: time.Millisecond,
expectTimely: false,
},
{
// Checking that the following inequality evaluates to false:
// 0 - 2 < 2 < 2 + 1
name: "block time too large",
blockTime: genesisTime.Add(4 * time.Millisecond),
localTime: genesisTime,
precision: time.Millisecond * 2,
msgDelay: time.Millisecond,
expectTimely: false,
},
}
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
ti := IsTimely(testCase.blockTime, testCase.localTime, testCase.precision, testCase.msgDelay)
assert.Equal(t, testCase.expectTimely, ti)
})
}
}