Browse Source

evidence: change evidence time to block time (#5219)

adds blockstore interface to evidence and adds fix to byzantine test
pull/5231/head
Callum Waters 4 years ago
committed by GitHub
parent
commit
312c4f8fe1
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
22 changed files with 527 additions and 213 deletions
  1. +1
    -1
      .golangci.yml
  2. +4
    -0
      CHANGELOG_PENDING.md
  3. +6
    -3
      abci/types/types.pb.go
  4. +17
    -17
      consensus/byzantine_test.go
  5. +4
    -2
      consensus/reactor_test.go
  6. +10
    -1
      consensus/state.go
  7. +30
    -0
      evidence/mocks/block_store.go
  8. +19
    -7
      evidence/pool.go
  9. +30
    -17
      evidence/pool_test.go
  10. +9
    -4
      evidence/reactor_test.go
  11. +11
    -0
      evidence/services.go
  12. +0
    -1
      node/node.go
  13. +211
    -50
      proto/tendermint/types/evidence.pb.go
  14. +9
    -0
      proto/tendermint/types/evidence.proto
  15. +10
    -2
      rpc/client/evidence_test.go
  16. +28
    -21
      state/validation.go
  17. +64
    -33
      state/validation_test.go
  18. +3
    -2
      types/block_test.go
  19. +40
    -28
      types/evidence.go
  20. +15
    -20
      types/evidence_test.go
  21. +5
    -3
      types/vote.go
  22. +1
    -1
      types/vote_set.go

+ 1
- 1
.golangci.yml View File

@ -20,7 +20,7 @@ linters:
- gosimple
- govet
- ineffassign
- interfacer
# - interfacer
- lll
- misspell
# - maligned


+ 4
- 0
CHANGELOG_PENDING.md View File

@ -18,6 +18,10 @@ Friendly reminder, we have a [bug bounty program](https://hackerone.com/tendermi
- [abci] [\#5174](https://github.com/tendermint/tendermint/pull/5174) Add amnesia evidence and remove mock and potential amnesia evidence from abci (@cmwaters)
### IMPROVEMENTS:
- [evidence] [\#5219](https://github.com/tendermint/tendermint/pull/5219) Change the source of evidence time to block time (@cmwaters)
### BUG FIXES:
- [evidence] [\#5170](https://github.com/tendermint/tendermint/pull/5170) change abci evidence time to the time the infraction happened not the time the evidence was committed on the block (@cmwaters)


+ 6
- 3
abci/types/types.pb.go View File

@ -2944,10 +2944,13 @@ func (m *VoteInfo) GetSignedLastBlock() bool {
}
type Evidence struct {
Type string `protobuf:"bytes,1,opt,name=type,proto3" json:"type,omitempty"`
Type string `protobuf:"bytes,1,opt,name=type,proto3" json:"type,omitempty"`
// The offending validator
Validator Validator `protobuf:"bytes,2,opt,name=validator,proto3" json:"validator"`
Height int64 `protobuf:"varint,3,opt,name=height,proto3" json:"height,omitempty"`
Time time.Time `protobuf:"bytes,4,opt,name=time,proto3,stdtime" json:"time"`
// The height when the offense occurred
Height int64 `protobuf:"varint,3,opt,name=height,proto3" json:"height,omitempty"`
// The corresponding time where the offense occurred
Time time.Time `protobuf:"bytes,4,opt,name=time,proto3,stdtime" json:"time"`
// Total voting power of the validator set in case the ABCI application does
// not store historical validators.
// https://github.com/tendermint/tendermint/issues/4581


+ 17
- 17
consensus/byzantine_test.go View File

@ -157,25 +157,25 @@ func TestByzantinePrevoteEquivocation(t *testing.T) {
}
defer stopConsensusNet(log.TestingLogger(), reactors, eventBuses)
// Check that evidence is submitted and committed at the third height
for i := 0; i < 2; i++ {
timeoutWaitGroup(t, nValidators, func(j int) {
<-blocksSubs[j].Out()
}, css)
}
timeoutWaitGroup(t, nValidators, func(j int) {
msg := <-blocksSubs[j].Out()
// Evidence should be submitted and committed at the third height but
// we will check the first five just in case
var evidence types.Evidence
for i := 0; i < 5; i++ {
msg := <-blocksSubs[nValidators-1].Out()
block := msg.Data().(types.EventDataNewBlock).Block
// assert that we have evidence
if assert.True(t, len(block.Evidence.Evidence) == 1) {
// and that the evidence is of type DuplicateVoteEvidence
ev, ok := block.Evidence.Evidence[0].(*types.DuplicateVoteEvidence)
assert.True(t, ok)
// and that the address matches to that of the byzantine node
pubkey, _ := bcs.privValidator.GetPubKey()
assert.Equal(t, []byte(pubkey.Address()), ev.Address())
if len(block.Evidence.Evidence) > 0 {
evidence = block.Evidence.Evidence[0]
break
}
}, css)
}
if assert.NotNil(t, evidence) {
ev, ok := evidence.(*types.DuplicateVoteEvidence)
assert.True(t, ok)
pubkey, _ := bcs.privValidator.GetPubKey()
assert.Equal(t, []byte(pubkey.Address()), ev.Address())
}
}
// 4 validators. 1 is byzantine. The other three are partitioned into A (1 val) and B (2 vals).


+ 4
- 2
consensus/reactor_test.go View File

@ -39,6 +39,8 @@ import (
//----------------------------------------------
// in-process testnets
var defaultTestTime = time.Date(2019, 1, 1, 0, 0, 0, 0, time.UTC)
func startConsensusNet(t *testing.T, css []*State, n int) (
[]*Reactor,
[]types.Subscription,
@ -202,7 +204,7 @@ type mockEvidencePool struct {
func newMockEvidencePool(val types.PrivValidator) *mockEvidencePool {
return &mockEvidencePool{
ev: []types.Evidence{types.NewMockDuplicateVoteEvidenceWithValidator(1, time.Now().UTC(), val, config.ChainID())},
ev: []types.Evidence{types.NewMockDuplicateVoteEvidenceWithValidator(1, defaultTestTime, val, config.ChainID())},
}
}
@ -234,7 +236,7 @@ func (m *mockEvidencePool) IsPending(evidence types.Evidence) bool {
return false
}
func (m *mockEvidencePool) AddPOLC(*types.ProofOfLockChange) error { return nil }
func (m *mockEvidencePool) Header(int64) *types.Header { return nil }
func (m *mockEvidencePool) Header(int64) *types.Header { return &types.Header{Time: defaultTestTime} }
//------------------------------------


+ 10
- 1
consensus/state.go View File

@ -1817,7 +1817,16 @@ func (cs *State) tryAddVote(vote *types.Vote, peerID p2p.ID) (bool, error) {
vote.Type)
return added, err
}
cs.evpool.AddEvidence(voteErr.DuplicateVoteEvidence)
var timestamp time.Time
if voteErr.VoteA.Height == 1 {
timestamp = cs.state.LastBlockTime // genesis time
} else {
timestamp = sm.MedianTime(cs.LastCommit.MakeCommit(), cs.LastValidators)
}
evidenceErr := cs.evpool.AddEvidence(types.NewDuplicateVoteEvidence(voteErr.VoteA, voteErr.VoteB, timestamp))
if evidenceErr != nil {
cs.Logger.Error("Failed to add evidence to the evidence pool", "err", evidenceErr)
}
return added, err
} else if err == types.ErrVoteNonDeterministicSignature {
cs.Logger.Debug("Vote has non-deterministic signature", "err", err)


+ 30
- 0
evidence/mocks/block_store.go View File

@ -0,0 +1,30 @@
// Code generated by mockery v2.1.0. DO NOT EDIT.
package mocks
import (
mock "github.com/stretchr/testify/mock"
types "github.com/tendermint/tendermint/types"
)
// BlockStore is an autogenerated mock type for the BlockStore type
type BlockStore struct {
mock.Mock
}
// LoadBlockMeta provides a mock function with given fields: height
func (_m *BlockStore) LoadBlockMeta(height int64) *types.BlockMeta {
ret := _m.Called(height)
var r0 *types.BlockMeta
if rf, ok := ret.Get(0).(func(int64) *types.BlockMeta); ok {
r0 = rf(height)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*types.BlockMeta)
}
}
return r0
}

+ 19
- 7
evidence/pool.go View File

@ -13,7 +13,6 @@ import (
"github.com/tendermint/tendermint/libs/log"
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
sm "github.com/tendermint/tendermint/state"
"github.com/tendermint/tendermint/store"
"github.com/tendermint/tendermint/types"
)
@ -34,7 +33,7 @@ type Pool struct {
// needed to load validators to verify evidence
stateDB dbm.DB
// needed to load headers to verify evidence
blockStore *store.BlockStore
blockStore BlockStore
mtx sync.Mutex
// latest state
@ -48,7 +47,7 @@ type Pool struct {
// Creates a new pool. If using an existing evidence store, it will add all pending evidence
// to the concurrent list.
func NewPool(stateDB, evidenceDB dbm.DB, blockStore *store.BlockStore) (*Pool, error) {
func NewPool(stateDB, evidenceDB dbm.DB, blockStore BlockStore) (*Pool, error) {
var (
state = sm.LoadState(stateDB)
)
@ -184,17 +183,30 @@ func (evpool *Pool) AddEvidence(evidence types.Evidence) error {
}
}
// For lunatic validator evidence, a header needs to be fetched.
// A header needs to be fetched. For lunatic evidence this is so we can verify
// that some of the fields are different to the ones we have. For all evidence it
// it so we can verify that the time of the evidence is correct
var header *types.Header
if _, ok := ev.(*types.LunaticValidatorEvidence); ok {
// if the evidence is from the current height - this means the evidence is fresh from the consensus
// and we won't have it in the block store. We thus check that the time isn't before the previous block
if ev.Height() == evpool.State().LastBlockHeight+1 {
if ev.Time().Before(evpool.State().LastBlockTime) {
return fmt.Errorf("evidence is from an earlier time than the previous block: %v < %v",
ev.Time(),
evpool.State().LastBlockTime)
}
header = &types.Header{Time: ev.Time()}
} else { // if the evidence is from a prior height
header = evpool.Header(ev.Height())
if header == nil {
return fmt.Errorf("don't have block meta at height #%d", ev.Height())
return fmt.Errorf("don't have header at height #%d", ev.Height())
}
}
// 1) Verify against state.
if err := sm.VerifyEvidence(evpool.stateDB, state, ev, header); err != nil {
evpool.logger.Debug("Inbound evidence is invalid", "evidence", ev, "err", err)
return types.NewErrEvidenceInvalid(ev, err)
}
@ -238,7 +250,7 @@ func (evpool *Pool) AddEvidence(evidence types.Evidence) error {
// 3) Add evidence to clist.
evpool.evidenceList.PushBack(ev)
evpool.logger.Info("Verified new evidence of byzantine behaviour", "evidence", ev)
evpool.logger.Info("Verified new evidence of byzantine behavior", "evidence", ev)
}
return nil


+ 30
- 17
evidence/pool_test.go View File

@ -7,11 +7,13 @@ import (
"github.com/gogo/protobuf/proto"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require"
dbm "github.com/tendermint/tm-db"
"github.com/tendermint/tendermint/crypto/tmhash"
"github.com/tendermint/tendermint/evidence/mocks"
"github.com/tendermint/tendermint/libs/bytes"
"github.com/tendermint/tendermint/libs/log"
tmrand "github.com/tendermint/tendermint/libs/rand"
@ -33,18 +35,20 @@ const evidenceChainID = "test_chain"
func TestEvidencePool(t *testing.T) {
var (
val = types.NewMockPV()
valAddr = val.PrivKey.PubKey().Address()
height = int64(52)
stateDB = initializeValidatorState(val, height)
evidenceDB = dbm.NewMemDB()
blockStoreDB = dbm.NewMemDB()
blockStore = initializeBlockStore(blockStoreDB, sm.LoadState(stateDB), valAddr)
blockStore = &mocks.BlockStore{}
evidenceTime = time.Date(2019, 1, 1, 0, 0, 0, 0, time.UTC)
goodEvidence = types.NewMockDuplicateVoteEvidenceWithValidator(height, evidenceTime, val, evidenceChainID)
badEvidence = types.NewMockDuplicateVoteEvidenceWithValidator(1, evidenceTime, val, evidenceChainID)
)
blockStore.On("LoadBlockMeta", mock.AnythingOfType("int64")).Return(
&types.BlockMeta{Header: types.Header{Time: evidenceTime}},
)
pool, err := NewPool(stateDB, evidenceDB, blockStore)
require.NoError(t, err)
@ -86,11 +90,14 @@ func TestProposingAndCommittingEvidence(t *testing.T) {
height = int64(1)
stateDB = initializeValidatorState(val, height)
evidenceDB = dbm.NewMemDB()
blockStoreDB = dbm.NewMemDB()
blockStore = initializeBlockStore(blockStoreDB, sm.LoadState(stateDB), val.PrivKey.PubKey().Address())
blockStore = &mocks.BlockStore{}
evidenceTime = time.Date(2019, 1, 1, 0, 0, 0, 0, time.UTC)
)
blockStore.On("LoadBlockMeta", mock.AnythingOfType("int64")).Return(
&types.BlockMeta{Header: types.Header{Time: evidenceTime}},
)
pool, err := NewPool(stateDB, evidenceDB, blockStore)
require.NoError(t, err)
@ -300,12 +307,11 @@ func TestAddingPotentialAmnesiaEvidence(t *testing.T) {
},
Proposer: val.ExtractIntoValidator(1),
}
height = int64(30)
stateDB = initializeStateFromValidatorSet(valSet, height)
evidenceDB = dbm.NewMemDB()
blockStoreDB = dbm.NewMemDB()
state = sm.LoadState(stateDB)
blockStore = initializeBlockStore(blockStoreDB, state, pubKey.Address())
height = int64(30)
stateDB = initializeStateFromValidatorSet(valSet, height)
evidenceDB = dbm.NewMemDB()
state = sm.LoadState(stateDB)
blockStore = &mocks.BlockStore{}
//evidenceTime = time.Date(2019, 1, 1, 0, 0, 0, 0, time.UTC)
firstBlockID = types.BlockID{
Hash: []byte("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"),
@ -324,6 +330,10 @@ func TestAddingPotentialAmnesiaEvidence(t *testing.T) {
evidenceTime = time.Date(2019, 1, 1, 0, 0, 0, 0, time.UTC)
)
blockStore.On("LoadBlockMeta", mock.AnythingOfType("int64")).Return(
&types.BlockMeta{Header: types.Header{Time: evidenceTime}},
)
// TEST SETUP
pool, err := NewPool(stateDB, evidenceDB, blockStore)
require.NoError(t, err)
@ -346,8 +356,9 @@ func TestAddingPotentialAmnesiaEvidence(t *testing.T) {
voteC.Signature = vC.Signature
require.NoError(t, err)
ev := &types.PotentialAmnesiaEvidence{
VoteA: voteA,
VoteB: voteB,
VoteA: voteA,
VoteB: voteB,
Timestamp: evidenceTime,
}
polc := &types.ProofOfLockChange{
@ -410,8 +421,9 @@ func TestAddingPotentialAmnesiaEvidence(t *testing.T) {
pool.logger.Info("CASE D")
// evidence of voting back in the past which is instantly punishable -> amnesia evidence is made directly
ev2 := &types.PotentialAmnesiaEvidence{
VoteA: voteC,
VoteB: voteB,
VoteA: voteC,
VoteB: voteB,
Timestamp: evidenceTime,
}
err = pool.AddEvidence(ev2)
assert.NoError(t, err)
@ -445,8 +457,9 @@ func TestAddingPotentialAmnesiaEvidence(t *testing.T) {
// a new amnesia evidence is seen. It has an empty polc so we should extract the potential amnesia evidence
// and start our own trial
newPe := &types.PotentialAmnesiaEvidence{
VoteA: voteB,
VoteB: voteD,
VoteA: voteB,
VoteB: voteD,
Timestamp: evidenceTime,
}
newAe := &types.AmnesiaEvidence{
PotentialAmnesiaEvidence: newPe,


+ 9
- 4
evidence/reactor_test.go View File

@ -8,14 +8,15 @@ import (
"github.com/go-kit/kit/log/term"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require"
dbm "github.com/tendermint/tm-db"
cfg "github.com/tendermint/tendermint/config"
"github.com/tendermint/tendermint/evidence/mocks"
"github.com/tendermint/tendermint/libs/log"
"github.com/tendermint/tendermint/p2p"
sm "github.com/tendermint/tendermint/state"
"github.com/tendermint/tendermint/types"
)
@ -38,11 +39,14 @@ func makeAndConnectReactors(config *cfg.Config, stateDBs []dbm.DB) []*Reactor {
reactors := make([]*Reactor, N)
logger := evidenceLogger()
evidenceTime := time.Date(2019, 1, 1, 0, 0, 0, 0, time.UTC)
for i := 0; i < N; i++ {
evidenceDB := dbm.NewMemDB()
blockStoreDB := dbm.NewMemDB()
blockStore := initializeBlockStore(blockStoreDB, sm.LoadState(stateDBs[i]), []byte("myval"))
blockStore := &mocks.BlockStore{}
blockStore.On("LoadBlockMeta", mock.AnythingOfType("int64")).Return(
&types.BlockMeta{Header: types.Header{Time: evidenceTime}},
)
pool, err := NewPool(stateDBs[i], evidenceDB, blockStore)
if err != nil {
panic(err)
@ -115,7 +119,8 @@ func _waitForEvidence(
func sendEvidence(t *testing.T, evpool *Pool, val types.PrivValidator, n int) types.EvidenceList {
evList := make([]types.Evidence, n)
for i := 0; i < n; i++ {
ev := types.NewMockDuplicateVoteEvidenceWithValidator(int64(i+1), time.Now().UTC(), val, evidenceChainID)
ev := types.NewMockDuplicateVoteEvidenceWithValidator(int64(i+1),
time.Date(2019, 1, 1, 0, 0, 0, 0, time.UTC), val, evidenceChainID)
err := evpool.AddEvidence(ev)
require.NoError(t, err)
evList[i] = ev


+ 11
- 0
evidence/services.go View File

@ -0,0 +1,11 @@
package evidence
import (
"github.com/tendermint/tendermint/types"
)
//go:generate mockery --case underscore --name BlockStore
type BlockStore interface {
LoadBlockMeta(height int64) *types.BlockMeta
}

+ 0
- 1
node/node.go View File

@ -345,7 +345,6 @@ func createEvidenceReactor(config *cfg.Config, dbProvider DBProvider,
if err != nil {
return nil, nil, err
}
evidencePool.SetLogger(evidenceLogger)
evidenceReactor := evidence.NewReactor(evidencePool)
evidenceReactor.SetLogger(evidenceLogger)
return evidenceReactor, evidencePool, nil


+ 211
- 50
proto/tendermint/types/evidence.pb.go View File

@ -7,16 +7,20 @@ import (
fmt "fmt"
_ "github.com/gogo/protobuf/gogoproto"
proto "github.com/gogo/protobuf/proto"
_ "github.com/gogo/protobuf/types"
github_com_gogo_protobuf_types "github.com/gogo/protobuf/types"
crypto "github.com/tendermint/tendermint/proto/tendermint/crypto"
io "io"
math "math"
math_bits "math/bits"
time "time"
)
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
var _ = time.Kitchen
// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
@ -27,8 +31,9 @@ const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package
// DuplicateVoteEvidence contains evidence a validator signed two conflicting
// votes.
type DuplicateVoteEvidence struct {
VoteA *Vote `protobuf:"bytes,1,opt,name=vote_a,json=voteA,proto3" json:"vote_a,omitempty"`
VoteB *Vote `protobuf:"bytes,2,opt,name=vote_b,json=voteB,proto3" json:"vote_b,omitempty"`
VoteA *Vote `protobuf:"bytes,1,opt,name=vote_a,json=voteA,proto3" json:"vote_a,omitempty"`
VoteB *Vote `protobuf:"bytes,2,opt,name=vote_b,json=voteB,proto3" json:"vote_b,omitempty"`
Timestamp time.Time `protobuf:"bytes,3,opt,name=timestamp,proto3,stdtime" json:"timestamp"`
}
func (m *DuplicateVoteEvidence) Reset() { *m = DuplicateVoteEvidence{} }
@ -78,10 +83,18 @@ func (m *DuplicateVoteEvidence) GetVoteB() *Vote {
return nil
}
func (m *DuplicateVoteEvidence) GetTimestamp() time.Time {
if m != nil {
return m.Timestamp
}
return time.Time{}
}
type PotentialAmnesiaEvidence struct {
VoteA *Vote `protobuf:"bytes,1,opt,name=vote_a,json=voteA,proto3" json:"vote_a,omitempty"`
VoteB *Vote `protobuf:"bytes,2,opt,name=vote_b,json=voteB,proto3" json:"vote_b,omitempty"`
HeightStamp int64 `protobuf:"varint,3,opt,name=height_stamp,json=heightStamp,proto3" json:"height_stamp,omitempty"`
VoteA *Vote `protobuf:"bytes,1,opt,name=vote_a,json=voteA,proto3" json:"vote_a,omitempty"`
VoteB *Vote `protobuf:"bytes,2,opt,name=vote_b,json=voteB,proto3" json:"vote_b,omitempty"`
HeightStamp int64 `protobuf:"varint,3,opt,name=height_stamp,json=heightStamp,proto3" json:"height_stamp,omitempty"`
Timestamp time.Time `protobuf:"bytes,4,opt,name=timestamp,proto3,stdtime" json:"timestamp"`
}
func (m *PotentialAmnesiaEvidence) Reset() { *m = PotentialAmnesiaEvidence{} }
@ -138,6 +151,13 @@ func (m *PotentialAmnesiaEvidence) GetHeightStamp() int64 {
return 0
}
func (m *PotentialAmnesiaEvidence) GetTimestamp() time.Time {
if m != nil {
return m.Timestamp
}
return time.Time{}
}
type AmnesiaEvidence struct {
PotentialAmnesiaEvidence *PotentialAmnesiaEvidence `protobuf:"bytes,1,opt,name=potential_amnesia_evidence,json=potentialAmnesiaEvidence,proto3" json:"potential_amnesia_evidence,omitempty"`
Polc *ProofOfLockChange `protobuf:"bytes,2,opt,name=polc,proto3" json:"polc,omitempty"`
@ -243,9 +263,10 @@ func (m *ConflictingHeadersEvidence) GetH2() *SignedHeader {
}
type LunaticValidatorEvidence struct {
Header *Header `protobuf:"bytes,1,opt,name=header,proto3" json:"header,omitempty"`
Vote *Vote `protobuf:"bytes,2,opt,name=vote,proto3" json:"vote,omitempty"`
InvalidHeaderField string `protobuf:"bytes,3,opt,name=invalid_header_field,json=invalidHeaderField,proto3" json:"invalid_header_field,omitempty"`
Header *Header `protobuf:"bytes,1,opt,name=header,proto3" json:"header,omitempty"`
Vote *Vote `protobuf:"bytes,2,opt,name=vote,proto3" json:"vote,omitempty"`
InvalidHeaderField string `protobuf:"bytes,3,opt,name=invalid_header_field,json=invalidHeaderField,proto3" json:"invalid_header_field,omitempty"`
Timestamp time.Time `protobuf:"bytes,4,opt,name=timestamp,proto3,stdtime" json:"timestamp"`
}
func (m *LunaticValidatorEvidence) Reset() { *m = LunaticValidatorEvidence{} }
@ -302,6 +323,13 @@ func (m *LunaticValidatorEvidence) GetInvalidHeaderField() string {
return ""
}
func (m *LunaticValidatorEvidence) GetTimestamp() time.Time {
if m != nil {
return m.Timestamp
}
return time.Time{}
}
type Evidence struct {
// Types that are valid to be assigned to Sum:
// *Evidence_DuplicateVoteEvidence
@ -545,48 +573,52 @@ func init() {
func init() { proto.RegisterFile("tendermint/types/evidence.proto", fileDescriptor_6825fabc78e0a168) }
var fileDescriptor_6825fabc78e0a168 = []byte{
// 656 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x55, 0x4f, 0x4f, 0xd4, 0x40,
0x1c, 0x6d, 0xd9, 0x65, 0xc5, 0x1f, 0x24, 0x60, 0x03, 0xda, 0x34, 0xa4, 0x40, 0x3d, 0x48, 0x08,
0x76, 0x61, 0x8d, 0xe1, 0xe2, 0x85, 0x3f, 0x9a, 0x4d, 0x20, 0x8a, 0x43, 0xc2, 0xc1, 0x4b, 0x9d,
0x6d, 0x67, 0xdb, 0x81, 0x6e, 0xa7, 0xd9, 0x4e, 0x37, 0x6e, 0xe2, 0x67, 0x30, 0xde, 0xfd, 0x06,
0x9e, 0xfd, 0x10, 0x1c, 0x39, 0x7a, 0x32, 0x06, 0xbe, 0x88, 0xe9, 0x74, 0x76, 0x17, 0xb7, 0x5b,
0x36, 0x5e, 0xbc, 0x34, 0xcd, 0xef, 0xf7, 0xe6, 0xbd, 0x37, 0x79, 0xf3, 0x9b, 0x81, 0x35, 0x4e,
0x22, 0x8f, 0x74, 0x3b, 0x34, 0xe2, 0x75, 0xde, 0x8f, 0x49, 0x52, 0x27, 0x3d, 0xea, 0x91, 0xc8,
0x25, 0x76, 0xdc, 0x65, 0x9c, 0x69, 0x4b, 0x23, 0x80, 0x2d, 0x00, 0xc6, 0xb2, 0xcf, 0x7c, 0x26,
0x9a, 0xf5, 0xec, 0x2f, 0xc7, 0x19, 0xab, 0x05, 0x22, 0xf1, 0x9d, 0xd0, 0x75, 0xbb, 0xfd, 0x98,
0xb3, 0xfa, 0x25, 0xe9, 0xcb, 0xae, 0x95, 0xc2, 0xca, 0x51, 0x1a, 0x87, 0xd4, 0xc5, 0x9c, 0x9c,
0x33, 0x4e, 0x5e, 0x4b, 0x0b, 0xda, 0x73, 0xa8, 0xf5, 0x18, 0x27, 0x0e, 0xd6, 0xd5, 0x75, 0x75,
0x73, 0xbe, 0xf1, 0xd8, 0x1e, 0x77, 0x63, 0x67, 0x78, 0x34, 0x9b, 0xa1, 0xf6, 0x87, 0xf0, 0x96,
0x3e, 0x33, 0x1d, 0x7e, 0x60, 0x7d, 0x53, 0x41, 0x3f, 0x65, 0x9c, 0x44, 0x9c, 0xe2, 0x70, 0xbf,
0x13, 0x91, 0x84, 0xe2, 0xff, 0x23, 0xad, 0x6d, 0xc0, 0x42, 0x40, 0xa8, 0x1f, 0x70, 0x27, 0xe1,
0xb8, 0x13, 0xeb, 0x95, 0x75, 0x75, 0xb3, 0x82, 0xe6, 0xf3, 0xda, 0x59, 0x56, 0xb2, 0x7e, 0xa8,
0xb0, 0x38, 0x6e, 0x2a, 0x00, 0x23, 0x1e, 0x18, 0x76, 0x70, 0xde, 0x74, 0x06, 0x81, 0x49, 0xa3,
0x5b, 0x45, 0xe5, 0xb2, 0x4d, 0x22, 0x3d, 0x2e, 0xdb, 0xfe, 0x1e, 0x54, 0x63, 0x16, 0xba, 0x72,
0x37, 0x4f, 0x27, 0x70, 0x76, 0x19, 0x6b, 0xbf, 0x6b, 0x9f, 0x30, 0xf7, 0xf2, 0x30, 0xc0, 0x91,
0x4f, 0x90, 0x58, 0x60, 0x7d, 0x06, 0xe3, 0x90, 0x45, 0xed, 0x90, 0xba, 0x9c, 0x46, 0x7e, 0x93,
0x60, 0x8f, 0x74, 0x93, 0x21, 0xad, 0x0d, 0x33, 0xc1, 0xae, 0x34, 0x6a, 0x16, 0x49, 0xcf, 0xa8,
0x1f, 0x11, 0x2f, 0x5f, 0x84, 0x66, 0x82, 0x5d, 0x81, 0x6f, 0x48, 0x13, 0xd3, 0xf1, 0x0d, 0xeb,
0xbb, 0x0a, 0xfa, 0x49, 0x1a, 0x61, 0x4e, 0xdd, 0x73, 0x1c, 0x52, 0x0f, 0x73, 0xd6, 0x1d, 0x8a,
0xef, 0x40, 0x2d, 0x10, 0x50, 0x69, 0x40, 0x2f, 0x12, 0x4a, 0x2a, 0x89, 0xd3, 0xb6, 0xa0, 0x9a,
0xe5, 0x35, 0x25, 0x53, 0x81, 0xd1, 0x76, 0x60, 0x99, 0x46, 0xbd, 0x4c, 0xd4, 0xc9, 0x57, 0x3b,
0x6d, 0x4a, 0x42, 0x4f, 0x44, 0xfb, 0x10, 0x69, 0xb2, 0x97, 0x0b, 0xbc, 0xc9, 0x3a, 0xd6, 0x97,
0x2a, 0xcc, 0x0d, 0xcd, 0x61, 0x78, 0xe2, 0x0d, 0x66, 0xc0, 0x11, 0x47, 0x69, 0x2c, 0xd7, 0x67,
0x45, 0xf5, 0x89, 0x43, 0xd3, 0x54, 0xd0, 0x8a, 0x37, 0x71, 0x9a, 0x62, 0x58, 0x75, 0x47, 0xd1,
0x48, 0x97, 0xc9, 0x48, 0x27, 0xdf, 0xe5, 0x76, 0x51, 0xa7, 0x3c, 0xd0, 0xa6, 0x82, 0x0c, 0xb7,
0x3c, 0xee, 0x0b, 0x30, 0xc2, 0x3c, 0x0d, 0xa7, 0x37, 0x88, 0x63, 0xa4, 0x57, 0x29, 0x3b, 0xaf,
0x65, 0x09, 0x36, 0x15, 0xa4, 0x87, 0x65, 0xe9, 0x5e, 0xdc, 0x3b, 0x1b, 0xd5, 0x7f, 0x9d, 0x8d,
0x4c, 0xab, 0x74, 0x3a, 0xde, 0xc2, 0x52, 0x41, 0x61, 0x56, 0x28, 0x6c, 0x14, 0x15, 0x8a, 0xc4,
0x8b, 0xf8, 0xef, 0xd2, 0xc1, 0x2c, 0x54, 0x92, 0xb4, 0x63, 0x7d, 0x84, 0x85, 0x41, 0xe9, 0x08,
0x73, 0xac, 0xbd, 0x82, 0xb9, 0x3b, 0x87, 0xa0, 0xb2, 0x39, 0xdf, 0x30, 0x8a, 0xf4, 0x43, 0x92,
0xea, 0xd5, 0xaf, 0x35, 0x05, 0x0d, 0x57, 0x68, 0x1a, 0x54, 0x03, 0x9c, 0x04, 0x22, 0xd6, 0x05,
0x24, 0xfe, 0xad, 0x4f, 0xf0, 0xa8, 0x30, 0xb8, 0xda, 0x36, 0x88, 0x5b, 0x29, 0x91, 0x1a, 0xf7,
0x5e, 0x5d, 0x89, 0xf6, 0x12, 0x1e, 0xc4, 0x69, 0xcb, 0xb9, 0x24, 0x7d, 0x79, 0x60, 0x56, 0xef,
0xe2, 0xf3, 0xcb, 0xdd, 0x3e, 0x4d, 0x5b, 0x21, 0x75, 0x8f, 0x49, 0x1f, 0xd5, 0xe2, 0xb4, 0x75,
0x4c, 0xfa, 0x07, 0xef, 0xaf, 0x6e, 0x4c, 0xf5, 0xfa, 0xc6, 0x54, 0x7f, 0xdf, 0x98, 0xea, 0xd7,
0x5b, 0x53, 0xb9, 0xbe, 0x35, 0x95, 0x9f, 0xb7, 0xa6, 0xf2, 0x61, 0xcf, 0xa7, 0x3c, 0x48, 0x5b,
0xb6, 0xcb, 0x3a, 0xf5, 0xbb, 0x8f, 0xc8, 0xe8, 0x37, 0x7f, 0x6c, 0xc6, 0x1f, 0x98, 0x56, 0x4d,
0xd4, 0x5f, 0xfc, 0x09, 0x00, 0x00, 0xff, 0xff, 0xb8, 0xe6, 0x16, 0x08, 0xc4, 0x06, 0x00, 0x00,
// 710 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x55, 0xc1, 0x4e, 0xdb, 0x4a,
0x14, 0xb5, 0x89, 0xc9, 0x83, 0x01, 0x09, 0x9e, 0x05, 0xef, 0x59, 0x16, 0x72, 0x4a, 0xba, 0x68,
0x85, 0xa8, 0x0d, 0x54, 0x15, 0x9b, 0x6e, 0x08, 0xb4, 0x8a, 0x04, 0x6a, 0xa9, 0xa9, 0x58, 0x74,
0xe3, 0x8e, 0xed, 0x89, 0x3d, 0xe0, 0x78, 0xac, 0x78, 0x1c, 0x35, 0x52, 0xbf, 0xa1, 0xe2, 0x63,
0xba, 0xe9, 0x1f, 0xb0, 0x64, 0xd9, 0x55, 0xa9, 0x60, 0xdf, 0x6f, 0xa8, 0x3c, 0x1e, 0xdb, 0x10,
0xc7, 0xa0, 0x56, 0x55, 0x37, 0x91, 0x33, 0xf7, 0xdc, 0x7b, 0xee, 0x99, 0x39, 0x77, 0x06, 0xb4,
0x28, 0x0a, 0x5d, 0x34, 0xe8, 0xe3, 0x90, 0x1a, 0x74, 0x14, 0xa1, 0xd8, 0x40, 0x43, 0xec, 0xa2,
0xd0, 0x41, 0x7a, 0x34, 0x20, 0x94, 0xc8, 0x8b, 0x25, 0x40, 0x67, 0x00, 0x75, 0xc9, 0x23, 0x1e,
0x61, 0x41, 0x23, 0xfd, 0xca, 0x70, 0x6a, 0xcb, 0x23, 0xc4, 0x0b, 0x90, 0xc1, 0xfe, 0xd9, 0x49,
0xcf, 0xa0, 0xb8, 0x8f, 0x62, 0x0a, 0xfb, 0x11, 0x07, 0xac, 0x54, 0x98, 0xd8, 0xef, 0x84, 0xa8,
0x33, 0x18, 0x45, 0x94, 0x18, 0xa7, 0x68, 0xc4, 0xa3, 0xed, 0x2f, 0x22, 0x58, 0xde, 0x4b, 0xa2,
0x00, 0x3b, 0x90, 0xa2, 0x63, 0x42, 0xd1, 0x0b, 0xde, 0xa4, 0xfc, 0x04, 0x34, 0x87, 0x84, 0x22,
0x0b, 0x2a, 0xe2, 0x03, 0xf1, 0xf1, 0xdc, 0xd6, 0x7f, 0xfa, 0x78, 0xbf, 0x7a, 0x8a, 0x37, 0xa7,
0x53, 0xd4, 0x4e, 0x01, 0xb7, 0x95, 0xa9, 0xfb, 0xe1, 0x1d, 0xb9, 0x03, 0x66, 0x0b, 0x19, 0x4a,
0x83, 0x65, 0xa8, 0x7a, 0x26, 0x54, 0xcf, 0x85, 0xea, 0x6f, 0x73, 0x44, 0x67, 0xe6, 0xfc, 0x5b,
0x4b, 0x38, 0xbb, 0x6c, 0x89, 0x66, 0x99, 0xd6, 0xbe, 0x14, 0x81, 0x72, 0x48, 0x28, 0x0a, 0x29,
0x86, 0xc1, 0x4e, 0x3f, 0x44, 0x31, 0x86, 0x7f, 0xa9, 0xfd, 0x55, 0x30, 0xef, 0x23, 0xec, 0xf9,
0xd4, 0x2a, 0x15, 0x34, 0xcc, 0xb9, 0x6c, 0xed, 0x28, 0x5d, 0xba, 0xad, 0x50, 0xfa, 0x3d, 0x85,
0x9f, 0x45, 0xb0, 0x30, 0x2e, 0xcc, 0x07, 0x6a, 0x94, 0x8b, 0xb6, 0x60, 0x16, 0xb4, 0x72, 0x6b,
0x71, 0xb1, 0x6b, 0xd5, 0xee, 0xeb, 0x36, 0xca, 0x54, 0xa2, 0xba, 0x2d, 0xdc, 0x06, 0x52, 0x44,
0x02, 0x87, 0xef, 0xc8, 0xc3, 0x09, 0x35, 0x07, 0x84, 0xf4, 0x5e, 0xf7, 0x0e, 0x88, 0x73, 0xba,
0xeb, 0xc3, 0xd0, 0x43, 0x26, 0x4b, 0x68, 0x7f, 0x04, 0xea, 0x2e, 0x09, 0x7b, 0x01, 0x76, 0x28,
0x0e, 0xbd, 0x2e, 0x82, 0x2e, 0x1a, 0xc4, 0x45, 0x59, 0x1d, 0x4c, 0xf9, 0x9b, 0xbc, 0x51, 0xad,
0x5a, 0xf4, 0x08, 0x7b, 0x21, 0x72, 0xb3, 0x24, 0x73, 0xca, 0xdf, 0x64, 0xf8, 0x2d, 0xde, 0xc4,
0xfd, 0xf8, 0xad, 0xf6, 0x0f, 0x11, 0x28, 0x07, 0x49, 0x08, 0x29, 0x76, 0x8e, 0x61, 0x80, 0x5d,
0x48, 0xc9, 0xa0, 0x20, 0xdf, 0x00, 0x4d, 0x9f, 0x41, 0x79, 0x03, 0x4a, 0xb5, 0x20, 0x2f, 0xc5,
0x71, 0xf2, 0x1a, 0x90, 0xd2, 0x33, 0xbf, 0xc7, 0x17, 0x0c, 0x23, 0x6f, 0x80, 0x25, 0x1c, 0x0e,
0x53, 0x52, 0x2b, 0xcb, 0xb6, 0x7a, 0x18, 0x05, 0x2e, 0xb3, 0xc7, 0xac, 0x29, 0xf3, 0x58, 0x46,
0xf0, 0x32, 0x8d, 0xfc, 0x11, 0x97, 0x7c, 0x92, 0xc0, 0x4c, 0x21, 0x10, 0x82, 0xff, 0xdd, 0x7c,
0x9e, 0x2d, 0x66, 0xe9, 0x31, 0x6f, 0x3c, 0xaa, 0x2a, 0x98, 0x78, 0x01, 0x74, 0x05, 0x73, 0xd9,
0x9d, 0x78, 0x33, 0x44, 0x60, 0xc5, 0x29, 0x8f, 0x97, 0x2b, 0x8d, 0x4b, 0x9e, 0x6c, 0xa7, 0xd6,
0xab, 0x3c, 0xf5, 0xa6, 0xe8, 0x0a, 0xa6, 0xea, 0xd4, 0x5b, 0xe6, 0x04, 0xa8, 0x41, 0x76, 0xa2,
0xd6, 0x30, 0x3f, 0xd2, 0x92, 0xaf, 0x51, 0xe7, 0xf9, 0x3a, 0x17, 0x74, 0x05, 0x53, 0x09, 0xea,
0x1c, 0x72, 0x72, 0xe7, 0x7c, 0x49, 0xbf, 0x3a, 0x5f, 0x29, 0x57, 0xed, 0x84, 0xbd, 0x02, 0x8b,
0x15, 0x86, 0x69, 0xc6, 0xb0, 0x5a, 0x65, 0xa8, 0x16, 0x5e, 0x80, 0xb7, 0x97, 0x3a, 0xd3, 0xa0,
0x11, 0x27, 0xfd, 0xf6, 0x7b, 0x30, 0x9f, 0x2f, 0xed, 0x41, 0x0a, 0xe5, 0xe7, 0x60, 0xe6, 0x86,
0x09, 0x1a, 0xcc, 0x63, 0x95, 0xf2, 0x45, 0x11, 0x29, 0xf5, 0x98, 0x59, 0x64, 0xc8, 0x32, 0x90,
0x7c, 0x18, 0xfb, 0xec, 0x58, 0xe7, 0x4d, 0xf6, 0xdd, 0xfe, 0x00, 0xfe, 0xad, 0x0c, 0xbf, 0xbc,
0x0e, 0xd8, 0xed, 0x18, 0x73, 0x8e, 0x3b, 0xaf, 0xd0, 0x58, 0x7e, 0x06, 0xfe, 0x89, 0x12, 0xdb,
0x3a, 0x45, 0x23, 0x6e, 0x98, 0x95, 0x9b, 0xf8, 0xec, 0xa5, 0xd2, 0x0f, 0x13, 0x3b, 0xc0, 0xce,
0x3e, 0x1a, 0x99, 0xcd, 0x28, 0xb1, 0xf7, 0xd1, 0xa8, 0xf3, 0xe6, 0xfc, 0x4a, 0x13, 0x2f, 0xae,
0x34, 0xf1, 0xfb, 0x95, 0x26, 0x9e, 0x5d, 0x6b, 0xc2, 0xc5, 0xb5, 0x26, 0x7c, 0xbd, 0xd6, 0x84,
0x77, 0xdb, 0x1e, 0xa6, 0x7e, 0x62, 0xeb, 0x0e, 0xe9, 0x1b, 0x37, 0x5f, 0xc4, 0xf2, 0x33, 0x7b,
0x5a, 0xc7, 0x5f, 0x4b, 0xbb, 0xc9, 0xd6, 0x9f, 0xfe, 0x0c, 0x00, 0x00, 0xff, 0xff, 0x84, 0x99,
0x61, 0x70, 0xb2, 0x07, 0x00, 0x00,
}
func (m *DuplicateVoteEvidence) Marshal() (dAtA []byte, err error) {
@ -609,6 +641,14 @@ func (m *DuplicateVoteEvidence) MarshalToSizedBuffer(dAtA []byte) (int, error) {
_ = i
var l int
_ = l
n1, err1 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.Timestamp, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.Timestamp):])
if err1 != nil {
return 0, err1
}
i -= n1
i = encodeVarintEvidence(dAtA, i, uint64(n1))
i--
dAtA[i] = 0x1a
if m.VoteB != nil {
{
size, err := m.VoteB.MarshalToSizedBuffer(dAtA[:i])
@ -656,6 +696,14 @@ func (m *PotentialAmnesiaEvidence) MarshalToSizedBuffer(dAtA []byte) (int, error
_ = i
var l int
_ = l
n4, err4 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.Timestamp, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.Timestamp):])
if err4 != nil {
return 0, err4
}
i -= n4
i = encodeVarintEvidence(dAtA, i, uint64(n4))
i--
dAtA[i] = 0x22
if m.HeightStamp != 0 {
i = encodeVarintEvidence(dAtA, i, uint64(m.HeightStamp))
i--
@ -802,6 +850,14 @@ func (m *LunaticValidatorEvidence) MarshalToSizedBuffer(dAtA []byte) (int, error
_ = i
var l int
_ = l
n11, err11 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.Timestamp, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.Timestamp):])
if err11 != nil {
return 0, err11
}
i -= n11
i = encodeVarintEvidence(dAtA, i, uint64(n11))
i--
dAtA[i] = 0x22
if len(m.InvalidHeaderField) > 0 {
i -= len(m.InvalidHeaderField)
copy(dAtA[i:], m.InvalidHeaderField)
@ -1091,6 +1147,8 @@ func (m *DuplicateVoteEvidence) Size() (n int) {
l = m.VoteB.Size()
n += 1 + l + sovEvidence(uint64(l))
}
l = github_com_gogo_protobuf_types.SizeOfStdTime(m.Timestamp)
n += 1 + l + sovEvidence(uint64(l))
return n
}
@ -1111,6 +1169,8 @@ func (m *PotentialAmnesiaEvidence) Size() (n int) {
if m.HeightStamp != 0 {
n += 1 + sovEvidence(uint64(m.HeightStamp))
}
l = github_com_gogo_protobuf_types.SizeOfStdTime(m.Timestamp)
n += 1 + l + sovEvidence(uint64(l))
return n
}
@ -1166,6 +1226,8 @@ func (m *LunaticValidatorEvidence) Size() (n int) {
if l > 0 {
n += 1 + l + sovEvidence(uint64(l))
}
l = github_com_gogo_protobuf_types.SizeOfStdTime(m.Timestamp)
n += 1 + l + sovEvidence(uint64(l))
return n
}
@ -1386,6 +1448,39 @@ func (m *DuplicateVoteEvidence) Unmarshal(dAtA []byte) error {
return err
}
iNdEx = postIndex
case 3:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Timestamp", wireType)
}
var msglen int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowEvidence
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
msglen |= int(b&0x7F) << shift
if b < 0x80 {
break
}
}
if msglen < 0 {
return ErrInvalidLengthEvidence
}
postIndex := iNdEx + msglen
if postIndex < 0 {
return ErrInvalidLengthEvidence
}
if postIndex > l {
return io.ErrUnexpectedEOF
}
if err := github_com_gogo_protobuf_types.StdTimeUnmarshal(&m.Timestamp, dAtA[iNdEx:postIndex]); err != nil {
return err
}
iNdEx = postIndex
default:
iNdEx = preIndex
skippy, err := skipEvidence(dAtA[iNdEx:])
@ -1530,6 +1625,39 @@ func (m *PotentialAmnesiaEvidence) Unmarshal(dAtA []byte) error {
break
}
}
case 4:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Timestamp", wireType)
}
var msglen int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowEvidence
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
msglen |= int(b&0x7F) << shift
if b < 0x80 {
break
}
}
if msglen < 0 {
return ErrInvalidLengthEvidence
}
postIndex := iNdEx + msglen
if postIndex < 0 {
return ErrInvalidLengthEvidence
}
if postIndex > l {
return io.ErrUnexpectedEOF
}
if err := github_com_gogo_protobuf_types.StdTimeUnmarshal(&m.Timestamp, dAtA[iNdEx:postIndex]); err != nil {
return err
}
iNdEx = postIndex
default:
iNdEx = preIndex
skippy, err := skipEvidence(dAtA[iNdEx:])
@ -1937,6 +2065,39 @@ func (m *LunaticValidatorEvidence) Unmarshal(dAtA []byte) error {
}
m.InvalidHeaderField = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
case 4:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Timestamp", wireType)
}
var msglen int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowEvidence
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
msglen |= int(b&0x7F) << shift
if b < 0x80 {
break
}
}
if msglen < 0 {
return ErrInvalidLengthEvidence
}
postIndex := iNdEx + msglen
if postIndex < 0 {
return ErrInvalidLengthEvidence
}
if postIndex > l {
return io.ErrUnexpectedEOF
}
if err := github_com_gogo_protobuf_types.StdTimeUnmarshal(&m.Timestamp, dAtA[iNdEx:postIndex]); err != nil {
return err
}
iNdEx = postIndex
default:
iNdEx = preIndex
skippy, err := skipEvidence(dAtA[iNdEx:])


+ 9
- 0
proto/tendermint/types/evidence.proto View File

@ -4,6 +4,7 @@ package tendermint.types;
option go_package = "github.com/tendermint/tendermint/proto/tendermint/types";
import "gogoproto/gogo.proto";
import "google/protobuf/timestamp.proto";
import "tendermint/types/types.proto";
import "tendermint/crypto/keys.proto";
@ -12,6 +13,9 @@ import "tendermint/crypto/keys.proto";
message DuplicateVoteEvidence {
Vote vote_a = 1;
Vote vote_b = 2;
google.protobuf.Timestamp timestamp = 3
[(gogoproto.nullable) = false, (gogoproto.stdtime) = true];
}
message PotentialAmnesiaEvidence {
@ -19,6 +23,8 @@ message PotentialAmnesiaEvidence {
Vote vote_b = 2;
int64 height_stamp = 3;
google.protobuf.Timestamp timestamp = 4
[(gogoproto.nullable) = false, (gogoproto.stdtime) = true];
}
message AmnesiaEvidence {
@ -35,6 +41,9 @@ message LunaticValidatorEvidence {
Header header = 1;
Vote vote = 2;
string invalid_header_field = 3;
google.protobuf.Timestamp timestamp = 4
[(gogoproto.nullable) = false, (gogoproto.stdtime) = true];
}
message Evidence {


+ 10
- 2
rpc/client/evidence_test.go View File

@ -20,6 +20,12 @@ import (
"github.com/tendermint/tendermint/types"
)
// For some reason the empty node used in tests has a time of
// 2018-10-10 08:20:13.695936996 +0000 UTC
// this is because the test genesis time is set here
// so in order to validate evidence we need evidence to be the same time
var defaultTestTime = time.Date(2018, 10, 10, 8, 20, 13, 695936996, time.UTC)
func newEvidence(t *testing.T, val *privval.FilePV,
vote *types.Vote, vote2 *types.Vote,
chainID string) *types.DuplicateVoteEvidence {
@ -35,7 +41,7 @@ func newEvidence(t *testing.T, val *privval.FilePV,
vote2.Signature, err = val.Key.PrivKey.Sign(types.VoteSignBytes(chainID, v2))
require.NoError(t, err)
return types.NewDuplicateVoteEvidence(vote, vote2)
return types.NewDuplicateVoteEvidence(vote, vote2, defaultTestTime)
}
func makeEvidences(
@ -49,7 +55,7 @@ func makeEvidences(
Height: 1,
Round: 0,
Type: tmproto.PrevoteType,
Timestamp: time.Now().UTC(),
Timestamp: defaultTestTime,
BlockID: types.BlockID{
Hash: tmhash.Sum([]byte("blockhash")),
PartSetHeader: types.PartSetHeader{
@ -121,6 +127,8 @@ func TestBroadcastEvidence_DuplicateVoteEvidence(t *testing.T) {
for i, c := range GetClients() {
t.Logf("client %d", i)
t.Log(correct.Time())
result, err := c.BroadcastEvidence(correct)
require.NoError(t, err, "BroadcastEvidence(%s) failed", correct)
assert.Equal(t, correct.Hash(), result.Hash, "expected result hash to match evidence hash")


+ 28
- 21
state/validation.go View File

@ -94,6 +94,21 @@ func validateBlock(evidencePool EvidencePool, stateDB dbm.DB, state State, block
}
}
// NOTE: We can't actually verify it's the right proposer because we dont
// know what round the block was first proposed. So just check that it's
// a legit address and a known validator.
if len(block.ProposerAddress) != crypto.AddressSize {
return fmt.Errorf("expected ProposerAddress size %d, got %d",
crypto.AddressSize,
len(block.ProposerAddress),
)
}
if !state.Validators.HasAddress(block.ProposerAddress) {
return fmt.Errorf("block.Header.ProposerAddress %X is not a validator",
block.ProposerAddress,
)
}
// Validate block Time
if block.Height > 1 {
if !block.Time.After(state.LastBlockTime) {
@ -154,12 +169,12 @@ func validateBlock(evidencePool EvidencePool, stateDB dbm.DB, state State, block
return types.NewErrEvidenceInvalid(ev, errors.New("amnesia evidence is new and hasn't undergone trial period yet"))
}
var header *types.Header
if _, ok := ev.(*types.LunaticValidatorEvidence); ok {
header = evidencePool.Header(ev.Height())
if header == nil {
return fmt.Errorf("don't have block meta at height #%d", ev.Height())
}
// A header needs to be fetched. For lunatic evidence this is so we can verify
// that some of the fields are different to the ones we have. For all evidence it
// it so we can verify that the time of the evidence is correct
header := evidencePool.Header(ev.Height())
if header == nil {
return fmt.Errorf("don't have block meta at height #%d", ev.Height())
}
if err := VerifyEvidence(stateDB, state, ev, header); err != nil {
@ -168,21 +183,6 @@ func validateBlock(evidencePool EvidencePool, stateDB dbm.DB, state State, block
}
// NOTE: We can't actually verify it's the right proposer because we dont
// know what round the block was first proposed. So just check that it's
// a legit address and a known validator.
if len(block.ProposerAddress) != crypto.AddressSize {
return fmt.Errorf("expected ProposerAddress size %d, got %d",
crypto.AddressSize,
len(block.ProposerAddress),
)
}
if !state.Validators.HasAddress(block.ProposerAddress) {
return fmt.Errorf("block.Header.ProposerAddress %X is not a validator",
block.ProposerAddress,
)
}
return nil
}
@ -200,6 +200,13 @@ func VerifyEvidence(stateDB dbm.DB, state State, evidence types.Evidence, commit
ageNumBlocks = height - evidence.Height()
)
if committedHeader.Time != evidence.Time() {
return fmt.Errorf("evidence time (%v) is different to the time of the header we have for the same height (%v)",
evidence.Time(),
committedHeader.Time,
)
}
if ageDuration > evidenceParams.MaxAgeDuration && ageNumBlocks > evidenceParams.MaxAgeNumBlocks {
return fmt.Errorf(
"evidence from height %d (created at: %v) is too old; min height is %d and evidence can not be older than %v",


+ 64
- 33
state/validation_test.go View File

@ -5,6 +5,7 @@ import (
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require"
"github.com/tendermint/tendermint/crypto"
@ -216,20 +217,32 @@ func TestValidateBlockEvidence(t *testing.T) {
defer proxyApp.Stop() //nolint:errcheck // ignore for tests
state, stateDB, privVals := makeState(4, 1)
defaultEvidenceTime := time.Date(2019, 1, 1, 0, 0, 0, 0, time.UTC)
evpool := &mocks.EvidencePool{}
evpool.On("IsPending", mock.AnythingOfType("*types.DuplicateVoteEvidence")).Return(false)
evpool.On("IsCommitted", mock.AnythingOfType("*types.DuplicateVoteEvidence")).Return(false)
evpool.On("Header", mock.AnythingOfType("int64")).Return(func(height int64) *types.Header {
return &types.Header{
Time: defaultEvidenceTime,
Height: height,
}
})
evpool.On("Update", mock.AnythingOfType("*types.Block"), mock.AnythingOfType("state.State")).Return()
state.ConsensusParams.Evidence.MaxNum = 3
blockExec := sm.NewBlockExecutor(
stateDB,
log.TestingLogger(),
proxyApp.Consensus(),
memmock.Mempool{},
sm.MockEvidencePool{},
evpool,
)
lastCommit := types.NewCommit(0, 0, types.BlockID{}, nil)
for height := int64(1); height < validationTestsStopHeight; height++ {
proposerAddr := state.Validators.GetProposer().Address
maxNumEvidence := state.ConsensusParams.Evidence.MaxNum
t.Log(maxNumEvidence)
if height > 1 {
/*
A block with too much evidence fails
@ -243,8 +256,10 @@ func TestValidateBlockEvidence(t *testing.T) {
}
block, _ := state.MakeBlock(height, makeTxs(height), lastCommit, evidence, proposerAddr)
err := blockExec.ValidateBlock(state, block)
_, ok := err.(*types.ErrEvidenceOverflow)
require.True(t, ok, "expected error to be of type ErrEvidenceOverflow at height %d", height)
if assert.Error(t, err) {
_, ok := err.(*types.ErrEvidenceOverflow)
require.True(t, ok, "expected error to be of type ErrEvidenceOverflow at height %d but got %v", height, err)
}
}
/*
@ -256,7 +271,7 @@ func TestValidateBlockEvidence(t *testing.T) {
for i := int32(0); uint32(i) < maxNumEvidence; i++ {
// make different evidence for each validator
_, val := state.Validators.GetByIndex(i)
evidence = append(evidence, types.NewMockDuplicateVoteEvidenceWithValidator(height, time.Now(),
evidence = append(evidence, types.NewMockDuplicateVoteEvidenceWithValidator(height, defaultEvidenceTime,
privVals[val.Address.String()], chainID))
}
@ -284,11 +299,14 @@ func TestValidateFailBlockOnCommittedEvidence(t *testing.T) {
ev2 := types.NewMockDuplicateVoteEvidenceWithValidator(height, defaultTestTime,
privVals[val2.Address.String()], chainID)
header := &types.Header{Time: defaultTestTime}
evpool := &mocks.EvidencePool{}
evpool.On("IsPending", ev).Return(false)
evpool.On("IsPending", ev2).Return(false)
evpool.On("IsCommitted", ev).Return(false)
evpool.On("IsCommitted", ev2).Return(true)
evpool.On("Header", height).Return(header)
blockExec := sm.NewBlockExecutor(
stateDB, log.TestingLogger(),
@ -314,12 +332,14 @@ func TestValidateAlreadyPendingEvidence(t *testing.T) {
privVals[val.Address.String()], chainID)
ev2 := types.NewMockDuplicateVoteEvidenceWithValidator(height, defaultTestTime,
privVals[val2.Address.String()], chainID)
header := &types.Header{Time: defaultTestTime}
evpool := &mocks.EvidencePool{}
evpool.On("IsPending", ev).Return(false)
evpool.On("IsPending", ev2).Return(true)
evpool.On("IsCommitted", ev).Return(false)
evpool.On("IsCommitted", ev2).Return(false)
evpool.On("Header", height).Return(header)
blockExec := sm.NewBlockExecutor(
stateDB, log.TestingLogger(),
@ -430,30 +450,30 @@ func TestValidatePrimedAmnesiaEvidence(t *testing.T) {
state, stateDB, vals := makeState(1, int(height))
addr, val := state.Validators.GetByIndex(0)
voteA := makeVote(height, 1, 0, addr, blockID)
voteA.Timestamp = time.Now().Add(1 * time.Minute)
voteA.Timestamp = defaultTestTime.Add(1 * time.Minute)
vA := voteA.ToProto()
err := vals[val.Address.String()].SignVote(chainID, vA)
require.NoError(t, err)
voteA.Signature = vA.Signature
voteB := makeVote(height, 2, 0, addr, differentBlockID)
voteB.Timestamp = defaultTestTime
vB := voteB.ToProto()
err = vals[val.Address.String()].SignVote(chainID, vB)
voteB.Signature = vB.Signature
require.NoError(t, err)
pe := &types.PotentialAmnesiaEvidence{
VoteA: voteB,
VoteB: voteA,
}
pe := types.NewPotentialAmnesiaEvidence(voteB, voteA, defaultTestTime)
ae := &types.AmnesiaEvidence{
PotentialAmnesiaEvidence: pe,
Polc: types.NewEmptyPOLC(),
}
header := &types.Header{Time: defaultTestTime}
evpool := &mocks.EvidencePool{}
evpool.On("IsPending", ae).Return(false)
evpool.On("IsCommitted", ae).Return(false)
evpool.On("AddEvidence", ae).Return(nil)
evpool.On("AddEvidence", pe).Return(nil)
evpool.On("Header", height).Return(header)
blockExec := sm.NewBlockExecutor(
stateDB, log.TestingLogger(),
@ -475,11 +495,19 @@ func TestVerifyEvidenceWrongAddress(t *testing.T) {
state, stateDB, _ := makeState(1, int(height))
ev := types.NewMockDuplicateVoteEvidence(height, defaultTestTime, chainID)
header := &types.Header{Time: defaultTestTime}
evpool := &mocks.EvidencePool{}
evpool.On("IsPending", ev).Return(false)
evpool.On("IsCommitted", ev).Return(false)
evpool.On("Header", height).Return(header)
blockExec := sm.NewBlockExecutor(
stateDB, log.TestingLogger(),
nil,
nil,
sm.MockEvidencePool{})
evpool,
)
// A block with a couple pieces of evidence passes.
block := makeBlock(state, height)
block.Evidence.Evidence = []types.Evidence{ev}
@ -496,13 +524,26 @@ func TestVerifyEvidenceExpiredEvidence(t *testing.T) {
state, stateDB, _ := makeState(1, int(height))
state.ConsensusParams.Evidence.MaxAgeNumBlocks = 1
ev := types.NewMockDuplicateVoteEvidence(1, defaultTestTime, chainID)
err := sm.VerifyEvidence(stateDB, state, ev, nil)
err := sm.VerifyEvidence(stateDB, state, ev, &types.Header{Time: defaultTestTime})
errMsg := "evidence from height 1 (created at: 2019-01-01 00:00:00 +0000 UTC) is too old"
if assert.Error(t, err) {
assert.Equal(t, err.Error()[:len(errMsg)], errMsg)
}
}
func TestVerifyEvidenceInvalidTime(t *testing.T) {
height := 4
state, stateDB, _ := makeState(1, height)
differentTime := time.Date(2019, 2, 1, 0, 0, 0, 0, time.UTC)
ev := types.NewMockDuplicateVoteEvidence(int64(height), differentTime, chainID)
err := sm.VerifyEvidence(stateDB, state, ev, &types.Header{Time: defaultTestTime})
errMsg := "evidence time (2019-02-01 00:00:00 +0000 UTC) is different to the time" +
" of the header we have for the same height (2019-01-01 00:00:00 +0000 UTC)"
if assert.Error(t, err) {
assert.Equal(t, errMsg, err.Error())
}
}
func TestVerifyEvidenceWithAmnesiaEvidence(t *testing.T) {
var height int64 = 1
state, stateDB, vals := makeState(4, int(height))
@ -518,6 +559,9 @@ func TestVerifyEvidenceWithAmnesiaEvidence(t *testing.T) {
err = vals[val.Address.String()].SignVote(chainID, vB)
voteB.Signature = vB.Signature
require.NoError(t, err)
pae := types.NewPotentialAmnesiaEvidence(voteA, voteB, defaultTestTime)
voteC := makeVote(height, 2, 1, addr2, blockID)
vC := voteC.ToProto()
err = vals[val2.Address.String()].SignVote(chainID, vC)
@ -525,16 +569,13 @@ func TestVerifyEvidenceWithAmnesiaEvidence(t *testing.T) {
require.NoError(t, err)
//var ae types.Evidence
badAe := &types.AmnesiaEvidence{
PotentialAmnesiaEvidence: &types.PotentialAmnesiaEvidence{
VoteA: voteA,
VoteB: voteB,
},
PotentialAmnesiaEvidence: pae,
Polc: &types.ProofOfLockChange{
Votes: []*types.Vote{voteC},
PubKey: val.PubKey,
},
}
err = sm.VerifyEvidence(stateDB, state, badAe, nil)
err = sm.VerifyEvidence(stateDB, state, badAe, &types.Header{Time: defaultTestTime})
if assert.Error(t, err) {
assert.Equal(t, err.Error(), "amnesia evidence contains invalid polc, err: "+
"invalid commit -- insufficient voting power: got 1000, needed more than 2667")
@ -553,26 +594,20 @@ func TestVerifyEvidenceWithAmnesiaEvidence(t *testing.T) {
require.NoError(t, err)
goodAe := &types.AmnesiaEvidence{
PotentialAmnesiaEvidence: &types.PotentialAmnesiaEvidence{
VoteA: voteA,
VoteB: voteB,
},
PotentialAmnesiaEvidence: pae,
Polc: &types.ProofOfLockChange{
Votes: []*types.Vote{voteC, voteD, voteE},
PubKey: val.PubKey,
},
}
err = sm.VerifyEvidence(stateDB, state, goodAe, nil)
err = sm.VerifyEvidence(stateDB, state, goodAe, &types.Header{Time: defaultTestTime})
assert.NoError(t, err)
goodAe = &types.AmnesiaEvidence{
PotentialAmnesiaEvidence: &types.PotentialAmnesiaEvidence{
VoteA: voteA,
VoteB: voteB,
},
Polc: types.NewEmptyPOLC(),
PotentialAmnesiaEvidence: pae,
Polc: types.NewEmptyPOLC(),
}
err = sm.VerifyEvidence(stateDB, state, goodAe, nil)
err = sm.VerifyEvidence(stateDB, state, goodAe, &types.Header{Time: defaultTestTime})
assert.NoError(t, err)
}
@ -608,11 +643,7 @@ func TestVerifyEvidenceWithLunaticValidatorEvidence(t *testing.T) {
err := vals[val.Address.String()].SignVote(chainID, v)
vote.Signature = v.Signature
require.NoError(t, err)
ev := &types.LunaticValidatorEvidence{
Header: h,
Vote: vote,
InvalidHeaderField: "ConsensusHash",
}
ev := types.NewLunaticValidatorEvidence(h, vote, "ConsensusHash", defaultTestTime)
err = ev.ValidateBasic()
require.NoError(t, err)
err = sm.VerifyEvidence(stateDB, state, ev, h)


+ 3
- 2
types/block_test.go View File

@ -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 {


+ 40
- 28
types/evidence.go View File

@ -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,


+ 15
- 20
types/evidence_test.go View File

@ -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{


+ 5
- 3
types/vote.go View File

@ -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,
}
}


+ 1
- 1
types/vote_set.go View File

@ -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")


Loading…
Cancel
Save