diff --git a/types/block.go b/types/block.go index 306675b7f..dcae746a3 100644 --- a/types/block.go +++ b/types/block.go @@ -17,7 +17,6 @@ import ( "github.com/tendermint/tendermint/libs/bits" tmbytes "github.com/tendermint/tendermint/libs/bytes" tmmath "github.com/tendermint/tendermint/libs/math" - tmtime "github.com/tendermint/tendermint/libs/time" tmproto "github.com/tendermint/tendermint/proto/tendermint/types" "github.com/tendermint/tendermint/version" ) @@ -95,25 +94,6 @@ func (b *Block) ValidateBasic() error { return nil } -// IsTimely validates that the block timestamp is 'timely' according to the proposer-based timestamp algorithm. -// To evaluate if a block is timely, its timestamp 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 && proposedBlockTime < validatorLocalTime + Precision + MsgDelay. -// -// 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 (b *Block) IsTimely(clock tmtime.Source, p TimestampParams) bool { - lt := clock.Now() - lhs := lt.Add(-p.Precision) - rhs := lt.Add(p.Precision).Add(p.MsgDelay) - if lhs.Before(b.Header.Time) && b.Header.Time.Before(rhs) { - return true - } - return false -} - // fillHeader fills in any remaining header fields that are a function of the block data func (b *Block) fillHeader() { if b.LastCommitHash == nil { diff --git a/types/block_test.go b/types/block_test.go index 78b957324..1c762653b 100644 --- a/types/block_test.go +++ b/types/block_test.go @@ -24,7 +24,6 @@ import ( "github.com/tendermint/tendermint/libs/bytes" tmrand "github.com/tendermint/tendermint/libs/rand" tmtime "github.com/tendermint/tendermint/libs/time" - tmtimemocks "github.com/tendermint/tendermint/libs/time/mocks" tmproto "github.com/tendermint/tendermint/proto/tendermint/types" tmversion "github.com/tendermint/tendermint/proto/tendermint/version" "github.com/tendermint/tendermint/version" @@ -1348,67 +1347,3 @@ func TestHeaderHashVector(t *testing.T) { require.Equal(t, tc.expBytes, hex.EncodeToString(hash)) } } - -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.Nanosecond), - precision: time.Nanosecond * 2, - msgDelay: time.Nanosecond, - 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.Nanosecond), - precision: time.Nanosecond * 2, - msgDelay: time.Nanosecond, - 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.Nanosecond), - localTime: genesisTime, - precision: time.Nanosecond * 2, - msgDelay: time.Nanosecond, - expectTimely: false, - }, - } - for _, testCase := range testCases { - t.Run(testCase.name, func(t *testing.T) { - b := Block{ - Header: Header{ - Time: testCase.blockTime, - }, - } - - p := TimestampParams{ - Precision: testCase.precision, - MsgDelay: testCase.msgDelay, - } - - mockSource := new(tmtimemocks.Source) - mockSource.On("Now").Return(testCase.localTime) - - ti := b.IsTimely(mockSource, p) - assert.Equal(t, testCase.expectTimely, ti) - }) - } -} diff --git a/types/params.go b/types/params.go index e979622d5..c4c83b01f 100644 --- a/types/params.go +++ b/types/params.go @@ -41,6 +41,7 @@ type ConsensusParams struct { Evidence EvidenceParams `json:"evidence"` Validator ValidatorParams `json:"validator"` Version VersionParams `json:"version"` + Timestamp TimestampParams `json:"timestamp"` } // HashedParams is a subset of ConsensusParams. @@ -126,10 +127,12 @@ func DefaultVersionParams() VersionParams { } func DefaultTimestampParams() TimestampParams { + // TODO(@wbanfield): Determine experimental values for these defaults + // https://github.com/tendermint/tendermint/issues/7202 return TimestampParams{ - Precision: 0, - Accuracy: 0, - MsgDelay: 0, + Precision: 2 * time.Second, + Accuracy: 500 * time.Millisecond, + MsgDelay: 3 * time.Second, } } diff --git a/types/proposal.go b/types/proposal.go index 450cc2a43..0bd90fd4d 100644 --- a/types/proposal.go +++ b/types/proposal.go @@ -79,6 +79,25 @@ func (p *Proposal) ValidateBasic() error { return nil } +// IsTimely validates that the block timestamp is 'timely' according to the proposer-based timestamp algorithm. +// To evaluate if a block is timely, its timestamp 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 && proposedBlockTime < validatorLocalTime + Precision + MsgDelay. +// +// 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(clock tmtime.Source, tp TimestampParams) bool { + lt := clock.Now() + lhs := lt.Add(-tp.Precision) + rhs := lt.Add(tp.Precision).Add(tp.MsgDelay) + if lhs.Before(p.Timestamp) && p.Timestamp.Before(rhs) { + return true + } + return false +} + // String returns a string representation of the Proposal. // // 1. height diff --git a/types/proposal_test.go b/types/proposal_test.go index 47f5a8890..ca8b806be 100644 --- a/types/proposal_test.go +++ b/types/proposal_test.go @@ -13,6 +13,7 @@ import ( "github.com/tendermint/tendermint/crypto/tmhash" "github.com/tendermint/tendermint/internal/libs/protoio" tmrand "github.com/tendermint/tendermint/libs/rand" + tmtimemocks "github.com/tendermint/tendermint/libs/time/mocks" tmproto "github.com/tendermint/tendermint/proto/tendermint/types" ) @@ -191,3 +192,65 @@ func TestProposalProtoBuf(t *testing.T) { } } } + +func TestIsTimely(t *testing.T) { + genesisTime, err := time.Parse(time.RFC3339, "2019-03-13T23:00:00Z") + require.NoError(t, err) + testCases := []struct { + name string + proposalTime 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", + proposalTime: genesisTime, + localTime: genesisTime.Add(1 * time.Nanosecond), + precision: time.Nanosecond * 2, + msgDelay: time.Nanosecond, + expectTimely: true, + }, + { + // Checking that the following inequality evaluates to false: + // 3 - 2 < 0 < 3 + 2 + 1 + name: "local time too large", + proposalTime: genesisTime, + localTime: genesisTime.Add(3 * time.Nanosecond), + precision: time.Nanosecond * 2, + msgDelay: time.Nanosecond, + expectTimely: false, + }, + { + // Checking that the following inequality evaluates to false: + // 0 - 2 < 2 < 2 + 1 + name: "proposal time too large", + proposalTime: genesisTime.Add(4 * time.Nanosecond), + localTime: genesisTime, + precision: time.Nanosecond * 2, + msgDelay: time.Nanosecond, + expectTimely: false, + }, + } + for _, testCase := range testCases { + t.Run(testCase.name, func(t *testing.T) { + p := Proposal{ + Timestamp: testCase.proposalTime, + } + + tp := TimestampParams{ + Precision: testCase.precision, + MsgDelay: testCase.msgDelay, + } + + mockSource := new(tmtimemocks.Source) + mockSource.On("Now").Return(testCase.localTime) + + ti := p.IsTimely(mockSource, tp) + assert.Equal(t, testCase.expectTimely, ti) + }) + } +}