mirror of
https://github.com/tendermint/tendermint.git
synced 2026-01-08 14:21:14 +00:00
evidence: change evidence time to block time (#5219)
adds blockstore interface to evidence and adds fix to byzantine test
This commit is contained in:
@@ -644,7 +644,8 @@ func TestBlockProtoBuf(t *testing.T) {
|
||||
|
||||
b2 := MakeBlock(h, []Tx{Tx([]byte{1})}, c1, []Evidence{})
|
||||
b2.ProposerAddress = tmrand.Bytes(crypto.AddressSize)
|
||||
evi := NewMockDuplicateVoteEvidence(h, time.Now(), "block-test-chain")
|
||||
evidenceTime := time.Date(2019, 1, 1, 0, 0, 0, 0, time.UTC)
|
||||
evi := NewMockDuplicateVoteEvidence(h, evidenceTime, "block-test-chain")
|
||||
b2.Evidence = EvidenceData{Evidence: EvidenceList{evi}}
|
||||
b2.EvidenceHash = b2.Evidence.Hash()
|
||||
|
||||
@@ -714,7 +715,7 @@ func TestEvidenceDataProtoBuf(t *testing.T) {
|
||||
const chainID = "mychain"
|
||||
v := makeVote(t, val, chainID, math.MaxInt32, math.MaxInt64, 1, 0x01, blockID, time.Now())
|
||||
v2 := makeVote(t, val, chainID, math.MaxInt32, math.MaxInt64, 2, 0x01, blockID2, time.Now())
|
||||
ev := NewDuplicateVoteEvidence(v2, v)
|
||||
ev := NewDuplicateVoteEvidence(v2, v, v2.Timestamp)
|
||||
data := &EvidenceData{Evidence: EvidenceList{ev}}
|
||||
_ = data.Hash()
|
||||
testCases := []struct {
|
||||
|
||||
@@ -181,13 +181,15 @@ func init() {
|
||||
type DuplicateVoteEvidence struct {
|
||||
VoteA *Vote `json:"vote_a"`
|
||||
VoteB *Vote `json:"vote_b"`
|
||||
|
||||
Timestamp time.Time `json:"timestamp"`
|
||||
}
|
||||
|
||||
var _ Evidence = &DuplicateVoteEvidence{}
|
||||
|
||||
// NewDuplicateVoteEvidence creates DuplicateVoteEvidence with right ordering given
|
||||
// two conflicting votes. If one of the votes is nil, evidence returned is nil as well
|
||||
func NewDuplicateVoteEvidence(vote1 *Vote, vote2 *Vote) *DuplicateVoteEvidence {
|
||||
func NewDuplicateVoteEvidence(vote1, vote2 *Vote, time time.Time) *DuplicateVoteEvidence {
|
||||
var voteA, voteB *Vote
|
||||
if vote1 == nil || vote2 == nil {
|
||||
return nil
|
||||
@@ -202,13 +204,14 @@ func NewDuplicateVoteEvidence(vote1 *Vote, vote2 *Vote) *DuplicateVoteEvidence {
|
||||
return &DuplicateVoteEvidence{
|
||||
VoteA: voteA,
|
||||
VoteB: voteB,
|
||||
|
||||
Timestamp: time,
|
||||
}
|
||||
}
|
||||
|
||||
// String returns a string representation of the evidence.
|
||||
func (dve *DuplicateVoteEvidence) String() string {
|
||||
return fmt.Sprintf("DuplicateVoteEvidence{VoteA: %v, VoteB: %v}", dve.VoteA, dve.VoteB)
|
||||
|
||||
return fmt.Sprintf("DuplicateVoteEvidence{VoteA: %v, VoteB: %v, Time: %v}", dve.VoteA, dve.VoteB, dve.Timestamp)
|
||||
}
|
||||
|
||||
// Height returns the height this evidence refers to.
|
||||
@@ -218,7 +221,7 @@ func (dve *DuplicateVoteEvidence) Height() int64 {
|
||||
|
||||
// Time returns time of the latest vote.
|
||||
func (dve *DuplicateVoteEvidence) Time() time.Time {
|
||||
return maxTime(dve.VoteA.Timestamp, dve.VoteB.Timestamp)
|
||||
return dve.Timestamp
|
||||
}
|
||||
|
||||
// Address returns the address of the validator.
|
||||
@@ -358,8 +361,9 @@ func (dve *DuplicateVoteEvidence) ToProto() *tmproto.DuplicateVoteEvidence {
|
||||
voteB := dve.VoteB.ToProto()
|
||||
voteA := dve.VoteA.ToProto()
|
||||
tp := tmproto.DuplicateVoteEvidence{
|
||||
VoteA: voteA,
|
||||
VoteB: voteB,
|
||||
VoteA: voteA,
|
||||
VoteB: voteB,
|
||||
Timestamp: dve.Timestamp,
|
||||
}
|
||||
return &tp
|
||||
}
|
||||
@@ -379,10 +383,7 @@ func DuplicateVoteEvidenceFromProto(pb *tmproto.DuplicateVoteEvidence) (*Duplica
|
||||
return nil, err
|
||||
}
|
||||
|
||||
dve := new(DuplicateVoteEvidence)
|
||||
|
||||
dve.VoteA = vA
|
||||
dve.VoteB = vB
|
||||
dve := NewDuplicateVoteEvidence(vA, vB, pb.Timestamp)
|
||||
|
||||
return dve, dve.ValidateBasic()
|
||||
}
|
||||
@@ -441,11 +442,12 @@ func (ev *ConflictingHeadersEvidence) Split(committedHeader *Header, valSet *Val
|
||||
if sig.Absent() {
|
||||
continue
|
||||
}
|
||||
evList = append(evList, &LunaticValidatorEvidence{
|
||||
Header: alternativeHeader.Header,
|
||||
Vote: alternativeHeader.Commit.GetVote(int32(i)),
|
||||
InvalidHeaderField: invalidField,
|
||||
})
|
||||
evList = append(evList, NewLunaticValidatorEvidence(
|
||||
alternativeHeader.Header,
|
||||
alternativeHeader.Commit.GetVote(int32(i)),
|
||||
invalidField,
|
||||
committedHeader.Time, //take the time of our own trusted header
|
||||
))
|
||||
}
|
||||
return evList
|
||||
}
|
||||
@@ -483,16 +485,17 @@ OUTER_LOOP:
|
||||
// messages in both commits, then it is an equivocation misbehavior =>
|
||||
// immediately slashable (#F1).
|
||||
if ev.H1.Commit.Round == ev.H2.Commit.Round {
|
||||
evList = append(evList, &DuplicateVoteEvidence{
|
||||
VoteA: ev.H1.Commit.GetVote(int32(i)),
|
||||
VoteB: ev.H2.Commit.GetVote(int32(j)),
|
||||
})
|
||||
evList = append(evList, NewDuplicateVoteEvidence(
|
||||
ev.H1.Commit.GetVote(int32(i)),
|
||||
ev.H2.Commit.GetVote(int32(j)),
|
||||
ev.H1.Time,
|
||||
))
|
||||
} else {
|
||||
// if H1.Round != H2.Round we need to run full detection procedure => not
|
||||
// immediately slashable.
|
||||
firstVote := ev.H1.Commit.GetVote(int32(i))
|
||||
secondVote := ev.H2.Commit.GetVote(int32(j))
|
||||
newEv := NewPotentialAmnesiaEvidence(firstVote, secondVote)
|
||||
newEv := NewPotentialAmnesiaEvidence(firstVote, secondVote, committedHeader.Time)
|
||||
|
||||
// has the validator incorrectly voted for a previous round
|
||||
if newEv.VoteA.Round > newEv.VoteB.Round {
|
||||
@@ -671,16 +674,21 @@ type LunaticValidatorEvidence struct {
|
||||
Header *Header `json:"header"`
|
||||
Vote *Vote `json:"vote"`
|
||||
InvalidHeaderField string `json:"invalid_header_field"`
|
||||
|
||||
Timestamp time.Time `json:"timestamp"`
|
||||
}
|
||||
|
||||
var _ Evidence = &LunaticValidatorEvidence{}
|
||||
|
||||
// NewLunaticValidatorEvidence creates a new instance of the respective evidence
|
||||
func NewLunaticValidatorEvidence(header *Header, vote *Vote, invalidHeaderField string) *LunaticValidatorEvidence {
|
||||
func NewLunaticValidatorEvidence(header *Header,
|
||||
vote *Vote, invalidHeaderField string, time time.Time) *LunaticValidatorEvidence {
|
||||
return &LunaticValidatorEvidence{
|
||||
Header: header,
|
||||
Vote: vote,
|
||||
InvalidHeaderField: invalidHeaderField,
|
||||
|
||||
Timestamp: time,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -690,7 +698,7 @@ func (e *LunaticValidatorEvidence) Height() int64 {
|
||||
|
||||
// Time returns the maximum between the header's time and vote's time.
|
||||
func (e *LunaticValidatorEvidence) Time() time.Time {
|
||||
return maxTime(e.Header.Time, e.Vote.Timestamp)
|
||||
return e.Timestamp
|
||||
}
|
||||
|
||||
func (e *LunaticValidatorEvidence) Address() []byte {
|
||||
@@ -839,6 +847,7 @@ func (e *LunaticValidatorEvidence) ToProto() *tmproto.LunaticValidatorEvidence {
|
||||
Header: h,
|
||||
Vote: v,
|
||||
InvalidHeaderField: e.InvalidHeaderField,
|
||||
Timestamp: e.Timestamp,
|
||||
}
|
||||
|
||||
return tp
|
||||
@@ -863,6 +872,7 @@ func LunaticValidatorEvidenceFromProto(pb *tmproto.LunaticValidatorEvidence) (*L
|
||||
Header: &h,
|
||||
Vote: v,
|
||||
InvalidHeaderField: pb.InvalidHeaderField,
|
||||
Timestamp: pb.Timestamp,
|
||||
}
|
||||
|
||||
return &tp, tp.ValidateBasic()
|
||||
@@ -880,20 +890,21 @@ type PotentialAmnesiaEvidence struct {
|
||||
VoteB *Vote `json:"vote_b"`
|
||||
|
||||
HeightStamp int64
|
||||
Timestamp time.Time `json:"timestamp"`
|
||||
}
|
||||
|
||||
var _ Evidence = &PotentialAmnesiaEvidence{}
|
||||
|
||||
// NewPotentialAmnesiaEvidence creates a new instance of the evidence and orders the votes correctly
|
||||
func NewPotentialAmnesiaEvidence(voteA *Vote, voteB *Vote) *PotentialAmnesiaEvidence {
|
||||
func NewPotentialAmnesiaEvidence(voteA, voteB *Vote, time time.Time) *PotentialAmnesiaEvidence {
|
||||
if voteA == nil || voteB == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if voteA.Timestamp.Before(voteB.Timestamp) {
|
||||
return &PotentialAmnesiaEvidence{VoteA: voteA, VoteB: voteB}
|
||||
return &PotentialAmnesiaEvidence{VoteA: voteA, VoteB: voteB, Timestamp: time}
|
||||
}
|
||||
return &PotentialAmnesiaEvidence{VoteA: voteB, VoteB: voteA}
|
||||
return &PotentialAmnesiaEvidence{VoteA: voteB, VoteB: voteA, Timestamp: time}
|
||||
}
|
||||
|
||||
func (e *PotentialAmnesiaEvidence) Height() int64 {
|
||||
@@ -901,7 +912,7 @@ func (e *PotentialAmnesiaEvidence) Height() int64 {
|
||||
}
|
||||
|
||||
func (e *PotentialAmnesiaEvidence) Time() time.Time {
|
||||
return e.VoteB.Timestamp
|
||||
return e.Timestamp
|
||||
}
|
||||
|
||||
func (e *PotentialAmnesiaEvidence) Address() []byte {
|
||||
@@ -1057,6 +1068,7 @@ func (e *PotentialAmnesiaEvidence) ToProto() *tmproto.PotentialAmnesiaEvidence {
|
||||
VoteA: voteA,
|
||||
VoteB: voteB,
|
||||
HeightStamp: e.HeightStamp,
|
||||
Timestamp: e.Timestamp,
|
||||
}
|
||||
|
||||
return tp
|
||||
@@ -1451,6 +1463,7 @@ func PotentialAmnesiaEvidenceFromProto(pb *tmproto.PotentialAmnesiaEvidence) (*P
|
||||
VoteA: voteA,
|
||||
VoteB: voteB,
|
||||
HeightStamp: pb.GetHeightStamp(),
|
||||
Timestamp: pb.Timestamp,
|
||||
}
|
||||
|
||||
return &tp, tp.ValidateBasic()
|
||||
@@ -1534,8 +1547,7 @@ func NewMockDuplicateVoteEvidenceWithValidator(height int64, time time.Time,
|
||||
vB := voteB.ToProto()
|
||||
_ = pv.SignVote(chainID, vB)
|
||||
voteB.Signature = vB.Signature
|
||||
return NewDuplicateVoteEvidence(voteA, voteB)
|
||||
|
||||
return NewDuplicateVoteEvidence(voteA, voteB, time)
|
||||
}
|
||||
|
||||
func makeMockVote(height int64, round, index int32, addr Address,
|
||||
|
||||
@@ -23,7 +23,7 @@ type voteData struct {
|
||||
|
||||
var defaultVoteTime = time.Date(2019, 1, 1, 0, 0, 0, 0, time.UTC)
|
||||
|
||||
func TestEvidence(t *testing.T) {
|
||||
func TestDuplicateVoteEvidence(t *testing.T) {
|
||||
val := NewMockPV()
|
||||
val2 := NewMockPV()
|
||||
|
||||
@@ -67,6 +67,8 @@ func TestEvidence(t *testing.T) {
|
||||
ev := &DuplicateVoteEvidence{
|
||||
VoteA: c.vote1,
|
||||
VoteB: c.vote2,
|
||||
|
||||
Timestamp: defaultVoteTime,
|
||||
}
|
||||
if c.valid {
|
||||
assert.Nil(t, ev.Verify(chainID, pubKey), "evidence should be valid")
|
||||
@@ -74,19 +76,12 @@ func TestEvidence(t *testing.T) {
|
||||
assert.NotNil(t, ev.Verify(chainID, pubKey), "evidence should be invalid")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestDuplicatedVoteEvidence(t *testing.T) {
|
||||
ev := randomDuplicatedVoteEvidence(t)
|
||||
|
||||
assert.True(t, ev.Equal(ev))
|
||||
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) {
|
||||
@@ -187,7 +182,7 @@ func TestDuplicateVoteEvidenceValidation(t *testing.T) {
|
||||
t.Run(tc.testName, func(t *testing.T) {
|
||||
vote1 := makeVote(t, val, chainID, math.MaxInt32, math.MaxInt64, math.MaxInt32, 0x02, blockID, defaultVoteTime)
|
||||
vote2 := makeVote(t, val, chainID, math.MaxInt32, math.MaxInt64, math.MaxInt32, 0x02, blockID2, defaultVoteTime)
|
||||
ev := NewDuplicateVoteEvidence(vote1, vote2)
|
||||
ev := NewDuplicateVoteEvidence(vote1, vote2, vote1.Timestamp)
|
||||
tc.malleateEvidence(ev)
|
||||
assert.Equal(t, tc.expectErr, ev.ValidateBasic() != nil, "Validate Basic had an unexpected result")
|
||||
})
|
||||
@@ -220,11 +215,11 @@ func TestLunaticValidatorEvidence(t *testing.T) {
|
||||
|
||||
vote := makeVote(t, val, header.ChainID, 0, header.Height, 0, 2, blockID, defaultVoteTime)
|
||||
|
||||
ev := NewLunaticValidatorEvidence(header, vote, "AppHash")
|
||||
ev := NewLunaticValidatorEvidence(header, vote, "AppHash", bTime)
|
||||
|
||||
//happy path
|
||||
assert.Equal(t, header.Height, ev.Height())
|
||||
assert.Equal(t, defaultVoteTime, ev.Time())
|
||||
assert.Equal(t, bTime, ev.Time())
|
||||
assert.EqualValues(t, vote.ValidatorAddress, ev.Address())
|
||||
assert.NotEmpty(t, ev.Hash())
|
||||
assert.NotEmpty(t, ev.Bytes())
|
||||
@@ -248,12 +243,12 @@ func TestLunaticValidatorEvidence(t *testing.T) {
|
||||
emptyBlockVote := makeVote(t, val, header.ChainID, 0, header.Height, 0, 2, BlockID{}, defaultVoteTime)
|
||||
|
||||
invalidLunaticEvidence := []*LunaticValidatorEvidence{
|
||||
NewLunaticValidatorEvidence(header, invalidVote, "AppHash"),
|
||||
NewLunaticValidatorEvidence(header, invalidHeightVote, "AppHash"),
|
||||
NewLunaticValidatorEvidence(nil, vote, "AppHash"),
|
||||
NewLunaticValidatorEvidence(header, nil, "AppHash"),
|
||||
NewLunaticValidatorEvidence(header, vote, "other"),
|
||||
NewLunaticValidatorEvidence(header, emptyBlockVote, "AppHash"),
|
||||
NewLunaticValidatorEvidence(header, invalidVote, "AppHash", header.Time),
|
||||
NewLunaticValidatorEvidence(header, invalidHeightVote, "AppHash", header.Time),
|
||||
NewLunaticValidatorEvidence(nil, vote, "AppHash", vote.Timestamp),
|
||||
NewLunaticValidatorEvidence(header, nil, "AppHash", header.Time),
|
||||
NewLunaticValidatorEvidence(header, vote, "other", header.Time),
|
||||
NewLunaticValidatorEvidence(header, emptyBlockVote, "AppHash", header.Time),
|
||||
}
|
||||
|
||||
for idx, ev := range invalidLunaticEvidence {
|
||||
@@ -348,10 +343,10 @@ func TestPotentialAmnesiaEvidence(t *testing.T) {
|
||||
vote3 = makeVote(t, val, chainID, 0, height, 2, 2, blockID, defaultVoteTime)
|
||||
)
|
||||
|
||||
ev := NewPotentialAmnesiaEvidence(vote1, vote2)
|
||||
ev := NewPotentialAmnesiaEvidence(vote1, vote2, vote1.Timestamp)
|
||||
|
||||
assert.Equal(t, height, ev.Height())
|
||||
assert.Equal(t, vote2.Timestamp, ev.Time())
|
||||
assert.Equal(t, vote1.Timestamp, ev.Time())
|
||||
assert.EqualValues(t, vote1.ValidatorAddress, ev.Address())
|
||||
assert.NotEmpty(t, ev.Hash())
|
||||
assert.NotEmpty(t, ev.Bytes())
|
||||
@@ -375,7 +370,7 @@ func TestPotentialAmnesiaEvidence(t *testing.T) {
|
||||
assert.True(t, ev.Equal(ev2))
|
||||
assert.Equal(t, ev.Hash(), ev2.Hash())
|
||||
|
||||
ev3 := NewPotentialAmnesiaEvidence(vote2, vote1)
|
||||
ev3 := NewPotentialAmnesiaEvidence(vote2, vote1, vote1.Timestamp)
|
||||
assert.True(t, ev3.Equal(ev))
|
||||
|
||||
ev4 := &PotentialAmnesiaEvidence{
|
||||
|
||||
@@ -29,16 +29,18 @@ var (
|
||||
)
|
||||
|
||||
type ErrVoteConflictingVotes struct {
|
||||
*DuplicateVoteEvidence
|
||||
VoteA *Vote
|
||||
VoteB *Vote
|
||||
}
|
||||
|
||||
func (err *ErrVoteConflictingVotes) Error() string {
|
||||
return fmt.Sprintf("conflicting votes from validator %X", err.VoteA.ValidatorAddress)
|
||||
}
|
||||
|
||||
func NewConflictingVoteError(val *Validator, vote1, vote2 *Vote) *ErrVoteConflictingVotes {
|
||||
func NewConflictingVoteError(vote1, vote2 *Vote) *ErrVoteConflictingVotes {
|
||||
return &ErrVoteConflictingVotes{
|
||||
NewDuplicateVoteEvidence(vote1, vote2),
|
||||
VoteA: vote1,
|
||||
VoteB: vote2,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -207,7 +207,7 @@ func (voteSet *VoteSet) addVote(vote *Vote) (added bool, err error) {
|
||||
// Add vote and get conflicting vote if any.
|
||||
added, conflicting := voteSet.addVerifiedVote(vote, blockKey, val.VotingPower)
|
||||
if conflicting != nil {
|
||||
return added, NewConflictingVoteError(val, conflicting, vote)
|
||||
return added, NewConflictingVoteError(conflicting, vote)
|
||||
}
|
||||
if !added {
|
||||
panic("Expected to add non-conflicting vote")
|
||||
|
||||
Reference in New Issue
Block a user