Compare commits

...

4 Commits

Author SHA1 Message Date
William Banfield
c653dbf723 rename in additional test 2022-01-11 17:20:46 -05:00
William Banfield
1b55ae2880 fix additional places using old timing name 2022-01-11 17:13:39 -05:00
William Banfield
81729d1ac3 proto: rename timing params to synchrony params 2022-01-11 11:52:19 -05:00
Anca Zamfir
2617a5cf33 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>
2022-01-11 11:44:07 +01:00
12 changed files with 317 additions and 178 deletions

View File

@@ -569,9 +569,9 @@ var testGenesisFmt = `{
"max_gas": "-1",
"time_iota_ms": "10"
},
"timing": {
"message_delay": "200",
"precision": "50"
"synchrony": {
"message_delay": "500000000",
"precision": "10000000"
},
"evidence": {
"max_age_num_blocks": "100000",

View File

@@ -66,7 +66,7 @@ type pbtsTestHarness struct {
type pbtsTestConfiguration struct {
// The timestamp consensus parameters to be used by the state machine under test.
timingParams types.TimingParams
synchronyParams types.SynchronyParams
// The setting to use for the TimeoutPropose configuration parameter.
timeoutPropose time.Duration
@@ -102,7 +102,7 @@ func newPBTSTestHarness(ctx context.Context, t *testing.T, tc pbtsTestConfigurat
}
cfg.Consensus.TimeoutPropose = tc.timeoutPropose
consensusParams := types.DefaultConsensusParams()
consensusParams.Timing = tc.timingParams
consensusParams.Synchrony = tc.synchronyParams
state, privVals := makeGenesisState(cfg, genesisStateArgs{
Params: consensusParams,
@@ -300,7 +300,6 @@ func (p *pbtsTestHarness) run() resultSet {
r2 := p.height2()
p.intermediateHeights()
r5 := p.height5()
_ = p.observedState.Stop()
return resultSet{
genesisHeight: r1,
height2: r2,
@@ -334,7 +333,7 @@ func TestProposerWaitsForGenesisTime(t *testing.T) {
// create a genesis time far (enough) in the future.
initialTime := time.Now().Add(800 * time.Millisecond)
cfg := pbtsTestConfiguration{
timingParams: types.TimingParams{
synchronyParams: types.SynchronyParams{
Precision: 10 * time.Millisecond,
MessageDelay: 10 * time.Millisecond,
},
@@ -362,7 +361,7 @@ func TestProposerWaitsForPreviousBlock(t *testing.T) {
defer cancel()
initialTime := time.Now().Add(time.Millisecond * 50)
cfg := pbtsTestConfiguration{
timingParams: types.TimingParams{
synchronyParams: types.SynchronyParams{
Precision: 100 * time.Millisecond,
MessageDelay: 500 * time.Millisecond,
},
@@ -423,3 +422,75 @@ func TestProposerWaitTime(t *testing.T) {
})
}
}
func TestTimelyProposal(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
initialTime := time.Now()
cfg := pbtsTestConfiguration{
synchronyParams: types.SynchronyParams{
Precision: 10 * time.Millisecond,
MessageDelay: 140 * time.Millisecond,
},
timeoutPropose: 40 * time.Millisecond,
genesisTime: initialTime,
height2ProposedBlockTime: initialTime.Add(10 * time.Millisecond),
height2ProposalDeliverTime: initialTime.Add(30 * time.Millisecond),
}
pbtsTest := newPBTSTestHarness(ctx, t, cfg)
results := pbtsTest.run()
assert.True(t, results.height2.prevote.BlockID.Hash != nil)
}
func TestTooFarInThePastProposal(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
initialTime := time.Now()
// localtime > proposedBlockTime + MsgDelay + Precision
cfg := pbtsTestConfiguration{
synchronyParams: types.SynchronyParams{
Precision: 1 * time.Millisecond,
MessageDelay: 10 * time.Millisecond,
},
timeoutPropose: 50 * time.Millisecond,
genesisTime: initialTime,
height2ProposedBlockTime: initialTime.Add(10 * time.Millisecond),
height2ProposalDeliverTime: initialTime.Add(21 * time.Millisecond),
}
pbtsTest := newPBTSTestHarness(ctx, t, cfg)
results := pbtsTest.run()
time.Sleep(1 * time.Second)
assert.True(t, results.height2.prevote.BlockID.Hash == nil)
}
func TestTooFarInTheFutureProposal(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
initialTime := time.Now()
// localtime < proposedBlockTime - Precision
cfg := pbtsTestConfiguration{
synchronyParams: types.SynchronyParams{
Precision: 1 * time.Millisecond,
MessageDelay: 10 * time.Millisecond,
},
timeoutPropose: 50 * time.Millisecond,
genesisTime: initialTime,
height2ProposedBlockTime: initialTime.Add(100 * time.Millisecond),
height2ProposalDeliverTime: initialTime.Add(10 * time.Millisecond),
height4ProposedBlockTime: initialTime.Add(150 * time.Millisecond),
}
pbtsTest := newPBTSTestHarness(ctx, t, cfg)
results := pbtsTest.run()
assert.True(t, results.height2.prevote.BlockID.Hash == nil)
}

View File

@@ -713,6 +713,7 @@ func (cs *State) updateToState(state sm.State) {
cs.Validators = validators
cs.Proposal = nil
cs.ProposalReceiveTime = time.Time{}
cs.ProposalBlock = nil
cs.ProposalBlockParts = nil
cs.LockedRound = -1
@@ -1047,6 +1048,7 @@ func (cs *State) enterNewRound(height int64, round int32) {
} else {
logger.Debug("resetting proposal info")
cs.Proposal = nil
cs.ProposalReceiveTime = time.Time{}
cs.ProposalBlock = nil
cs.ProposalBlockParts = nil
}
@@ -1311,24 +1313,47 @@ 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() bool {
sp := types.SynchronyParams{
Precision: cs.state.ConsensusParams.Synchrony.Precision,
MessageDelay: cs.state.ConsensusParams.Synchrony.MessageDelay,
}
return cs.Proposal.IsTimely(cs.ProposalReceiveTime, sp, cs.state.InitialHeight)
}
func (cs *State) defaultDoPrevote(height int64, round int32) {
logger := cs.Logger.With("height", height, "round", round)
// We did not receive a proposal within this round. (and thus executing this from a timeout)
// Check that a proposed block was not received within this round (and thus executing this from a timeout).
if cs.ProposalBlock == nil {
logger.Debug("prevote step: ProposalBlock is nil")
logger.Debug("prevote step: ProposalBlock is nil; prevoting nil")
cs.signAddVote(tmproto.PrevoteType, nil, types.PartSetHeader{})
return
}
if cs.Proposal == nil || cs.ProposalBlock == nil {
logger.Debug("prevote step; did not receive proposal, prevoting nil")
if cs.Proposal == nil {
logger.Debug("prevote step: did not receive proposal; prevoting nil")
cs.signAddVote(tmproto.PrevoteType, nil, types.PartSetHeader{})
return
}
if !cs.Proposal.Timestamp.Equal(cs.ProposalBlock.Header.Time) {
logger.Debug("proposal timestamp not equal, prevoting nil")
logger.Debug("prevote step: proposal timestamp not equal; prevoting nil")
cs.signAddVote(tmproto.PrevoteType, nil, types.PartSetHeader{})
return
}
if cs.Proposal.POLRound == -1 && cs.LockedRound == -1 && !cs.proposalIsTimely() {
logger.Debug("prevote step: Proposal is not timely; prevoting nil - ",
"proposed",
tmtime.Canonical(cs.Proposal.Timestamp).Format(time.RFC3339Nano),
"received",
tmtime.Canonical(cs.ProposalReceiveTime).Format(time.RFC3339Nano),
"msg_delay",
cs.state.ConsensusParams.Synchrony.MessageDelay,
"precision",
cs.state.ConsensusParams.Synchrony.Precision)
cs.signAddVote(tmproto.PrevoteType, nil, types.PartSetHeader{})
return
}
@@ -1337,7 +1362,7 @@ func (cs *State) defaultDoPrevote(height int64, round int32) {
err := cs.blockExec.ValidateBlock(cs.state, cs.ProposalBlock)
if err != nil {
// ProposalBlock is invalid, prevote nil.
logger.Error("prevote step: ProposalBlock is invalid", "err", err)
logger.Error("prevote step: ProposalBlock is invalid; prevoting nil", "err", err)
cs.signAddVote(tmproto.PrevoteType, nil, types.PartSetHeader{})
return
}
@@ -1357,7 +1382,6 @@ func (cs *State) defaultDoPrevote(height int64, round int32) {
*/
if cs.Proposal.POLRound == -1 {
if cs.LockedRound == -1 {
// TODO(@wbanfield) add check for timely here as well
logger.Debug("prevote step: ProposalBlock is valid and there is no locked block; prevoting the proposal")
cs.signAddVote(tmproto.PrevoteType, cs.ProposalBlock.Hash(), cs.ProposalBlockParts.Header())
return
@@ -1489,7 +1513,7 @@ func (cs *State) enterPrecommit(height int64, round int32) {
// +2/3 prevoted nil. Precommit nil.
if blockID.IsNil() {
logger.Debug("precommit step; +2/3 prevoted for nil")
logger.Debug("precommit step: +2/3 prevoted for nil; precommitting nil")
cs.signAddVote(tmproto.PrecommitType, nil, types.PartSetHeader{})
return
}
@@ -1504,18 +1528,18 @@ func (cs *State) enterPrecommit(height int64, round int32) {
// If the proposal time does not match the block time, precommit nil.
if !cs.Proposal.Timestamp.Equal(cs.ProposalBlock.Header.Time) {
logger.Debug("proposal timestamp not equal, precommitting nil")
logger.Debug("precommit step: proposal timestamp not equal; precommitting nil")
cs.signAddVote(tmproto.PrecommitType, nil, types.PartSetHeader{})
return
}
// If we're already locked on that block, precommit it, and update the LockedRound
if cs.LockedBlock.HashesTo(blockID.Hash) {
logger.Debug("precommit step; +2/3 prevoted locked block; relocking")
logger.Debug("precommit step: +2/3 prevoted locked block; relocking")
cs.LockedRound = round
if err := cs.eventBus.PublishEventRelock(cs.RoundStateEvent()); err != nil {
logger.Error("failed publishing event relock", "err", err)
logger.Error("precommit step: failed publishing event relock", "err", err)
}
cs.signAddVote(tmproto.PrecommitType, blockID.Hash, blockID.PartSetHeader)
@@ -1526,11 +1550,11 @@ func (cs *State) enterPrecommit(height int64, round int32) {
// the proposed block, update our locked block to this block and issue a
// precommit vote for it.
if cs.ProposalBlock.HashesTo(blockID.Hash) {
logger.Debug("precommit step; +2/3 prevoted proposal block; locking", "hash", blockID.Hash)
logger.Debug("precommit step: +2/3 prevoted proposal block; locking", "hash", blockID.Hash)
// Validate the block.
if err := cs.blockExec.ValidateBlock(cs.state, cs.ProposalBlock); err != nil {
panic(fmt.Sprintf("precommit step; +2/3 prevoted for an invalid block: %v", err))
panic(fmt.Sprintf("precommit step: +2/3 prevoted for an invalid block %v; relocking", err))
}
cs.LockedRound = round
@@ -1538,7 +1562,7 @@ func (cs *State) enterPrecommit(height int64, round int32) {
cs.LockedBlockParts = cs.ProposalBlockParts
if err := cs.eventBus.PublishEventLock(cs.RoundStateEvent()); err != nil {
logger.Error("failed publishing event lock", "err", err)
logger.Error("precommit step: failed publishing event lock", "err", err)
}
cs.signAddVote(tmproto.PrecommitType, blockID.Hash, blockID.PartSetHeader)
@@ -1547,7 +1571,7 @@ func (cs *State) enterPrecommit(height int64, round int32) {
// There was a polka in this round for a block we don't have.
// Fetch that block, and precommit nil.
logger.Debug("precommit step; +2/3 prevotes for a block we do not have; voting nil", "block_id", blockID)
logger.Debug("precommit step: +2/3 prevotes for a block we do not have; voting nil", "block_id", blockID)
if !cs.ProposalBlockParts.HasHeader(blockID.PartSetHeader) {
cs.ProposalBlock = nil
@@ -1892,9 +1916,11 @@ 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 {
if cs.Proposal != nil || proposal == nil {
return nil
}
@@ -1919,6 +1945,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!

View File

@@ -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_receive_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"`

