mirror of
https://github.com/tendermint/tendermint.git
synced 2026-02-08 21:10:10 +00:00
internal/consensus: remove proposal wait time (#7418)
This commit is contained in:
committed by
William Banfield
parent
14f4db7c19
commit
e17178d70d
@@ -324,74 +324,6 @@ func (hr heightResult) isComplete() bool {
|
||||
return !hr.proposalIssuedAt.IsZero() && !hr.prevoteIssuedAt.IsZero() && hr.prevote != nil
|
||||
}
|
||||
|
||||
// TestReceiveProposalWaitsForPreviousBlockTime tests that a validator receiving
|
||||
// a proposal waits until the previous block time passes before issuing a prevote.
|
||||
// The test delivers the block to the validator after the configured `timeout-propose`,
|
||||
// but before the proposer-based timestamp bound on block delivery and checks that
|
||||
// the consensus algorithm correctly waits for the new block to be delivered
|
||||
// and issues a prevote for it.
|
||||
func TestReceiveProposalWaitsForPreviousBlockTime(t *testing.T) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
initialTime := time.Now().Add(50 * time.Millisecond)
|
||||
cfg := pbtsTestConfiguration{
|
||||
timingParams: types.TimingParams{
|
||||
Precision: 100 * time.Millisecond,
|
||||
MessageDelay: 500 * time.Millisecond,
|
||||
},
|
||||
timeoutPropose: 50 * time.Millisecond,
|
||||
genesisTime: initialTime,
|
||||
height2ProposalDeliverTime: initialTime.Add(450 * time.Millisecond),
|
||||
height2ProposedBlockTime: initialTime.Add(350 * time.Millisecond),
|
||||
}
|
||||
|
||||
pbtsTest := newPBTSTestHarness(ctx, t, cfg)
|
||||
results := pbtsTest.run()
|
||||
|
||||
// Check that the validator waited until after the proposer-based timestamp
|
||||
// waitingTime bound.
|
||||
assert.True(t, results.height2.prevoteIssuedAt.After(cfg.height2ProposalDeliverTime))
|
||||
maxWaitingTime := cfg.genesisTime.Add(cfg.timingParams.Precision).Add(cfg.timingParams.MessageDelay)
|
||||
assert.True(t, results.height2.prevoteIssuedAt.Before(maxWaitingTime))
|
||||
|
||||
// Check that the validator did not prevote for nil.
|
||||
assert.NotNil(t, results.height2.prevote.BlockID.Hash)
|
||||
}
|
||||
|
||||
// TestReceiveProposalTimesOutOnSlowDelivery tests that a validator receiving
|
||||
// a proposal times out and prevotes nil if the block is not delivered by the
|
||||
// within the proposer-based timestamp algorithm's waitingTime bound.
|
||||
// The test delivers the block to the validator after the previous block's time
|
||||
// and after the proposer-based timestamp bound on block delivery.
|
||||
// The test then checks that the validator correctly waited for the new block
|
||||
// and prevoted nil after timing out.
|
||||
func TestReceiveProposalTimesOutOnSlowDelivery(t *testing.T) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
initialTime := time.Now()
|
||||
cfg := pbtsTestConfiguration{
|
||||
timingParams: types.TimingParams{
|
||||
Precision: 100 * time.Millisecond,
|
||||
MessageDelay: 500 * time.Millisecond,
|
||||
},
|
||||
timeoutPropose: 50 * time.Millisecond,
|
||||
genesisTime: initialTime,
|
||||
height2ProposalDeliverTime: initialTime.Add(660 * time.Millisecond),
|
||||
height2ProposedBlockTime: initialTime.Add(350 * time.Millisecond),
|
||||
}
|
||||
|
||||
pbtsTest := newPBTSTestHarness(ctx, t, cfg)
|
||||
results := pbtsTest.run()
|
||||
|
||||
// Check that the validator waited until after the proposer-based timestamp
|
||||
// waitinTime bound.
|
||||
maxWaitingTime := initialTime.Add(cfg.timingParams.Precision).Add(cfg.timingParams.MessageDelay)
|
||||
assert.True(t, results.height2.prevoteIssuedAt.After(maxWaitingTime))
|
||||
|
||||
// Ensure that the validator issued a prevote for nil.
|
||||
assert.Nil(t, results.height2.prevote.BlockID.Hash)
|
||||
}
|
||||
|
||||
// TestProposerWaitsForGenesisTime tests that a proposer will not propose a block
|
||||
// until after the genesis time has passed. The test sets the genesis time in the
|
||||
// future and then ensures that the observed validator waits to propose a block.
|
||||
@@ -491,56 +423,3 @@ func TestProposerWaitTime(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestProposalTimeout(t *testing.T) {
|
||||
genesisTime, err := time.Parse(time.RFC3339, "2019-03-13T23:00:00Z")
|
||||
require.NoError(t, err)
|
||||
testCases := []struct {
|
||||
name string
|
||||
localTime time.Time
|
||||
previousBlockTime time.Time
|
||||
precision time.Duration
|
||||
msgDelay time.Duration
|
||||
expectedDuration time.Duration
|
||||
}{
|
||||
{
|
||||
name: "MessageDelay + Precision has not quite elapsed",
|
||||
localTime: genesisTime.Add(525 * time.Millisecond),
|
||||
previousBlockTime: genesisTime.Add(6 * time.Millisecond),
|
||||
precision: time.Millisecond * 20,
|
||||
msgDelay: time.Millisecond * 500,
|
||||
expectedDuration: 1 * time.Millisecond,
|
||||
},
|
||||
{
|
||||
name: "MessageDelay + Precision equals current time",
|
||||
localTime: genesisTime.Add(525 * time.Millisecond),
|
||||
previousBlockTime: genesisTime.Add(5 * time.Millisecond),
|
||||
precision: time.Millisecond * 20,
|
||||
msgDelay: time.Millisecond * 500,
|
||||
expectedDuration: 0,
|
||||
},
|
||||
{
|
||||
name: "MessageDelay + Precision has elapsed",
|
||||
localTime: genesisTime.Add(725 * time.Millisecond),
|
||||
previousBlockTime: genesisTime.Add(5 * time.Millisecond),
|
||||
precision: time.Millisecond * 20,
|
||||
msgDelay: time.Millisecond * 500,
|
||||
expectedDuration: 0,
|
||||
},
|
||||
}
|
||||
for _, testCase := range testCases {
|
||||
t.Run(testCase.name, func(t *testing.T) {
|
||||
|
||||
mockSource := new(tmtimemocks.Source)
|
||||
mockSource.On("Now").Return(testCase.localTime)
|
||||
|
||||
tp := types.TimingParams{
|
||||
Precision: testCase.precision,
|
||||
MessageDelay: testCase.msgDelay,
|
||||
}
|
||||
|
||||
ti := proposalStepWaitingTime(mockSource, testCase.previousBlockTime, tp)
|
||||
assert.Equal(t, testCase.expectedDuration, ti)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1177,11 +1177,8 @@ func (cs *State) enterPropose(ctx context.Context, height int64, round int32) {
|
||||
}
|
||||
}()
|
||||
|
||||
waitingTime := proposalStepWaitingTime(tmtime.DefaultSource{}, cs.state.LastBlockTime, cs.state.ConsensusParams.Timing) // nolint: lll
|
||||
proposalTimeout := maxDuration(cs.config.Propose(round), waitingTime)
|
||||
|
||||
// If we don't get the proposal and all block parts quick enough, enterPrevote
|
||||
cs.scheduleTimeout(proposalTimeout, height, round, cstypes.RoundStepPropose)
|
||||
cs.scheduleTimeout(cs.config.Propose(round), height, round, cstypes.RoundStepPropose)
|
||||
|
||||
// Nothing more to do if we're not a validator
|
||||
if cs.privValidator == nil {
|
||||
@@ -2491,32 +2488,3 @@ func proposerWaitTime(lt tmtime.Source, bt time.Time) time.Duration {
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// proposalStepWaitingTime is used along with the `timeout-propose` configuration
|
||||
// parameter to determines how long a validator will wait for a block to be sent from a proposer.
|
||||
// proposalStepWaitingTime ensures that the validator waits long enough for the proposer to
|
||||
// deliver a block with a monotically increasing timestamp.
|
||||
//
|
||||
// To ensure that the validator waits long enough, it must wait until the previous
|
||||
// block's timestamp. It also must account for the difference between its own clock and
|
||||
// the proposer's clock, i.e. the 'Precision', and the amount of time for the message to be transmitted,
|
||||
// i.e. the MsgDelay.
|
||||
//
|
||||
// The result of proposalStepWaitingTime is compared with the configured `timeout-propose` duration,
|
||||
// and the validator waits for whichever duration is larger before advancing to the next step
|
||||
// and prevoting nil.
|
||||
func proposalStepWaitingTime(lt tmtime.Source, bt time.Time, tp types.TimingParams) time.Duration {
|
||||
t := lt.Now()
|
||||
wt := bt.Add(tp.Precision).Add(tp.MessageDelay)
|
||||
if t.After(wt) {
|
||||
return 0
|
||||
}
|
||||
return wt.Sub(t)
|
||||
}
|
||||
|
||||
func maxDuration(d1, d2 time.Duration) time.Duration {
|
||||
if d1 >= d2 {
|
||||
return d1
|
||||
}
|
||||
return d2
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user