diff --git a/internal/consensus/pbts_test.go b/internal/consensus/pbts_test.go index d991f43f2..69b04e265 100644 --- a/internal/consensus/pbts_test.go +++ b/internal/consensus/pbts_test.go @@ -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) - }) - } -} diff --git a/internal/consensus/state.go b/internal/consensus/state.go index 76705c8c7..daceb42eb 100644 --- a/internal/consensus/state.go +++ b/internal/consensus/state.go @@ -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 -}