View File

@@ -203,7 +203,7 @@ func TestStateSyncVectors(t *testing.T) {
Version: &tmproto.VersionParams{
AppVersion: 11,
},
Timing: &tmproto.TimingParams{
Synchrony: &tmproto.SynchronyParams{
MessageDelay: 550,
Precision: 90,
},

View File

@@ -34,7 +34,7 @@ type ConsensusParams struct {
Evidence *EvidenceParams `protobuf:"bytes,2,opt,name=evidence,proto3" json:"evidence,omitempty"`
Validator *ValidatorParams `protobuf:"bytes,3,opt,name=validator,proto3" json:"validator,omitempty"`
Version *VersionParams `protobuf:"bytes,4,opt,name=version,proto3" json:"version,omitempty"`
Timing *TimingParams `protobuf:"bytes,5,opt,name=timing,proto3" json:"timing,omitempty"`
Synchrony *SynchronyParams `protobuf:"bytes,5,opt,name=synchrony,proto3" json:"synchrony,omitempty"`
}
func (m *ConsensusParams) Reset() { *m = ConsensusParams{} }
@@ -98,9 +98,9 @@ func (m *ConsensusParams) GetVersion() *VersionParams {
return nil
}
func (m *ConsensusParams) GetTiming() *TimingParams {
func (m *ConsensusParams) GetSynchrony() *SynchronyParams {
if m != nil {
return m.Timing
return m.Synchrony
}
return nil
}
@@ -381,23 +381,23 @@ func (m *HashedParams) GetBlockMaxGas() int64 {
return 0
}
type TimingParams struct {
type SynchronyParams struct {
MessageDelay time.Duration `protobuf:"bytes,1,opt,name=message_delay,json=messageDelay,proto3,stdduration" json:"message_delay"`
Precision time.Duration `protobuf:"bytes,2,opt,name=precision,proto3,stdduration" json:"precision"`
}
func (m *TimingParams) Reset() { *m = TimingParams{} }
func (m *TimingParams) String() string { return proto.CompactTextString(m) }
func (*TimingParams) ProtoMessage() {}
func (*TimingParams) Descriptor() ([]byte, []int) {
func (m *SynchronyParams) Reset() { *m = SynchronyParams{} }
func (m *SynchronyParams) String() string { return proto.CompactTextString(m) }
func (*SynchronyParams) ProtoMessage() {}
func (*SynchronyParams) Descriptor() ([]byte, []int) {
return fileDescriptor_e12598271a686f57, []int{6}
}
func (m *TimingParams) XXX_Unmarshal(b []byte) error {
func (m *SynchronyParams) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
}
func (m *TimingParams) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
func (m *SynchronyParams) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
if deterministic {
return xxx_messageInfo_TimingParams.Marshal(b, m, deterministic)
return xxx_messageInfo_SynchronyParams.Marshal(b, m, deterministic)
} else {
b = b[:cap(b)]
n, err := m.MarshalToSizedBuffer(b)
@@ -407,26 +407,26 @@ func (m *TimingParams) XXX_Marshal(b []byte, deterministic bool) ([]byte, error)
return b[:n], nil
}
}
func (m *TimingParams) XXX_Merge(src proto.Message) {
xxx_messageInfo_TimingParams.Merge(m, src)
func (m *SynchronyParams) XXX_Merge(src proto.Message) {
xxx_messageInfo_SynchronyParams.Merge(m, src)
}
func (m *TimingParams) XXX_Size() int {
func (m *SynchronyParams) XXX_Size() int {
return m.Size()
}
func (m *TimingParams) XXX_DiscardUnknown() {
xxx_messageInfo_TimingParams.DiscardUnknown(m)
func (m *SynchronyParams) XXX_DiscardUnknown() {
xxx_messageInfo_SynchronyParams.DiscardUnknown(m)
}
var xxx_messageInfo_TimingParams proto.InternalMessageInfo
var xxx_messageInfo_SynchronyParams proto.InternalMessageInfo
func (m *TimingParams) GetMessageDelay() time.Duration {
func (m *SynchronyParams) GetMessageDelay() time.Duration {
if m != nil {
return m.MessageDelay
}
return 0
}
func (m *TimingParams) GetPrecision() time.Duration {
func (m *SynchronyParams) GetPrecision() time.Duration {
if m != nil {
return m.Precision
}
@@ -440,48 +440,49 @@ func init() {
proto.RegisterType((*ValidatorParams)(nil), "tendermint.types.ValidatorParams")
proto.RegisterType((*VersionParams)(nil), "tendermint.types.VersionParams")
proto.RegisterType((*HashedParams)(nil), "tendermint.types.HashedParams")
proto.RegisterType((*TimingParams)(nil), "tendermint.types.TimingParams")
proto.RegisterType((*SynchronyParams)(nil), "tendermint.types.SynchronyParams")
}
func init() { proto.RegisterFile("tendermint/types/params.proto", fileDescriptor_e12598271a686f57) }
var fileDescriptor_e12598271a686f57 = []byte{
// 559 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x94, 0xcf, 0x6e, 0xd3, 0x30,
0x1c, 0xc7, 0x9b, 0x75, 0xeb, 0xda, 0x5f, 0xdb, 0x75, 0xb2, 0x90, 0x08, 0x43, 0x4b, 0x4b, 0x0e,
0x68, 0x12, 0x52, 0x82, 0x98, 0x00, 0x21, 0x21, 0xa1, 0x75, 0x43, 0x4c, 0x42, 0x43, 0x28, 0x1a,
0x1c, 0x76, 0x89, 0x9c, 0xd6, 0x64, 0xd1, 0xea, 0xd8, 0x8a, 0x93, 0xaa, 0x7d, 0x0b, 0x8e, 0x48,
0xbc, 0x00, 0xbc, 0x01, 0x8f, 0xb0, 0xe3, 0x8e, 0x9c, 0x00, 0xb5, 0x2f, 0x82, 0xe2, 0xd8, 0xa4,
0x7f, 0x38, 0xc0, 0x2d, 0xf1, 0xf7, 0xfb, 0x89, 0xe5, 0xcf, 0xaf, 0x35, 0xec, 0xa7, 0x24, 0x1e,
0x92, 0x84, 0x46, 0x71, 0xea, 0xa6, 0x53, 0x4e, 0x84, 0xcb, 0x71, 0x82, 0xa9, 0x70, 0x78, 0xc2,
0x52, 0x86, 0x76, 0xcb, 0xd8, 0x91, 0xf1, 0xde, 0xad, 0x90, 0x85, 0x4c, 0x86, 0x6e, 0xfe, 0x54,
0xf4, 0xf6, 0xac, 0x90, 0xb1, 0x70, 0x44, 0x5c, 0xf9, 0x16, 0x64, 0x1f, 0xdc, 0x61, 0x96, 0xe0,
0x34, 0x62, 0x71, 0x91, 0xdb, 0xdf, 0x36, 0xa0, 0x73, 0xcc, 0x62, 0x41, 0x62, 0x91, 0x89, 0xb7,
0x72, 0x07, 0x74, 0x08, 0x5b, 0xc1, 0x88, 0x0d, 0xae, 0x4c, 0xa3, 0x67, 0x1c, 0x34, 0x1f, 0xed,
0x3b, 0xab, 0x7b, 0x39, 0xfd, 0x3c, 0x2e, 0xda, 0x5e, 0xd1, 0x45, 0xcf, 0xa1, 0x4e, 0xc6, 0xd1,
0x90, 0xc4, 0x03, 0x62, 0x6e, 0x48, 0xae, 0xb7, 0xce, 0xbd, 0x54, 0x0d, 0x85, 0xfe, 0x21, 0xd0,
0x0b, 0x68, 0x8c, 0xf1, 0x28, 0x1a, 0xe2, 0x94, 0x25, 0x66, 0x55, 0xe2, 0xf7, 0xd6, 0xf1, 0xf7,
0xba, 0xa2, 0xf8, 0x92, 0x41, 0xcf, 0x60, 0x7b, 0x4c, 0x12, 0x11, 0xb1, 0xd8, 0xdc, 0x94, 0x78,
0xf7, 0x2f, 0x78, 0x51, 0x50, 0xb0, 0xee, 0xa3, 0x27, 0x50, 0x4b, 0x23, 0x1a, 0xc5, 0xa1, 0xb9,
0x25, 0x49, 0x6b, 0x9d, 0x3c, 0x97, 0xb9, 0x02, 0x55, 0xdb, 0x3e, 0x86, 0xe6, 0x82, 0x07, 0x74,
0x17, 0x1a, 0x14, 0x4f, 0xfc, 0x60, 0x9a, 0x12, 0x21, 0xcd, 0x55, 0xbd, 0x3a, 0xc5, 0x93, 0x7e,
0xfe, 0x8e, 0x6e, 0xc3, 0x76, 0x1e, 0x86, 0x58, 0x48, 0x39, 0x55, 0xaf, 0x46, 0xf1, 0xe4, 0x15,
0x16, 0xf6, 0x57, 0x03, 0x76, 0x96, 0xad, 0xa0, 0x07, 0x80, 0xf2, 0x2e, 0x0e, 0x89, 0x1f, 0x67,
0xd4, 0x97, 0x7a, 0xf5, 0x17, 0x3b, 0x14, 0x4f, 0x8e, 0x42, 0xf2, 0x26, 0xa3, 0x72, 0x6b, 0x81,
0xce, 0x60, 0x57, 0x97, 0xf5, 0x64, 0x95, 0xfe, 0x3b, 0x4e, 0x31, 0x7a, 0x47, 0x8f, 0xde, 0x39,
0x51, 0x85, 0x7e, 0xfd, 0xfa, 0x47, 0xb7, 0xf2, 0xe9, 0x67, 0xd7, 0xf0, 0x76, 0x8a, 0xef, 0xe9,
0x64, 0xf9, 0x10, 0xd5, 0xe5, 0x43, 0xd8, 0x8f, 0xa1, 0xb3, 0x32, 0x01, 0x64, 0x43, 0x9b, 0x67,
0x81, 0x7f, 0x45, 0xa6, 0xbe, 0x34, 0x65, 0x1a, 0xbd, 0xea, 0x41, 0xc3, 0x6b, 0xf2, 0x2c, 0x78,
0x4d, 0xa6, 0xe7, 0xf9, 0x92, 0xfd, 0x10, 0xda, 0x4b, 0xe6, 0x51, 0x17, 0x9a, 0x98, 0x73, 0x5f,
0xcf, 0x2b, 0x3f, 0xd9, 0xa6, 0x07, 0x98, 0x73, 0x55, 0xb3, 0x2f, 0xa0, 0x75, 0x8a, 0xc5, 0x25,
0x19, 0x2a, 0xe0, 0x3e, 0x74, 0xa4, 0x05, 0x7f, 0x55, 0x70, 0x5b, 0x2e, 0x9f, 0x69, 0xcb, 0x36,
0xb4, 0xcb, 0x5e, 0xe9, 0xba, 0xa9, 0x5b, 0xb9, 0xf0, 0xcf, 0x06, 0xb4, 0x16, 0xc7, 0x89, 0x4e,
0xa1, 0x4d, 0x89, 0x10, 0xd2, 0x20, 0x19, 0xe1, 0xa9, 0xfa, 0xd5, 0xff, 0x93, 0xbe, 0x96, 0x22,
0x4f, 0x72, 0x10, 0x1d, 0x41, 0x83, 0x27, 0x64, 0x10, 0x89, 0xff, 0x1c, 0x42, 0x49, 0xf5, 0xdf,
0x7d, 0x99, 0x59, 0xc6, 0xf5, 0xcc, 0x32, 0x6e, 0x66, 0x96, 0xf1, 0x6b, 0x66, 0x19, 0x1f, 0xe7,
0x56, 0xe5, 0x66, 0x6e, 0x55, 0xbe, 0xcf, 0xad, 0xca, 0xc5, 0xd3, 0x30, 0x4a, 0x2f, 0xb3, 0xc0,
0x19, 0x30, 0xea, 0x2e, 0x5e, 0x0f, 0xe5, 0x63, 0xf1, 0xff, 0x5f, 0xbd, 0x3a, 0x82, 0x9a, 0x5c,
0x3f, 0xfc, 0x1d, 0x00, 0x00, 0xff, 0xff, 0xf4, 0x57, 0x2d, 0xa2, 0x55, 0x04, 0x00, 0x00,
// 561 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x94, 0x4d, 0x6b, 0xd4, 0x40,
0x18, 0xc7, 0x37, 0xdd, 0xbe, 0xec, 0x3e, 0xdb, 0xed, 0x96, 0x41, 0x30, 0x56, 0x9a, 0x5d, 0x73,
0x90, 0x82, 0x90, 0x88, 0x45, 0x44, 0x10, 0xa4, 0xdb, 0x8a, 0x05, 0xa9, 0x48, 0x7c, 0x39, 0xf4,
0x12, 0x26, 0xbb, 0x63, 0x36, 0x74, 0x93, 0x19, 0x32, 0xc9, 0xb2, 0xf9, 0x16, 0x1e, 0x3d, 0x79,
0xd6, 0x8f, 0xe1, 0xad, 0xc7, 0x1e, 0x3d, 0xa9, 0xec, 0x7e, 0x11, 0x99, 0xc9, 0x4c, 0xd3, 0xdd,
0x2a, 0xd8, 0x5b, 0x32, 0xcf, 0xef, 0x97, 0x87, 0xf9, 0x3f, 0x93, 0x81, 0xdd, 0x8c, 0x24, 0x43,
0x92, 0xc6, 0x51, 0x92, 0xb9, 0x59, 0xc1, 0x08, 0x77, 0x19, 0x4e, 0x71, 0xcc, 0x1d, 0x96, 0xd2,
0x8c, 0xa2, 0xed, 0xaa, 0xec, 0xc8, 0xf2, 0xce, 0xad, 0x90, 0x86, 0x54, 0x16, 0x5d, 0xf1, 0x54,
0x72, 0x3b, 0x56, 0x48, 0x69, 0x38, 0x26, 0xae, 0x7c, 0x0b, 0xf2, 0x8f, 0xee, 0x30, 0x4f, 0x71,
0x16, 0xd1, 0xa4, 0xac, 0xdb, 0xdf, 0x57, 0xa0, 0x73, 0x48, 0x13, 0x4e, 0x12, 0x9e, 0xf3, 0x37,
0xb2, 0x03, 0xda, 0x87, 0xb5, 0x60, 0x4c, 0x07, 0x67, 0xa6, 0xd1, 0x33, 0xf6, 0x5a, 0x8f, 0x76,
0x9d, 0xe5, 0x5e, 0x4e, 0x5f, 0x94, 0x4b, 0xda, 0x2b, 0x59, 0xf4, 0x0c, 0x1a, 0x64, 0x12, 0x0d,
0x49, 0x32, 0x20, 0xe6, 0x8a, 0xf4, 0x7a, 0xd7, 0xbd, 0x17, 0x8a, 0x50, 0xea, 0xa5, 0x81, 0x9e,
0x43, 0x73, 0x82, 0xc7, 0xd1, 0x10, 0x67, 0x34, 0x35, 0xeb, 0x52, 0xbf, 0x77, 0x5d, 0xff, 0xa0,
0x11, 0xe5, 0x57, 0x0e, 0x7a, 0x0a, 0x1b, 0x13, 0x92, 0xf2, 0x88, 0x26, 0xe6, 0xaa, 0xd4, 0xbb,
0x7f, 0xd1, 0x4b, 0x40, 0xc9, 0x9a, 0x17, 0xbd, 0x79, 0x91, 0x0c, 0x46, 0x29, 0x4d, 0x0a, 0x73,
0xed, 0x5f, 0xbd, 0xdf, 0x6a, 0x44, 0xf7, 0xbe, 0x74, 0xec, 0x43, 0x68, 0x5d, 0x09, 0x04, 0xdd,
0x85, 0x66, 0x8c, 0xa7, 0x7e, 0x50, 0x64, 0x84, 0xcb, 0x08, 0xeb, 0x5e, 0x23, 0xc6, 0xd3, 0xbe,
0x78, 0x47, 0xb7, 0x61, 0x43, 0x14, 0x43, 0xcc, 0x65, 0x4a, 0x75, 0x6f, 0x3d, 0xc6, 0xd3, 0x97,
0x98, 0xdb, 0xdf, 0x0c, 0xd8, 0x5a, 0x8c, 0x07, 0x3d, 0x00, 0x24, 0x58, 0x1c, 0x12, 0x3f, 0xc9,
0x63, 0x5f, 0xe6, 0xac, 0xbf, 0xd8, 0x89, 0xf1, 0xf4, 0x20, 0x24, 0xaf, 0xf3, 0x58, 0xb6, 0xe6,
0xe8, 0x04, 0xb6, 0x35, 0xac, 0x47, 0xac, 0xe6, 0x70, 0xc7, 0x29, 0xcf, 0x80, 0xa3, 0xcf, 0x80,
0x73, 0xa4, 0x80, 0x7e, 0xe3, 0xfc, 0x67, 0xb7, 0xf6, 0xf9, 0x57, 0xd7, 0xf0, 0xb6, 0xca, 0xef,
0xe9, 0xca, 0xe2, 0x26, 0xea, 0x8b, 0x9b, 0xb0, 0x1f, 0x43, 0x67, 0x69, 0x14, 0xc8, 0x86, 0x36,
0xcb, 0x03, 0xff, 0x8c, 0x14, 0xbe, 0xcc, 0xcb, 0x34, 0x7a, 0xf5, 0xbd, 0xa6, 0xd7, 0x62, 0x79,
0xf0, 0x8a, 0x14, 0xef, 0xc4, 0x92, 0xfd, 0x10, 0xda, 0x0b, 0x23, 0x40, 0x5d, 0x68, 0x61, 0xc6,
0x7c, 0x3d, 0x38, 0xb1, 0xb3, 0x55, 0x0f, 0x30, 0x63, 0x0a, 0xb3, 0x4f, 0x61, 0xf3, 0x18, 0xf3,
0x11, 0x19, 0x2a, 0xe1, 0x3e, 0x74, 0x64, 0x0a, 0xfe, 0x72, 0xc0, 0x6d, 0xb9, 0x7c, 0xa2, 0x53,
0xb6, 0xa1, 0x5d, 0x71, 0x55, 0xd6, 0x2d, 0x4d, 0x89, 0xc0, 0xbf, 0x18, 0xd0, 0x59, 0x1a, 0x2a,
0x3a, 0x86, 0x76, 0x4c, 0x38, 0x97, 0x21, 0x92, 0x31, 0x2e, 0xd4, 0x1f, 0xf0, 0x5f, 0x09, 0x6e,
0x2a, 0xf3, 0x48, 0x88, 0xe8, 0x00, 0x9a, 0x2c, 0x25, 0x83, 0x88, 0xdf, 0x70, 0x0e, 0x95, 0xd5,
0x7f, 0xff, 0x75, 0x66, 0x19, 0xe7, 0x33, 0xcb, 0xb8, 0x98, 0x59, 0xc6, 0xef, 0x99, 0x65, 0x7c,
0x9a, 0x5b, 0xb5, 0x8b, 0xb9, 0x55, 0xfb, 0x31, 0xb7, 0x6a, 0xa7, 0x4f, 0xc2, 0x28, 0x1b, 0xe5,
0x81, 0x33, 0xa0, 0xb1, 0x7b, 0xf5, 0xaa, 0xa8, 0x1e, 0xcb, 0xbb, 0x60, 0xf9, 0x1a, 0x09, 0xd6,
0xe5, 0xfa, 0xfe, 0x9f, 0x00, 0x00, 0x00, 0xff, 0xff, 0xcb, 0x26, 0x8a, 0x0b, 0x61, 0x04, 0x00,
0x00,
}
func (this *ConsensusParams) Equal(that interface{}) bool {
@@ -515,7 +516,7 @@ func (this *ConsensusParams) Equal(that interface{}) bool {
if !this.Version.Equal(that1.Version) {
return false
}
if !this.Timing.Equal(that1.Timing) {
if !this.Synchrony.Equal(that1.Synchrony) {
return false
}
return true
@@ -657,14 +658,14 @@ func (this *HashedParams) Equal(that interface{}) bool {
}
return true
}
func (this *TimingParams) Equal(that interface{}) bool {
func (this *SynchronyParams) Equal(that interface{}) bool {
if that == nil {
return this == nil
}
that1, ok := that.(*TimingParams)
that1, ok := that.(*SynchronyParams)
if !ok {
that2, ok := that.(TimingParams)
that2, ok := that.(SynchronyParams)
if ok {
that1 = &that2
} else {
@@ -704,9 +705,9 @@ func (m *ConsensusParams) MarshalToSizedBuffer(dAtA []byte) (int, error) {
_ = i
var l int
_ = l
if m.Timing != nil {
if m.Synchrony != nil {
{
size, err := m.Timing.MarshalToSizedBuffer(dAtA[:i])
size, err := m.Synchrony.MarshalToSizedBuffer(dAtA[:i])
if err != nil {
return 0, err
}
@@ -934,7 +935,7 @@ func (m *HashedParams) MarshalToSizedBuffer(dAtA []byte) (int, error) {
return len(dAtA) - i, nil
}
func (m *TimingParams) Marshal() (dAtA []byte, err error) {
func (m *SynchronyParams) Marshal() (dAtA []byte, err error) {
size := m.Size()
dAtA = make([]byte, size)
n, err := m.MarshalToSizedBuffer(dAtA[:size])
@@ -944,12 +945,12 @@ func (m *TimingParams) Marshal() (dAtA []byte, err error) {
return dAtA[:n], nil
}
func (m *TimingParams) MarshalTo(dAtA []byte) (int, error) {
func (m *SynchronyParams) MarshalTo(dAtA []byte) (int, error) {
size := m.Size()
return m.MarshalToSizedBuffer(dAtA[:size])
}
func (m *TimingParams) MarshalToSizedBuffer(dAtA []byte) (int, error) {
func (m *SynchronyParams) MarshalToSizedBuffer(dAtA []byte) (int, error) {
i := len(dAtA)
_ = i
var l int
@@ -1006,8 +1007,8 @@ func (m *ConsensusParams) Size() (n int) {
l = m.Version.Size()
n += 1 + l + sovParams(uint64(l))
}
if m.Timing != nil {
l = m.Timing.Size()
if m.Synchrony != nil {
l = m.Synchrony.Size()
n += 1 + l + sovParams(uint64(l))
}
return n
@@ -1087,7 +1088,7 @@ func (m *HashedParams) Size() (n int) {
return n
}
func (m *TimingParams) Size() (n int) {
func (m *SynchronyParams) Size() (n int) {
if m == nil {
return 0
}
@@ -1281,7 +1282,7 @@ func (m *ConsensusParams) Unmarshal(dAtA []byte) error {
iNdEx = postIndex
case 5:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Timing", wireType)
return fmt.Errorf("proto: wrong wireType = %d for field Synchrony", wireType)
}
var msglen int
for shift := uint(0); ; shift += 7 {
@@ -1308,10 +1309,10 @@ func (m *ConsensusParams) Unmarshal(dAtA []byte) error {
if postIndex > l {
return io.ErrUnexpectedEOF
}
if m.Timing == nil {
m.Timing = &TimingParams{}
if m.Synchrony == nil {
m.Synchrony = &SynchronyParams{}
}
if err := m.Timing.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
if err := m.Synchrony.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
return err
}
iNdEx = postIndex
@@ -1784,7 +1785,7 @@ func (m *HashedParams) Unmarshal(dAtA []byte) error {
}
return nil
}
func (m *TimingParams) Unmarshal(dAtA []byte) error {
func (m *SynchronyParams) Unmarshal(dAtA []byte) error {
l := len(dAtA)
iNdEx := 0
for iNdEx < l {
@@ -1807,10 +1808,10 @@ func (m *TimingParams) Unmarshal(dAtA []byte) error {
fieldNum := int32(wire >> 3)
wireType := int(wire & 0x7)
if wireType == 4 {
return fmt.Errorf("proto: TimingParams: wiretype end group for non-group")
return fmt.Errorf("proto: SynchronyParams: wiretype end group for non-group")
}
if fieldNum <= 0 {
return fmt.Errorf("proto: TimingParams: illegal tag %d (wire type %d)", fieldNum, wire)
return fmt.Errorf("proto: SynchronyParams: illegal tag %d (wire type %d)", fieldNum, wire)
}
switch fieldNum {
case 1:

View File

@@ -144,4 +144,4 @@ extend google.protobuf.FieldOptions {
optional bool wktpointer = 65012;
optional string castrepeated = 65013;
}
}

View File

@@ -71,7 +71,7 @@ func TestBasicGenesisDoc(t *testing.T) {
"app_hash":"",
"app_state":{"account_owner": "Bob"},
"consensus_params": {
"timing": {"precision": "1", "message_delay": "10"},
"synchrony": {"precision": "1", "message_delay": "10"},
"validator": {"pub_key_types":["ed25519"]},
"block": {"max_bytes": "100"},
"evidence": {"max_age_num_blocks": "100", "max_age_duration": "10"}

View File

@@ -41,7 +41,7 @@ type ConsensusParams struct {
Evidence EvidenceParams `json:"evidence"`
Validator ValidatorParams `json:"validator"`
Version VersionParams `json:"version"`
Timing TimingParams `json:"timing"`
Synchrony SynchronyParams `json:"synchrony"`
}
// HashedParams is a subset of ConsensusParams.
@@ -76,9 +76,9 @@ type VersionParams struct {
AppVersion uint64 `json:"app_version"`
}
// TimingParams influence the validity of block timestamps.
// SynchronyParams influence the validity of block timestamps.
// TODO (@wbanfield): add link to proposer-based timestamp spec when completed.
type TimingParams struct {
type SynchronyParams struct {
Precision time.Duration `json:"precision"`
MessageDelay time.Duration `json:"message_delay"`
}
@@ -90,7 +90,7 @@ func DefaultConsensusParams() *ConsensusParams {
Evidence: DefaultEvidenceParams(),
Validator: DefaultValidatorParams(),
Version: DefaultVersionParams(),
Timing: DefaultTimingParams(),
Synchrony: DefaultSynchronyParams(),
}
}
@@ -125,12 +125,12 @@ func DefaultVersionParams() VersionParams {
}
}
func DefaultTimingParams() TimingParams {
func DefaultSynchronyParams() SynchronyParams {
// 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,
return SynchronyParams{
Precision: 10 * time.Millisecond,
MessageDelay: 500 * time.Millisecond,
}
}
@@ -180,14 +180,14 @@ func (params ConsensusParams) ValidateConsensusParams() error {
params.Evidence.MaxBytes)
}
if params.Timing.MessageDelay <= 0 {
return fmt.Errorf("timing.MessageDelay must be greater than 0. Got: %d",
params.Timing.MessageDelay)
if params.Synchrony.MessageDelay <= 0 {
return fmt.Errorf("synchrony.MessageDelay must be greater than 0. Got: %d",
params.Synchrony.MessageDelay)
}
if params.Timing.Precision <= 0 {
return fmt.Errorf("timing.Precision must be greater than 0. Got: %d",
params.Timing.Precision)
if params.Synchrony.Precision <= 0 {
return fmt.Errorf("synchrony.Precision must be greater than 0. Got: %d",
params.Synchrony.Precision)
}
if len(params.Validator.PubKeyTypes) == 0 {
@@ -234,7 +234,7 @@ func (params *ConsensusParams) Equals(params2 *ConsensusParams) bool {
return params.Block == params2.Block &&
params.Evidence == params2.Evidence &&
params.Version == params2.Version &&
params.Timing == params2.Timing &&
params.Synchrony == params2.Synchrony &&
tmstrings.StringSliceEqual(params.Validator.PubKeyTypes, params2.Validator.PubKeyTypes)
}
@@ -265,9 +265,9 @@ func (params ConsensusParams) UpdateConsensusParams(params2 *tmproto.ConsensusPa
if params2.Version != nil {
res.Version.AppVersion = params2.Version.AppVersion
}
if params2.Timing != nil {
res.Timing.Precision = params2.Timing.Precision
res.Timing.MessageDelay = params2.Timing.MessageDelay
if params2.Synchrony != nil {
res.Synchrony.Precision = params2.Synchrony.Precision
res.Synchrony.MessageDelay = params2.Synchrony.MessageDelay
}
return res
}
@@ -289,9 +289,9 @@ func (params *ConsensusParams) ToProto() tmproto.ConsensusParams {
Version: &tmproto.VersionParams{
AppVersion: params.Version.AppVersion,
},
Timing: &tmproto.TimingParams{
MessageDelay: params.Timing.MessageDelay,
Precision: params.Timing.Precision,
Synchrony: &tmproto.SynchronyParams{
MessageDelay: params.Synchrony.MessageDelay,
Precision: params.Synchrony.Precision,
},
}
}
@@ -313,9 +313,9 @@ func ConsensusParamsFromProto(pbParams tmproto.ConsensusParams) ConsensusParams
Version: VersionParams{
AppVersion: pbParams.Version.AppVersion,
},
Timing: TimingParams{
MessageDelay: pbParams.Timing.MessageDelay,
Precision: pbParams.Timing.Precision,
Synchrony: SynchronyParams{
MessageDelay: pbParams.Synchrony.MessageDelay,
Precision: pbParams.Synchrony.Precision,
},
}
}

View File

@@ -194,7 +194,7 @@ func makeParams(args makeParamsArgs) ConsensusParams {
Validator: ValidatorParams{
PubKeyTypes: args.pubkeyTypes,
},
Timing: TimingParams{
Synchrony: SynchronyParams{
Precision: args.precision,
MessageDelay: args.messageDelay,
},
@@ -242,10 +242,10 @@ func TestConsensusParamsUpdate(t *testing.T) {
updatedParams: makeParams(makeParamsArgs{blockBytes: 1, blockGas: 2, evidenceAge: 3}),
},
{
// update timing params
// update synchrony params
intialParams: makeParams(makeParamsArgs{evidenceAge: 3, precision: time.Second, messageDelay: 3 * time.Second}),
updates: &tmproto.ConsensusParams{
Timing: &tmproto.TimingParams{
Synchrony: &tmproto.SynchronyParams{
Precision: time.Second * 2,
MessageDelay: time.Second * 4,
},

View File

@@ -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, sp SynchronyParams, initialHeight int64) bool {
// lhs is `proposedBlockTime - Precision` in the first inequality
lhs := p.Timestamp.Add(-sp.Precision)
// rhs is `proposedBlockTime + MsgDelay + Precision` in the second inequality
rhs := p.Timestamp.Add(sp.MessageDelay).Add(sp.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.

View File

@@ -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"
)
@@ -198,59 +197,93 @@ 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,
}
tp := TimingParams{
sp := SynchronyParams{
Precision: testCase.precision,
MessageDelay: testCase.msgDelay,
}
mockSource := new(tmtimemocks.Source)
mockSource.On("Now").Return(testCase.localTime)
ti := p.IsTimely(mockSource, tp)
ti := p.IsTimely(testCase.recvTime, sp, testCase.genesisHeight)
assert.Equal(t, testCase.expectTimely, ti)
})
}