mirror of
https://github.com/tendermint/tendermint.git
synced 2026-09-13 11:34:17 +00:00
Prevote nil if proposal is not timely (#7415)
* Prevote nil if not timely * William's suggestion to get the proposal from the proposer instead of generating it. * Don't check rhs for genesis block * Update IsTimely to match the specification * Fix proposal tests * Add more timely tests and check votes * Mark proposal invalid in SetProposal, fix in the future test * save proposal time on roundstate * received -> receive * always reset proposal time * Add IsTimely test for genesis proposal * Check timely before ValidateBlock * Review comments from Daniel Co-authored-by: William Banfield <wbanfield@gmail.com>
This commit is contained in:
co-authored by
William Banfield
parent
9e56a95473
commit
8eec8447e8
+2
-2
@@ -129,8 +129,8 @@ func DefaultTimingParams() TimingParams {
|
||||
// TODO(@wbanfield): Determine experimental values for these defaults
|
||||
// https://github.com/tendermint/tendermint/issues/7202
|
||||
return TimingParams{
|
||||
Precision: 1 * time.Nanosecond,
|
||||
MessageDelay: 1 * time.Nanosecond,
|
||||
Precision: 10 * time.Millisecond,
|
||||
MessageDelay: 500 * time.Millisecond,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+14
-8
@@ -84,18 +84,24 @@ func (p *Proposal) ValidateBasic() error {
|
||||
// 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.
|
||||
// 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(clock tmtime.Source, tp TimingParams) bool {
|
||||
lt := clock.Now()
|
||||
lhs := lt.Add(-tp.Precision)
|
||||
rhs := lt.Add(tp.Precision).Add(tp.MessageDelay)
|
||||
if lhs.Before(p.Timestamp) && rhs.After(p.Timestamp) {
|
||||
return true
|
||||
func (p *Proposal) IsTimely(recvTime time.Time, tp TimingParams, initialHeight int64) bool {
|
||||
// lhs is `proposedBlockTime - Precision` in the first inequality
|
||||
lhs := p.Timestamp.Add(-tp.Precision)
|
||||
// rhs is `proposedBlockTime + MsgDelay + Precision` in the second inequality
|
||||
rhs := p.Timestamp.Add(tp.MessageDelay).Add(tp.Precision)
|
||||
|
||||
if recvTime.Before(lhs) || (p.Height != initialHeight && recvTime.After(rhs)) {
|
||||
return false
|
||||
}
|
||||
return false
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// String returns a string representation of the Proposal.
|
||||
|
||||
+65
-32
@@ -14,7 +14,6 @@ import (
|
||||
"github.com/tendermint/tendermint/internal/libs/protoio"
|
||||
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"
|
||||
)
|
||||
|
||||
@@ -217,47 +216,84 @@ 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
|
||||
name string
|
||||
genesisHeight int64
|
||||
proposalHeight int64
|
||||
proposalTime time.Time
|
||||
recvTime time.Time
|
||||
precision time.Duration
|
||||
msgDelay time.Duration
|
||||
expectTimely bool
|
||||
}{
|
||||
// proposalTime - precision <= localTime <= proposalTime + msgDelay + precision
|
||||
{
|
||||
// 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,
|
||||
// 0 - 2 <= 1 <= 0 + 1 + 2
|
||||
name: "basic timely",
|
||||
genesisHeight: 1,
|
||||
proposalHeight: 2,
|
||||
proposalTime: genesisTime,
|
||||
recvTime: 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,
|
||||
// 0 - 2 <= 4 <= 0 + 1 + 2
|
||||
name: "local time too large",
|
||||
genesisHeight: 1,
|
||||
proposalHeight: 2,
|
||||
proposalTime: genesisTime,
|
||||
recvTime: genesisTime.Add(4 * 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,
|
||||
// 4 - 2 <= 0 <= 4 + 2 + 1
|
||||
name: "proposal time too large",
|
||||
genesisHeight: 1,
|
||||
proposalHeight: 2,
|
||||
proposalTime: genesisTime.Add(4 * time.Nanosecond),
|
||||
recvTime: genesisTime,
|
||||
precision: time.Nanosecond * 2,
|
||||
msgDelay: time.Nanosecond,
|
||||
expectTimely: false,
|
||||
},
|
||||
{
|
||||
// Checking that the following inequality evaluates to true:
|
||||
// 0 - 2 <= 4
|
||||
// and the following check is skipped
|
||||
// 4 <= 0 + 1 + 2
|
||||
name: "local time too large but proposal is for genesis",
|
||||
genesisHeight: 1,
|
||||
proposalHeight: 1,
|
||||
proposalTime: genesisTime,
|
||||
recvTime: genesisTime.Add(4 * time.Nanosecond),
|
||||
precision: time.Nanosecond * 2,
|
||||
msgDelay: time.Nanosecond,
|
||||
expectTimely: true,
|
||||
},
|
||||
{
|
||||
// Checking that the following inequality evaluates to false:
|
||||
// 4 - 2 <= 0
|
||||
name: "proposal time too large for genesis block proposal",
|
||||
genesisHeight: 1,
|
||||
proposalHeight: 1,
|
||||
proposalTime: genesisTime.Add(4 * time.Nanosecond),
|
||||
recvTime: genesisTime,
|
||||
precision: time.Nanosecond * 2,
|
||||
msgDelay: time.Nanosecond,
|
||||
expectTimely: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, testCase := range testCases {
|
||||
t.Run(testCase.name, func(t *testing.T) {
|
||||
p := Proposal{
|
||||
Height: testCase.proposalHeight,
|
||||
Timestamp: testCase.proposalTime,
|
||||
}
|
||||
|
||||
@@ -266,10 +302,7 @@ func TestIsTimely(t *testing.T) {
|
||||
MessageDelay: testCase.msgDelay,
|
||||
}
|
||||
|
||||
mockSource := new(tmtimemocks.Source)
|
||||
mockSource.On("Now").Return(testCase.localTime)
|
||||
|
||||
ti := p.IsTimely(mockSource, tp)
|
||||
ti := p.IsTimely(testCase.recvTime, tp, testCase.genesisHeight)
|
||||
assert.Equal(t, testCase.expectTimely, ti)
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user