mirror of
https://github.com/tendermint/tendermint.git
synced 2026-08-22 07:06:14 +00:00
save proposal time on roundstate
This commit is contained in:
@@ -1311,13 +1311,13 @@ func (cs *State) enterPrevote(height int64, round int32) {
|
||||
// (so we have more time to try and collect +2/3 prevotes for a single block)
|
||||
}
|
||||
|
||||
func (cs *State) proposalIsTimely(proposal *types.Proposal) bool {
|
||||
func (cs *State) proposalIsTimely() bool {
|
||||
tp := types.TimingParams{
|
||||
Precision: cs.state.ConsensusParams.Timing.Precision,
|
||||
MessageDelay: cs.state.ConsensusParams.Timing.MessageDelay,
|
||||
}
|
||||
|
||||
return proposal.IsTimely(tmtime.DefaultSource{}, tp, cs.state.InitialHeight)
|
||||
return cs.Proposal.IsTimely(cs.ProposalReceiveTime, tp, cs.state.InitialHeight)
|
||||
}
|
||||
|
||||
func (cs *State) defaultDoPrevote(height int64, round int32) {
|
||||
@@ -1366,7 +1366,7 @@ func (cs *State) defaultDoPrevote(height int64, round int32) {
|
||||
*/
|
||||
if cs.Proposal.POLRound == -1 {
|
||||
if cs.LockedRound == -1 {
|
||||
if !cs.Proposal.Valid {
|
||||
if !cs.proposalIsTimely() {
|
||||
logger.Debug("prevote step: ProposalBlock is not timely; prevoting nil")
|
||||
cs.signAddVote(tmproto.PrevoteType, nil, types.PartSetHeader{})
|
||||
return
|
||||
@@ -1905,6 +1905,8 @@ func (cs *State) RecordMetrics(height int64, block *types.Block) {
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
func (cs *State) defaultSetProposal(proposal *types.Proposal) error {
|
||||
recvTime := tmtime.Now()
|
||||
|
||||
// Already have one
|
||||
// TODO: possibly catch double proposals
|
||||
if cs.Proposal != nil || proposal == nil {
|
||||
@@ -1932,6 +1934,7 @@ func (cs *State) defaultSetProposal(proposal *types.Proposal) error {
|
||||
|
||||
proposal.Signature = p.Signature
|
||||
cs.Proposal = proposal
|
||||
cs.ProposalReceiveTime = recvTime
|
||||
// We don't update cs.ProposalBlockParts if it is already set.
|
||||
// This happens if we're already in cstypes.RoundStepCommit or if there is a valid block in the current round.
|
||||
// TODO: We can check if Proposal is for a different block as this is a sign of misbehavior!
|
||||
@@ -1939,10 +1942,6 @@ func (cs *State) defaultSetProposal(proposal *types.Proposal) error {
|
||||
cs.ProposalBlockParts = types.NewPartSetFromHeader(proposal.BlockID.PartSetHeader)
|
||||
}
|
||||
|
||||
// Mark the proposal as invalid if too far in the past or future
|
||||
if proposal.POLRound > -1 || cs.proposalIsTimely(proposal) {
|
||||
cs.Proposal.Valid = true
|
||||
}
|
||||
cs.Logger.Info("received proposal", "proposal", proposal)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -71,14 +71,15 @@ type RoundState struct {
|
||||
StartTime time.Time `json:"start_time"`
|
||||
|
||||
// Subjective time when +2/3 precommits for Block at Round were found
|
||||
CommitTime time.Time `json:"commit_time"`
|
||||
Validators *types.ValidatorSet `json:"validators"`
|
||||
Proposal *types.Proposal `json:"proposal"`
|
||||
ProposalBlock *types.Block `json:"proposal_block"`
|
||||
ProposalBlockParts *types.PartSet `json:"proposal_block_parts"`
|
||||
LockedRound int32 `json:"locked_round"`
|
||||
LockedBlock *types.Block `json:"locked_block"`
|
||||
LockedBlockParts *types.PartSet `json:"locked_block_parts"`
|
||||
CommitTime time.Time `json:"commit_time"`
|
||||
Validators *types.ValidatorSet `json:"validators"`
|
||||
Proposal *types.Proposal `json:"proposal"`
|
||||
ProposalReceiveTime time.Time `json:"proposal_received_time"`
|
||||
ProposalBlock *types.Block `json:"proposal_block"`
|
||||
ProposalBlockParts *types.PartSet `json:"proposal_block_parts"`
|
||||
LockedRound int32 `json:"locked_round"`
|
||||
LockedBlock *types.Block `json:"locked_block"`
|
||||
LockedBlockParts *types.PartSet `json:"locked_block_parts"`
|
||||
|
||||
// Last known round with POL for non-nil valid block.
|
||||
ValidRound int32 `json:"valid_round"`
|
||||
|
||||
+4
-6
@@ -30,7 +30,6 @@ type Proposal struct {
|
||||
BlockID BlockID `json:"block_id"`
|
||||
Timestamp time.Time `json:"timestamp"`
|
||||
Signature []byte `json:"signature"`
|
||||
Valid bool
|
||||
}
|
||||
|
||||
// NewProposal returns a new Proposal.
|
||||
@@ -90,16 +89,15 @@ func (p *Proposal) ValidateBasic() error {
|
||||
//
|
||||
// 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, initialHeight int64) bool {
|
||||
localTime := clock.Now()
|
||||
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)
|
||||
|
||||
localTimeAfterOrEqLHS := localTime.After(lhs) || localTime.Equal(lhs)
|
||||
localTimeBeforeOrEqRHS := localTime.Before(rhs) || localTime.Equal(rhs)
|
||||
if localTimeAfterOrEqLHS && (p.Height == initialHeight || localTimeBeforeOrEqRHS) {
|
||||
recvTimeAfterOrEqLHS := recvTime.After(lhs) || recvTime.Equal(lhs)
|
||||
recvTimeBeforeOrEqRHS := recvTime.Before(rhs) || recvTime.Equal(rhs)
|
||||
if recvTimeAfterOrEqLHS && (p.Height == initialHeight || recvTimeBeforeOrEqRHS) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
|
||||
@@ -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"
|
||||
)
|
||||
|
||||
@@ -200,7 +199,7 @@ func TestIsTimely(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
proposalTime time.Time
|
||||
localTime time.Time
|
||||
recvTime time.Time
|
||||
precision time.Duration
|
||||
msgDelay time.Duration
|
||||
expectTimely bool
|
||||
@@ -211,7 +210,7 @@ func TestIsTimely(t *testing.T) {
|
||||
// 0 - 2 <= 1 <= 0 + 1 + 2
|
||||
name: "basic timely",
|
||||
proposalTime: genesisTime,
|
||||
localTime: genesisTime.Add(1 * time.Nanosecond),
|
||||
recvTime: genesisTime.Add(1 * time.Nanosecond),
|
||||
precision: time.Nanosecond * 2,
|
||||
msgDelay: time.Nanosecond,
|
||||
expectTimely: true,
|
||||
@@ -221,7 +220,7 @@ func TestIsTimely(t *testing.T) {
|
||||
// 0 - 2 <= 4 <= 0 + 1 + 2
|
||||
name: "local time too large",
|
||||
proposalTime: genesisTime,
|
||||
localTime: genesisTime.Add(4 * time.Nanosecond),
|
||||
recvTime: genesisTime.Add(4 * time.Nanosecond),
|
||||
precision: time.Nanosecond * 2,
|
||||
msgDelay: time.Nanosecond,
|
||||
expectTimely: false,
|
||||
@@ -231,7 +230,7 @@ func TestIsTimely(t *testing.T) {
|
||||
// 4 - 2 <= 0 <= 4 + 2 + 1
|
||||
name: "proposal time too large",
|
||||
proposalTime: genesisTime.Add(4 * time.Nanosecond),
|
||||
localTime: genesisTime,
|
||||
recvTime: genesisTime,
|
||||
precision: time.Nanosecond * 2,
|
||||
msgDelay: time.Nanosecond,
|
||||
expectTimely: false,
|
||||
@@ -248,10 +247,7 @@ func TestIsTimely(t *testing.T) {
|
||||
MessageDelay: testCase.msgDelay,
|
||||
}
|
||||
|
||||
mockSource := new(tmtimemocks.Source)
|
||||
mockSource.On("Now").Return(testCase.localTime)
|
||||
|
||||
ti := p.IsTimely(mockSource, tp, 2)
|
||||
ti := p.IsTimely(testCase.recvTime, tp, 2)
|
||||
assert.Equal(t, testCase.expectTimely, ti)
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user