mirror of
https://github.com/tendermint/tendermint.git
synced 2026-04-22 00:30:31 +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:
@@ -20,7 +20,7 @@ linters:
|
||||
- gosimple
|
||||
- govet
|
||||
- ineffassign
|
||||
- interfacer
|
||||
# - interfacer
|
||||
- lll
|
||||
- misspell
|
||||
# - maligned
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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).
|
||||
|
||||
@@ -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} }
|
||||
|
||||
//------------------------------------
|
||||
|
||||
|
||||
@@ -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
evidence/mocks/block_store.go
Normal file
30
evidence/mocks/block_store.go
Normal 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
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
evidence/services.go
Normal file
11
evidence/services.go
Normal 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
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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:])
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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