Browse Source

types: fix evidence timestamp calculation (#5032)

depending on the votes order in DuplicateVoteEvidence is arbitrary.
we should always choose the latest timestamp.

Closes #5030
pull/5044/head
Anton Kaliaev 4 years ago
committed by GitHub
parent
commit
0b13059216
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 30 additions and 12 deletions
  1. +19
    -7
      types/evidence.go
  2. +11
    -5
      types/evidence_test.go

+ 19
- 7
types/evidence.go View File

@ -310,9 +310,9 @@ func (dve *DuplicateVoteEvidence) Height() int64 {
return dve.VoteA.Height return dve.VoteA.Height
} }
// Time returns the time the evidence was created.
// Time returns time of the latest vote.
func (dve *DuplicateVoteEvidence) Time() time.Time { func (dve *DuplicateVoteEvidence) Time() time.Time {
return dve.VoteA.Timestamp
return maxTime(dve.VoteA.Timestamp, dve.VoteB.Timestamp)
} }
// Address returns the address of the validator. // Address returns the address of the validator.
@ -677,8 +677,10 @@ OUTER_LOOP:
func (ev ConflictingHeadersEvidence) Height() int64 { return ev.H1.Height } func (ev ConflictingHeadersEvidence) Height() int64 { return ev.H1.Height }
// XXX: this is not the time of equivocation
func (ev ConflictingHeadersEvidence) Time() time.Time { return ev.H1.Time }
// Time returns time of the latest header.
func (ev ConflictingHeadersEvidence) Time() time.Time {
return maxTime(ev.H1.Time, ev.H2.Time)
}
func (ev ConflictingHeadersEvidence) Address() []byte { func (ev ConflictingHeadersEvidence) Address() []byte {
panic("use ConflictingHeadersEvidence#Split to split evidence into individual pieces") panic("use ConflictingHeadersEvidence#Split to split evidence into individual pieces")
@ -833,6 +835,7 @@ func (e PhantomValidatorEvidence) Height() int64 {
return e.Vote.Height return e.Vote.Height
} }
// Time returns the Vote's timestamp.
func (e PhantomValidatorEvidence) Time() time.Time { func (e PhantomValidatorEvidence) Time() time.Time {
return e.Vote.Timestamp return e.Vote.Timestamp
} }
@ -954,8 +957,9 @@ func (e LunaticValidatorEvidence) Height() int64 {
return e.Header.Height return e.Header.Height
} }
// Time returns the maximum between the header's time and vote's time.
func (e LunaticValidatorEvidence) Time() time.Time { func (e LunaticValidatorEvidence) Time() time.Time {
return e.Header.Time
return maxTime(e.Header.Time, e.Vote.Timestamp)
} }
func (e LunaticValidatorEvidence) Address() []byte { func (e LunaticValidatorEvidence) Address() []byte {
@ -1145,8 +1149,9 @@ func (e PotentialAmnesiaEvidence) Height() int64 {
return e.VoteA.Height return e.VoteA.Height
} }
// Time returns time of the latest vote.
func (e PotentialAmnesiaEvidence) Time() time.Time { func (e PotentialAmnesiaEvidence) Time() time.Time {
return e.VoteA.Timestamp
return maxTime(e.VoteA.Timestamp, e.VoteB.Timestamp)
} }
func (e PotentialAmnesiaEvidence) Address() []byte { func (e PotentialAmnesiaEvidence) Address() []byte {
@ -1340,7 +1345,7 @@ func (e ProofOfLockChange) Height() int64 {
return e.Votes[0].Height return e.Votes[0].Height
} }
// returns the time of the last vote
// Time returns time of the latest vote.
func (e ProofOfLockChange) Time() time.Time { func (e ProofOfLockChange) Time() time.Time {
latest := e.Votes[0].Timestamp latest := e.Votes[0].Timestamp
for _, vote := range e.Votes { for _, vote := range e.Votes {
@ -1770,3 +1775,10 @@ func NewMockPOLC(height int64, time time.Time, pubKey crypto.PubKey) ProofOfLock
PubKey: pubKey, PubKey: pubKey,
} }
} }
func maxTime(t1 time.Time, t2 time.Time) time.Time {
if t1.After(t2) {
return t1
}
return t2
}

+ 11
- 5
types/evidence_test.go View File

@ -80,6 +80,12 @@ func TestDuplicatedVoteEvidence(t *testing.T) {
assert.True(t, ev.Equal(ev)) assert.True(t, ev.Equal(ev))
assert.False(t, ev.Equal(&DuplicateVoteEvidence{})) assert.False(t, ev.Equal(&DuplicateVoteEvidence{}))
maxTime := ev.VoteB.Timestamp
if ev.VoteA.Timestamp.After(ev.VoteB.Timestamp) {
maxTime = ev.VoteA.Timestamp
}
assert.Equal(t, maxTime, ev.Time(), "expected time of the latest vote")
} }
func TestEvidenceList(t *testing.T) { func TestEvidenceList(t *testing.T) {
@ -152,7 +158,7 @@ func randomDuplicatedVoteEvidence(t *testing.T) *DuplicateVoteEvidence {
const chainID = "mychain" const chainID = "mychain"
return &DuplicateVoteEvidence{ return &DuplicateVoteEvidence{
VoteA: makeVote(t, val, chainID, 0, 10, 2, 1, blockID, defaultVoteTime), VoteA: makeVote(t, val, chainID, 0, 10, 2, 1, blockID, defaultVoteTime),
VoteB: makeVote(t, val, chainID, 0, 10, 2, 1, blockID2, defaultVoteTime),
VoteB: makeVote(t, val, chainID, 0, 10, 2, 1, blockID2, defaultVoteTime.Add(1*time.Minute)),
} }
} }
@ -223,7 +229,7 @@ func TestLunaticValidatorEvidence(t *testing.T) {
} }
assert.Equal(t, header.Height, ev.Height()) assert.Equal(t, header.Height, ev.Height())
assert.Equal(t, bTime, ev.Time())
assert.Equal(t, defaultVoteTime, ev.Time())
assert.EqualValues(t, vote.ValidatorAddress, ev.Address()) assert.EqualValues(t, vote.ValidatorAddress, ev.Address())
assert.NotEmpty(t, ev.Hash()) assert.NotEmpty(t, ev.Hash())
assert.NotEmpty(t, ev.Bytes()) assert.NotEmpty(t, ev.Bytes())
@ -330,7 +336,7 @@ func TestConflictingHeadersEvidence(t *testing.T) {
}) })
assert.Equal(t, height, ev.Height()) assert.Equal(t, height, ev.Height())
// assert.Equal(t, bTime, ev.Time())
assert.Equal(t, ev.H2.Time, ev.Time())
assert.NotEmpty(t, ev.Hash()) assert.NotEmpty(t, ev.Hash())
assert.NotEmpty(t, ev.Bytes()) assert.NotEmpty(t, ev.Bytes())
assert.NoError(t, ev.VerifyComposite(header1, valSet)) assert.NoError(t, ev.VerifyComposite(header1, valSet))
@ -350,7 +356,7 @@ func TestPotentialAmnesiaEvidence(t *testing.T) {
blockID = makeBlockID(tmhash.Sum([]byte("blockhash")), math.MaxInt32, tmhash.Sum([]byte("partshash"))) blockID = makeBlockID(tmhash.Sum([]byte("blockhash")), math.MaxInt32, tmhash.Sum([]byte("partshash")))
blockID2 = makeBlockID(tmhash.Sum([]byte("blockhash2")), math.MaxInt32, tmhash.Sum([]byte("partshash"))) blockID2 = makeBlockID(tmhash.Sum([]byte("blockhash2")), math.MaxInt32, tmhash.Sum([]byte("partshash")))
vote1 = makeVote(t, val, chainID, 0, height, 0, 2, blockID, defaultVoteTime) vote1 = makeVote(t, val, chainID, 0, height, 0, 2, blockID, defaultVoteTime)
vote2 = makeVote(t, val, chainID, 0, height, 1, 2, blockID2, defaultVoteTime)
vote2 = makeVote(t, val, chainID, 0, height, 1, 2, blockID2, defaultVoteTime.Add(1*time.Minute))
) )
ev := &PotentialAmnesiaEvidence{ ev := &PotentialAmnesiaEvidence{
@ -359,7 +365,7 @@ func TestPotentialAmnesiaEvidence(t *testing.T) {
} }
assert.Equal(t, height, ev.Height()) assert.Equal(t, height, ev.Height())
// assert.Equal(t, bTime, ev.Time())
assert.Equal(t, vote2.Timestamp, ev.Time())
assert.EqualValues(t, vote1.ValidatorAddress, ev.Address()) assert.EqualValues(t, vote1.ValidatorAddress, ev.Address())
assert.NotEmpty(t, ev.Hash()) assert.NotEmpty(t, ev.Hash())
assert.NotEmpty(t, ev.Bytes()) assert.NotEmpty(t, ev.Bytes())


Loading…
Cancel
Save