mirror of
https://github.com/tendermint/tendermint.git
synced 2026-08-15 11:46:11 +00:00
evidence: remove phantom validator evidence (#5181)
This commit is contained in:
@@ -4,6 +4,12 @@ Special thanks to external contributors on this release:
|
||||
|
||||
Friendly reminder, we have a [bug bounty program](https://hackerone.com/tendermint).
|
||||
|
||||
### BREAKING CHANGES
|
||||
|
||||
- Go API
|
||||
|
||||
- [evidence] [\#5181](https://github.com/tendermint/tendermint/pull/5181) Phantom validator evidence was removed (also from abci) (@cmwaters)
|
||||
|
||||
### FEATURES:
|
||||
|
||||
- [abci] [\#5174](https://github.com/tendermint/tendermint/pull/5174) Add amnesia evidence and remove mock and potential amnesia evidence from abci (@cmwaters)
|
||||
@@ -4,11 +4,12 @@
|
||||
* 18-02-2020: Initial draft
|
||||
* 24-02-2020: Second version
|
||||
* 13-04-2020: Add PotentialAmnesiaEvidence and a few remarks
|
||||
* 31-07-2020: Remove PhantomValidatorEvidence
|
||||
|
||||
## Context
|
||||
|
||||
If the light client is under attack, either directly -> lunatic/phantom
|
||||
validators (light fork) or indirectly -> full fork, it's supposed to halt and
|
||||
If the light client is under attack, either directly -> lunatic
|
||||
attack (light fork) or indirectly -> full fork, it's supposed to halt and
|
||||
send evidence of misbehavior to a correct full node. Upon receiving an
|
||||
evidence, the full node should punish malicious validators (if possible).
|
||||
|
||||
@@ -102,21 +103,6 @@ If we'd go with breaking evidence, here are the types we'll need:
|
||||
|
||||
Existing `DuplicateVoteEvidence` needs to be created and gossiped.
|
||||
|
||||
### F4. Phantom validators
|
||||
|
||||
A new type of evidence needs to be created:
|
||||
|
||||
```go
|
||||
type PhantomValidatorEvidence struct {
|
||||
Header types.Header
|
||||
Vote types.Vote
|
||||
LastHeightValidatorWasInSet int64
|
||||
}
|
||||
```
|
||||
|
||||
It contains a validator's public key and a vote for a block, where this
|
||||
validator is not part of the validator set. `LastHeightValidatorWasInSet`
|
||||
indicates the last height validator was in the validator set.
|
||||
|
||||
### F5. Lunatic validator
|
||||
|
||||
@@ -184,7 +170,10 @@ accountability process should then use this evidence to request additional
|
||||
information from offended validators and construct a new type of evidence to
|
||||
punish those who conducted an amnesia attack.
|
||||
|
||||
See ADR-056 for the architecture of the fork accountability procedure.
|
||||
See ADR-056 for the architecture of the handling amnesia attacks.
|
||||
|
||||
NOTE: Conflicting headers evidence used to also create PhantomValidatorEvidence
|
||||
but this has since been removed. Refer to Appendix B.
|
||||
|
||||
## Status
|
||||
|
||||
@@ -216,3 +205,19 @@ If there is an actual fork (full fork), a full node may follow either one or
|
||||
another branch. So both H1 or H2 can be considered committed depending on which
|
||||
branch the full node is following. It's supposed to halt if it notices an
|
||||
actual fork, but there's a small chance it doesn't.
|
||||
|
||||
## Appendix B
|
||||
|
||||
PhantomValidatorEvidence was used to capture when a validator that was still staked
|
||||
(i.e. within the bonded period) but was not in the current validator set had voted for a block.
|
||||
|
||||
In later discussions it was argued that although possible to keep phantom validator
|
||||
evidence, any case a phantom validator that could have the capacity to be involved
|
||||
in fooling a light client would have to be aided by 1/3+ lunatic validators.
|
||||
|
||||
It would also be very unlikely that the new validators injected by the lunatic attack
|
||||
would be validators that currently still have something staked.
|
||||
|
||||
Not only this but there was a large degree of extra computation required in storing all
|
||||
the currently staked validators that could possibly fall into the group of being
|
||||
a phantom validator. Given this, it was removed.
|
||||
|
||||
+15
-124
@@ -39,18 +39,13 @@ type Pool struct {
|
||||
mtx sync.Mutex
|
||||
// latest state
|
||||
state sm.State
|
||||
// a map of active validators and respective last heights validator is active
|
||||
// if it was in validator set after EvidenceParams.MaxAgeNumBlocks or
|
||||
// currently is (ie. [MaxAgeNumBlocks, CurrentHeight])
|
||||
// In simple words, it means it's still bonded -> therefore slashable.
|
||||
valToLastHeight valToLastHeightMap
|
||||
|
||||
// This is the closest height where at one or more of the current trial periods
|
||||
// will have ended and we will need to then upgrade the evidence to amnesia evidence.
|
||||
// It is set to -1 when we don't have any evidence on trial.
|
||||
nextEvidenceTrialEndedHeight int64
|
||||
}
|
||||
|
||||
// Validator.Address -> Last height it was in validator set
|
||||
type valToLastHeightMap map[string]int64
|
||||
|
||||
// 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) {
|
||||
@@ -58,11 +53,6 @@ func NewPool(stateDB, evidenceDB dbm.DB, blockStore *store.BlockStore) (*Pool, e
|
||||
state = sm.LoadState(stateDB)
|
||||
)
|
||||
|
||||
valToLastHeight, err := buildValToLastHeightMap(state, stateDB, blockStore)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
pool := &Pool{
|
||||
stateDB: stateDB,
|
||||
blockStore: blockStore,
|
||||
@@ -70,7 +60,6 @@ func NewPool(stateDB, evidenceDB dbm.DB, blockStore *store.BlockStore) (*Pool, e
|
||||
logger: log.NewNopLogger(),
|
||||
evidenceStore: evidenceDB,
|
||||
evidenceList: clist.New(),
|
||||
valToLastHeight: valToLastHeight,
|
||||
nextEvidenceTrialEndedHeight: -1,
|
||||
}
|
||||
|
||||
@@ -104,8 +93,8 @@ func (evpool *Pool) AllPendingEvidence() []types.Evidence {
|
||||
return evidence
|
||||
}
|
||||
|
||||
// Update uses the latest block & state to update its copy of the state,
|
||||
// validator to last height map and calls MarkEvidenceAsCommitted.
|
||||
// Update uses the latest block & state to update any evidence that has been committed, to prune all expired evidence
|
||||
// and to check if any trial period of potential amnesia evidence has finished.
|
||||
func (evpool *Pool) Update(block *types.Block, state sm.State) {
|
||||
// sanity check
|
||||
if state.LastBlockHeight != block.Height {
|
||||
@@ -126,13 +115,14 @@ func (evpool *Pool) Update(block *types.Block, state sm.State) {
|
||||
if block.Height%state.ConsensusParams.Evidence.MaxAgeNumBlocks == 0 {
|
||||
evpool.logger.Debug("Pruning no longer necessary evidence")
|
||||
evpool.pruneExpiredPOLC()
|
||||
// NOTE: As this is periodic, this implies that there may be some pending evidence in the
|
||||
// db that have already expired. However, expired evidence will also be removed whenever
|
||||
// PendingEvidence() is called ensuring that no expired evidence is proposed.
|
||||
evpool.removeExpiredPendingEvidence()
|
||||
}
|
||||
|
||||
evpool.updateValToLastHeight(block.Height, state)
|
||||
|
||||
if evpool.nextEvidenceTrialEndedHeight > 0 && block.Height > evpool.nextEvidenceTrialEndedHeight {
|
||||
evpool.logger.Debug("Upgrading all potential evidence that have served the trial period")
|
||||
evpool.logger.Debug("Upgrading all potential amnesia evidence that have served the trial period")
|
||||
evpool.nextEvidenceTrialEndedHeight = evpool.upgradePotentialAmnesiaEvidence()
|
||||
}
|
||||
}
|
||||
@@ -181,15 +171,7 @@ func (evpool *Pool) AddEvidence(evidence types.Evidence) error {
|
||||
return err
|
||||
}
|
||||
|
||||
// XXX: Copy here since this should be a rare case.
|
||||
evpool.mtx.Lock()
|
||||
valToLastHeightCopy := make(valToLastHeightMap, len(evpool.valToLastHeight))
|
||||
for k, v := range evpool.valToLastHeight {
|
||||
valToLastHeightCopy[k] = v
|
||||
}
|
||||
evpool.mtx.Unlock()
|
||||
|
||||
evList = ce.Split(&blockMeta.Header, valSet, valToLastHeightCopy)
|
||||
evList = ce.Split(&blockMeta.Header, valSet)
|
||||
}
|
||||
|
||||
for _, ev := range evList {
|
||||
@@ -224,6 +206,8 @@ func (evpool *Pool) AddEvidence(evidence types.Evidence) error {
|
||||
}
|
||||
continue
|
||||
} else if ae, ok := ev.(*types.AmnesiaEvidence); ok {
|
||||
// we have received an new amnesia evidence that we have never seen before so we must extract out the
|
||||
// potential amnesia evidence part and run our own trial
|
||||
if ae.Polc.IsAbsent() && ae.PotentialAmnesiaEvidence.VoteA.Round <
|
||||
ae.PotentialAmnesiaEvidence.VoteB.Round {
|
||||
if err := evpool.handleInboundPotentialAmnesiaEvidence(ae.PotentialAmnesiaEvidence); err != nil {
|
||||
@@ -231,8 +215,9 @@ func (evpool *Pool) AddEvidence(evidence types.Evidence) error {
|
||||
}
|
||||
continue
|
||||
} else {
|
||||
// we are going to add this amnesia evidence and check if we already have an amnesia evidence or potential
|
||||
// amnesia evidence that addesses the same case
|
||||
// we are going to add this amnesia evidence as it's already punishable.
|
||||
// We also check if we already have an amnesia evidence or potential
|
||||
// amnesia evidence that addesses the same case that we will need to remove
|
||||
aeWithoutPolc := types.NewAmnesiaEvidence(ae.PotentialAmnesiaEvidence, types.NewEmptyPOLC())
|
||||
if evpool.IsPending(aeWithoutPolc) {
|
||||
evpool.removePendingEvidence(aeWithoutPolc)
|
||||
@@ -404,21 +389,6 @@ func (evpool *Pool) Header(height int64) *types.Header {
|
||||
return &blockMeta.Header
|
||||
}
|
||||
|
||||
// ValidatorLastHeight returns the last height of the validator w/ the
|
||||
// given address. 0 - if address never was a validator or was such a
|
||||
// long time ago (> ConsensusParams.Evidence.MaxAgeDuration && >
|
||||
// ConsensusParams.Evidence.MaxAgeNumBlocks).
|
||||
func (evpool *Pool) ValidatorLastHeight(address []byte) int64 {
|
||||
evpool.mtx.Lock()
|
||||
defer evpool.mtx.Unlock()
|
||||
|
||||
h, ok := evpool.valToLastHeight[string(address)]
|
||||
if !ok {
|
||||
return 0
|
||||
}
|
||||
return h
|
||||
}
|
||||
|
||||
// State returns the current state of the evpool.
|
||||
func (evpool *Pool) State() sm.State {
|
||||
evpool.mtx.Lock()
|
||||
@@ -711,85 +681,6 @@ func evMapKey(ev types.Evidence) string {
|
||||
return string(ev.Hash())
|
||||
}
|
||||
|
||||
func (evpool *Pool) updateValToLastHeight(blockHeight int64, state sm.State) {
|
||||
evpool.mtx.Lock()
|
||||
defer evpool.mtx.Unlock()
|
||||
|
||||
// Update current validators & add new ones.
|
||||
for _, val := range state.Validators.Validators {
|
||||
evpool.valToLastHeight[string(val.Address)] = blockHeight
|
||||
}
|
||||
|
||||
// Remove validators outside of MaxAgeNumBlocks & MaxAgeDuration.
|
||||
removeHeight := blockHeight - state.ConsensusParams.Evidence.MaxAgeNumBlocks
|
||||
if removeHeight >= 1 {
|
||||
for val, height := range evpool.valToLastHeight {
|
||||
if height <= removeHeight {
|
||||
delete(evpool.valToLastHeight, val)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func buildValToLastHeightMap(state sm.State, stateDB dbm.DB, blockStore *store.BlockStore) (valToLastHeightMap, error) {
|
||||
var (
|
||||
valToLastHeight = make(map[string]int64)
|
||||
params = state.ConsensusParams.Evidence
|
||||
|
||||
numBlocks = int64(0)
|
||||
minAgeTime = time.Now().Add(-params.MaxAgeDuration)
|
||||
height = state.LastBlockHeight
|
||||
)
|
||||
|
||||
if height == 0 {
|
||||
return valToLastHeight, nil
|
||||
}
|
||||
|
||||
meta := blockStore.LoadBlockMeta(height)
|
||||
if meta == nil {
|
||||
return nil, fmt.Errorf("block meta for height %d not found", height)
|
||||
}
|
||||
blockTime := meta.Header.Time
|
||||
|
||||
// From state.LastBlockHeight, build a map of "active" validators until
|
||||
// MaxAgeNumBlocks is passed and block time is less than now() -
|
||||
// MaxAgeDuration.
|
||||
for height >= 1 && (numBlocks <= params.MaxAgeNumBlocks || !blockTime.Before(minAgeTime)) {
|
||||
valSet, err := sm.LoadValidators(stateDB, height)
|
||||
if err != nil {
|
||||
// last stored height -> return
|
||||
if _, ok := err.(sm.ErrNoValSetForHeight); ok {
|
||||
return valToLastHeight, nil
|
||||
}
|
||||
return nil, fmt.Errorf("validator set for height %d not found", height)
|
||||
}
|
||||
|
||||
for _, val := range valSet.Validators {
|
||||
key := string(val.Address)
|
||||
if _, ok := valToLastHeight[key]; !ok {
|
||||
valToLastHeight[key] = height
|
||||
}
|
||||
}
|
||||
|
||||
height--
|
||||
|
||||
if height > 0 {
|
||||
// NOTE: we assume here blockStore and state.Validators are in sync. I.e if
|
||||
// block N is stored, then validators for height N are also stored in
|
||||
// state.
|
||||
meta := blockStore.LoadBlockMeta(height)
|
||||
if meta == nil {
|
||||
return nil, fmt.Errorf("block meta for height %d not found", height)
|
||||
}
|
||||
blockTime = meta.Header.Time
|
||||
}
|
||||
|
||||
numBlocks++
|
||||
}
|
||||
|
||||
return valToLastHeight, nil
|
||||
}
|
||||
|
||||
// big endian padded hex
|
||||
func bE(h int64) string {
|
||||
return fmt.Sprintf("%0.16X", h)
|
||||
|
||||
@@ -182,27 +182,6 @@ func TestEvidencePoolUpdate(t *testing.T) {
|
||||
|
||||
// a) Update marks evidence as committed
|
||||
assert.True(t, pool.IsCommitted(evidence))
|
||||
// b) Update updates valToLastHeight map
|
||||
assert.Equal(t, height+1, pool.ValidatorLastHeight(valAddr))
|
||||
}
|
||||
|
||||
func TestEvidencePoolNewPool(t *testing.T) {
|
||||
var (
|
||||
val = types.NewMockPV()
|
||||
valAddr = val.PrivKey.PubKey().Address()
|
||||
height = int64(1)
|
||||
stateDB = initializeValidatorState(val, height)
|
||||
evidenceDB = dbm.NewMemDB()
|
||||
blockStoreDB = dbm.NewMemDB()
|
||||
state = sm.LoadState(stateDB)
|
||||
blockStore = initializeBlockStore(blockStoreDB, state, valAddr)
|
||||
)
|
||||
|
||||
pool, err := NewPool(stateDB, evidenceDB, blockStore)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, height, pool.ValidatorLastHeight(valAddr))
|
||||
assert.EqualValues(t, 0, pool.ValidatorLastHeight([]byte("non-existent-validator")))
|
||||
}
|
||||
|
||||
func TestAddingAndPruningPOLC(t *testing.T) {
|
||||
|
||||
@@ -302,58 +302,6 @@ func (m *LunaticValidatorEvidence) GetInvalidHeaderField() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
type PhantomValidatorEvidence struct {
|
||||
Vote *Vote `protobuf:"bytes,1,opt,name=vote,proto3" json:"vote,omitempty"`
|
||||
LastHeightValidatorWasInSet int64 `protobuf:"varint,2,opt,name=last_height_validator_was_in_set,json=lastHeightValidatorWasInSet,proto3" json:"last_height_validator_was_in_set,omitempty"`
|
||||
}
|
||||
|
||||
func (m *PhantomValidatorEvidence) Reset() { *m = PhantomValidatorEvidence{} }
|
||||
func (m *PhantomValidatorEvidence) String() string { return proto.CompactTextString(m) }
|
||||
func (*PhantomValidatorEvidence) ProtoMessage() {}
|
||||
func (*PhantomValidatorEvidence) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_6825fabc78e0a168, []int{5}
|
||||
}
|
||||
func (m *PhantomValidatorEvidence) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
}
|
||||
func (m *PhantomValidatorEvidence) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
if deterministic {
|
||||
return xxx_messageInfo_PhantomValidatorEvidence.Marshal(b, m, deterministic)
|
||||
} else {
|
||||
b = b[:cap(b)]
|
||||
n, err := m.MarshalToSizedBuffer(b)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return b[:n], nil
|
||||
}
|
||||
}
|
||||
func (m *PhantomValidatorEvidence) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_PhantomValidatorEvidence.Merge(m, src)
|
||||
}
|
||||
func (m *PhantomValidatorEvidence) XXX_Size() int {
|
||||
return m.Size()
|
||||
}
|
||||
func (m *PhantomValidatorEvidence) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_PhantomValidatorEvidence.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_PhantomValidatorEvidence proto.InternalMessageInfo
|
||||
|
||||
func (m *PhantomValidatorEvidence) GetVote() *Vote {
|
||||
if m != nil {
|
||||
return m.Vote
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *PhantomValidatorEvidence) GetLastHeightValidatorWasInSet() int64 {
|
||||
if m != nil {
|
||||
return m.LastHeightValidatorWasInSet
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
type Evidence struct {
|
||||
// Types that are valid to be assigned to Sum:
|
||||
// *Evidence_DuplicateVoteEvidence
|
||||
@@ -361,7 +309,6 @@ type Evidence struct {
|
||||
// *Evidence_LunaticValidatorEvidence
|
||||
// *Evidence_PotentialAmnesiaEvidence
|
||||
// *Evidence_AmnesiaEvidence
|
||||
// *Evidence_PhantomValidatorEvidence
|
||||
Sum isEvidence_Sum `protobuf_oneof:"sum"`
|
||||
}
|
||||
|
||||
@@ -369,7 +316,7 @@ func (m *Evidence) Reset() { *m = Evidence{} }
|
||||
func (m *Evidence) String() string { return proto.CompactTextString(m) }
|
||||
func (*Evidence) ProtoMessage() {}
|
||||
func (*Evidence) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_6825fabc78e0a168, []int{6}
|
||||
return fileDescriptor_6825fabc78e0a168, []int{5}
|
||||
}
|
||||
func (m *Evidence) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
@@ -419,16 +366,12 @@ type Evidence_PotentialAmnesiaEvidence struct {
|
||||
type Evidence_AmnesiaEvidence struct {
|
||||
AmnesiaEvidence *AmnesiaEvidence `protobuf:"bytes,5,opt,name=amnesia_evidence,json=amnesiaEvidence,proto3,oneof" json:"amnesia_evidence,omitempty"`
|
||||
}
|
||||
type Evidence_PhantomValidatorEvidence struct {
|
||||
PhantomValidatorEvidence *PhantomValidatorEvidence `protobuf:"bytes,6,opt,name=phantom_validator_evidence,json=phantomValidatorEvidence,proto3,oneof" json:"phantom_validator_evidence,omitempty"`
|
||||
}
|
||||
|
||||
func (*Evidence_DuplicateVoteEvidence) isEvidence_Sum() {}
|
||||
func (*Evidence_ConflictingHeadersEvidence) isEvidence_Sum() {}
|
||||
func (*Evidence_LunaticValidatorEvidence) isEvidence_Sum() {}
|
||||
func (*Evidence_PotentialAmnesiaEvidence) isEvidence_Sum() {}
|
||||
func (*Evidence_AmnesiaEvidence) isEvidence_Sum() {}
|
||||
func (*Evidence_PhantomValidatorEvidence) isEvidence_Sum() {}
|
||||
|
||||
func (m *Evidence) GetSum() isEvidence_Sum {
|
||||
if m != nil {
|
||||
@@ -472,13 +415,6 @@ func (m *Evidence) GetAmnesiaEvidence() *AmnesiaEvidence {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Evidence) GetPhantomValidatorEvidence() *PhantomValidatorEvidence {
|
||||
if x, ok := m.GetSum().(*Evidence_PhantomValidatorEvidence); ok {
|
||||
return x.PhantomValidatorEvidence
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// XXX_OneofWrappers is for the internal use of the proto package.
|
||||
func (*Evidence) XXX_OneofWrappers() []interface{} {
|
||||
return []interface{}{
|
||||
@@ -487,7 +423,6 @@ func (*Evidence) XXX_OneofWrappers() []interface{} {
|
||||
(*Evidence_LunaticValidatorEvidence)(nil),
|
||||
(*Evidence_PotentialAmnesiaEvidence)(nil),
|
||||
(*Evidence_AmnesiaEvidence)(nil),
|
||||
(*Evidence_PhantomValidatorEvidence)(nil),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -501,7 +436,7 @@ func (m *EvidenceData) Reset() { *m = EvidenceData{} }
|
||||
func (m *EvidenceData) String() string { return proto.CompactTextString(m) }
|
||||
func (*EvidenceData) ProtoMessage() {}
|
||||
func (*EvidenceData) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_6825fabc78e0a168, []int{7}
|
||||
return fileDescriptor_6825fabc78e0a168, []int{6}
|
||||
}
|
||||
func (m *EvidenceData) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
@@ -553,7 +488,7 @@ func (m *ProofOfLockChange) Reset() { *m = ProofOfLockChange{} }
|
||||
func (m *ProofOfLockChange) String() string { return proto.CompactTextString(m) }
|
||||
func (*ProofOfLockChange) ProtoMessage() {}
|
||||
func (*ProofOfLockChange) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_6825fabc78e0a168, []int{8}
|
||||
return fileDescriptor_6825fabc78e0a168, []int{7}
|
||||
}
|
||||
func (m *ProofOfLockChange) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
@@ -602,7 +537,6 @@ func init() {
|
||||
proto.RegisterType((*AmnesiaEvidence)(nil), "tendermint.types.AmnesiaEvidence")
|
||||
proto.RegisterType((*ConflictingHeadersEvidence)(nil), "tendermint.types.ConflictingHeadersEvidence")
|
||||
proto.RegisterType((*LunaticValidatorEvidence)(nil), "tendermint.types.LunaticValidatorEvidence")
|
||||
proto.RegisterType((*PhantomValidatorEvidence)(nil), "tendermint.types.PhantomValidatorEvidence")
|
||||
proto.RegisterType((*Evidence)(nil), "tendermint.types.Evidence")
|
||||
proto.RegisterType((*EvidenceData)(nil), "tendermint.types.EvidenceData")
|
||||
proto.RegisterType((*ProofOfLockChange)(nil), "tendermint.types.ProofOfLockChange")
|
||||
@@ -611,53 +545,48 @@ func init() {
|
||||
func init() { proto.RegisterFile("tendermint/types/evidence.proto", fileDescriptor_6825fabc78e0a168) }
|
||||
|
||||
var fileDescriptor_6825fabc78e0a168 = []byte{
|
||||
// 728 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x55, 0xcd, 0x4e, 0xdb, 0x4a,
|
||||
0x18, 0x8d, 0x49, 0xc8, 0xe5, 0x7e, 0x20, 0xc1, 0xb5, 0xe0, 0xd6, 0x4a, 0x91, 0x01, 0x77, 0x51,
|
||||
0x84, 0xa8, 0x03, 0xa9, 0x2a, 0x36, 0xdd, 0xf0, 0x57, 0xa5, 0x02, 0xb5, 0xd4, 0x48, 0x54, 0xea,
|
||||
0xc6, 0x9d, 0xd8, 0x13, 0x7b, 0xc0, 0x99, 0xb1, 0xe2, 0x71, 0xda, 0x48, 0x7d, 0x85, 0x4a, 0xdd,
|
||||
0xf7, 0x0d, 0xba, 0xee, 0x43, 0xb0, 0x64, 0xd9, 0x55, 0x55, 0xc1, 0x5b, 0x74, 0x55, 0x79, 0x3c,
|
||||
0x71, 0xa2, 0x38, 0x86, 0x76, 0xd3, 0x8d, 0x65, 0xcd, 0x77, 0xe6, 0x9c, 0x33, 0x33, 0xe7, 0x9b,
|
||||
0x81, 0x15, 0x8e, 0xa9, 0x8b, 0xbb, 0x1d, 0x42, 0x79, 0x9d, 0xf7, 0x43, 0x1c, 0xd5, 0x71, 0x8f,
|
||||
0xb8, 0x98, 0x3a, 0xd8, 0x0c, 0xbb, 0x8c, 0x33, 0x75, 0x61, 0x08, 0x30, 0x05, 0xa0, 0xb6, 0xe8,
|
||||
0x31, 0x8f, 0x89, 0x62, 0x3d, 0xf9, 0x4b, 0x71, 0xb5, 0xe5, 0x1c, 0x91, 0xf8, 0x4e, 0xa8, 0x3a,
|
||||
0xdd, 0x7e, 0xc8, 0x59, 0xfd, 0x02, 0xf7, 0x65, 0xd5, 0x88, 0x61, 0xe9, 0x20, 0x0e, 0x03, 0xe2,
|
||||
0x20, 0x8e, 0xcf, 0x18, 0xc7, 0x87, 0xd2, 0x82, 0xfa, 0x08, 0xaa, 0x3d, 0xc6, 0xb1, 0x8d, 0x34,
|
||||
0x65, 0x55, 0x59, 0x9f, 0x6d, 0xfc, 0x6f, 0x8e, 0xbb, 0x31, 0x13, 0xbc, 0x35, 0x9d, 0xa0, 0x76,
|
||||
0x33, 0x78, 0x4b, 0x9b, 0xba, 0x1b, 0xbe, 0x67, 0x7c, 0x56, 0x40, 0x3b, 0x61, 0x1c, 0x53, 0x4e,
|
||||
0x50, 0xb0, 0xdb, 0xa1, 0x38, 0x22, 0xe8, 0xef, 0x48, 0xab, 0x6b, 0x30, 0xe7, 0x63, 0xe2, 0xf9,
|
||||
0xdc, 0x8e, 0x38, 0xea, 0x84, 0x5a, 0x79, 0x55, 0x59, 0x2f, 0x5b, 0xb3, 0xe9, 0xd8, 0x69, 0x32,
|
||||
0x64, 0x7c, 0x55, 0x60, 0x7e, 0xdc, 0x94, 0x0f, 0xb5, 0x70, 0x60, 0xd8, 0x46, 0x69, 0xd1, 0x1e,
|
||||
0x1c, 0x98, 0x34, 0xba, 0x91, 0x57, 0x2e, 0x5a, 0xa4, 0xa5, 0x85, 0x45, 0xcb, 0xdf, 0x81, 0x4a,
|
||||
0xc8, 0x02, 0x47, 0xae, 0xe6, 0xc1, 0x04, 0xce, 0x2e, 0x63, 0xed, 0x97, 0xed, 0x63, 0xe6, 0x5c,
|
||||
0xec, 0xfb, 0x88, 0x7a, 0xd8, 0x12, 0x13, 0x8c, 0x0f, 0x50, 0xdb, 0x67, 0xb4, 0x1d, 0x10, 0x87,
|
||||
0x13, 0xea, 0x35, 0x31, 0x72, 0x71, 0x37, 0xca, 0x68, 0x4d, 0x98, 0xf2, 0xb7, 0xa5, 0x51, 0x3d,
|
||||
0x4f, 0x7a, 0x4a, 0x3c, 0x8a, 0xdd, 0x74, 0x92, 0x35, 0xe5, 0x6f, 0x0b, 0x7c, 0x43, 0x9a, 0xb8,
|
||||
0x1b, 0xdf, 0x30, 0xbe, 0x28, 0xa0, 0x1d, 0xc7, 0x14, 0x71, 0xe2, 0x9c, 0xa1, 0x80, 0xb8, 0x88,
|
||||
0xb3, 0x6e, 0x26, 0xbe, 0x05, 0x55, 0x5f, 0x40, 0xa5, 0x01, 0x2d, 0x4f, 0x28, 0xa9, 0x24, 0x4e,
|
||||
0xdd, 0x80, 0x4a, 0x72, 0x5e, 0x77, 0x9c, 0xa9, 0xc0, 0xa8, 0x5b, 0xb0, 0x48, 0x68, 0x2f, 0x11,
|
||||
0xb5, 0xd3, 0xd9, 0x76, 0x9b, 0xe0, 0xc0, 0x15, 0x47, 0xfb, 0xaf, 0xa5, 0xca, 0x5a, 0x2a, 0xf0,
|
||||
0x2c, 0xa9, 0x18, 0x1f, 0x93, 0xfc, 0xf9, 0x88, 0x72, 0xd6, 0xc9, 0x9b, 0x1d, 0x48, 0x2b, 0xbf,
|
||||
0x21, 0x7d, 0x08, 0xab, 0x01, 0x8a, 0xb8, 0x2d, 0x23, 0xd5, 0x1b, 0x90, 0xd9, 0xef, 0x50, 0x64,
|
||||
0x13, 0x6a, 0x47, 0x98, 0x8b, 0x25, 0x94, 0xad, 0xfb, 0x09, 0xae, 0x29, 0x60, 0x99, 0xe4, 0x6b,
|
||||
0x14, 0x3d, 0xa7, 0xa7, 0x98, 0x1b, 0x3f, 0x2b, 0x30, 0x93, 0xe9, 0x23, 0xb8, 0xe7, 0x0e, 0x7a,
|
||||
0xd2, 0x16, 0xd1, 0x1e, 0xcb, 0xd9, 0xc3, 0xbc, 0xa5, 0x89, 0x4d, 0xdc, 0x2c, 0x59, 0x4b, 0xee,
|
||||
0xc4, 0xee, 0x0e, 0x61, 0xd9, 0x19, 0x46, 0x45, 0xee, 0x5a, 0x34, 0xd4, 0x49, 0x77, 0x7d, 0x33,
|
||||
0xaf, 0x53, 0x1c, 0xb0, 0x66, 0xc9, 0xaa, 0x39, 0xc5, 0xf1, 0x3b, 0x87, 0x5a, 0x90, 0xa6, 0x63,
|
||||
0x64, 0x93, 0x32, 0xbd, 0x72, 0x51, 0xff, 0x14, 0x25, 0xaa, 0x59, 0xb2, 0xb4, 0xa0, 0x28, 0x6d,
|
||||
0xe7, 0xb7, 0xf6, 0x6a, 0xe5, 0x4f, 0x7b, 0x35, 0xd1, 0x2a, 0xec, 0xd6, 0x17, 0xb0, 0x90, 0x53,
|
||||
0x98, 0x16, 0x0a, 0x6b, 0x79, 0x85, 0x3c, 0xf1, 0x3c, 0x1a, 0xe3, 0x4b, 0xbc, 0xa7, 0xc1, 0x9c,
|
||||
0xb4, 0x4f, 0xd5, 0x42, 0xef, 0x05, 0x61, 0x16, 0xde, 0x0b, 0x6a, 0x7b, 0xd3, 0x50, 0x8e, 0xe2,
|
||||
0x8e, 0xf1, 0x16, 0xe6, 0x06, 0x43, 0x07, 0x88, 0x23, 0xf5, 0x29, 0xcc, 0x8c, 0x04, 0xae, 0xbc,
|
||||
0x3e, 0xdb, 0xa8, 0xe5, 0x05, 0x33, 0x92, 0xca, 0xe5, 0xf7, 0x95, 0x92, 0x95, 0xcd, 0x50, 0x55,
|
||||
0xa8, 0xf8, 0x28, 0xf2, 0x45, 0x84, 0xe6, 0x2c, 0xf1, 0x6f, 0xbc, 0x87, 0xff, 0x72, 0x97, 0x96,
|
||||
0xba, 0x09, 0xe2, 0x46, 0x8e, 0xa4, 0xc6, 0xad, 0xd7, 0x76, 0xa4, 0x3e, 0x81, 0x7f, 0xc2, 0xb8,
|
||||
0x65, 0x5f, 0xe0, 0xbe, 0x0c, 0xe7, 0xf2, 0x28, 0x3e, 0x7d, 0xd8, 0xcc, 0x93, 0xb8, 0x15, 0x10,
|
||||
0xe7, 0x08, 0xf7, 0xad, 0x6a, 0x18, 0xb7, 0x8e, 0x70, 0x7f, 0xef, 0xd5, 0xe5, 0xb5, 0xae, 0x5c,
|
||||
0x5d, 0xeb, 0xca, 0x8f, 0x6b, 0x5d, 0xf9, 0x74, 0xa3, 0x97, 0xae, 0x6e, 0xf4, 0xd2, 0xb7, 0x1b,
|
||||
0xbd, 0xf4, 0x66, 0xc7, 0x23, 0xdc, 0x8f, 0x5b, 0xa6, 0xc3, 0x3a, 0xf5, 0xd1, 0x07, 0x74, 0xf8,
|
||||
0x9b, 0x3e, 0xb4, 0xe3, 0x8f, 0x6b, 0xab, 0x2a, 0xc6, 0x1f, 0xff, 0x0a, 0x00, 0x00, 0xff, 0xff,
|
||||
0xdc, 0x62, 0x93, 0xc8, 0xc0, 0x07, 0x00, 0x00,
|
||||
// 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,
|
||||
}
|
||||
|
||||
func (m *DuplicateVoteEvidence) Marshal() (dAtA []byte, err error) {
|
||||
@@ -907,46 +836,6 @@ func (m *LunaticValidatorEvidence) MarshalToSizedBuffer(dAtA []byte) (int, error
|
||||
return len(dAtA) - i, nil
|
||||
}
|
||||
|
||||
func (m *PhantomValidatorEvidence) Marshal() (dAtA []byte, err error) {
|
||||
size := m.Size()
|
||||
dAtA = make([]byte, size)
|
||||
n, err := m.MarshalToSizedBuffer(dAtA[:size])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return dAtA[:n], nil
|
||||
}
|
||||
|
||||
func (m *PhantomValidatorEvidence) MarshalTo(dAtA []byte) (int, error) {
|
||||
size := m.Size()
|
||||
return m.MarshalToSizedBuffer(dAtA[:size])
|
||||
}
|
||||
|
||||
func (m *PhantomValidatorEvidence) MarshalToSizedBuffer(dAtA []byte) (int, error) {
|
||||
i := len(dAtA)
|
||||
_ = i
|
||||
var l int
|
||||
_ = l
|
||||
if m.LastHeightValidatorWasInSet != 0 {
|
||||
i = encodeVarintEvidence(dAtA, i, uint64(m.LastHeightValidatorWasInSet))
|
||||
i--
|
||||
dAtA[i] = 0x10
|
||||
}
|
||||
if m.Vote != nil {
|
||||
{
|
||||
size, err := m.Vote.MarshalToSizedBuffer(dAtA[:i])
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
i -= size
|
||||
i = encodeVarintEvidence(dAtA, i, uint64(size))
|
||||
}
|
||||
i--
|
||||
dAtA[i] = 0xa
|
||||
}
|
||||
return len(dAtA) - i, nil
|
||||
}
|
||||
|
||||
func (m *Evidence) Marshal() (dAtA []byte, err error) {
|
||||
size := m.Size()
|
||||
dAtA = make([]byte, size)
|
||||
@@ -1084,27 +973,6 @@ func (m *Evidence_AmnesiaEvidence) MarshalToSizedBuffer(dAtA []byte) (int, error
|
||||
}
|
||||
return len(dAtA) - i, nil
|
||||
}
|
||||
func (m *Evidence_PhantomValidatorEvidence) MarshalTo(dAtA []byte) (int, error) {
|
||||
size := m.Size()
|
||||
return m.MarshalToSizedBuffer(dAtA[:size])
|
||||
}
|
||||
|
||||
func (m *Evidence_PhantomValidatorEvidence) MarshalToSizedBuffer(dAtA []byte) (int, error) {
|
||||
i := len(dAtA)
|
||||
if m.PhantomValidatorEvidence != nil {
|
||||
{
|
||||
size, err := m.PhantomValidatorEvidence.MarshalToSizedBuffer(dAtA[:i])
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
i -= size
|
||||
i = encodeVarintEvidence(dAtA, i, uint64(size))
|
||||
}
|
||||
i--
|
||||
dAtA[i] = 0x32
|
||||
}
|
||||
return len(dAtA) - i, nil
|
||||
}
|
||||
func (m *EvidenceData) Marshal() (dAtA []byte, err error) {
|
||||
size := m.Size()
|
||||
dAtA = make([]byte, size)
|
||||
@@ -1301,22 +1169,6 @@ func (m *LunaticValidatorEvidence) Size() (n int) {
|
||||
return n
|
||||
}
|
||||
|
||||
func (m *PhantomValidatorEvidence) Size() (n int) {
|
||||
if m == nil {
|
||||
return 0
|
||||
}
|
||||
var l int
|
||||
_ = l
|
||||
if m.Vote != nil {
|
||||
l = m.Vote.Size()
|
||||
n += 1 + l + sovEvidence(uint64(l))
|
||||
}
|
||||
if m.LastHeightValidatorWasInSet != 0 {
|
||||
n += 1 + sovEvidence(uint64(m.LastHeightValidatorWasInSet))
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
func (m *Evidence) Size() (n int) {
|
||||
if m == nil {
|
||||
return 0
|
||||
@@ -1389,18 +1241,6 @@ func (m *Evidence_AmnesiaEvidence) Size() (n int) {
|
||||
}
|
||||
return n
|
||||
}
|
||||
func (m *Evidence_PhantomValidatorEvidence) Size() (n int) {
|
||||
if m == nil {
|
||||
return 0
|
||||
}
|
||||
var l int
|
||||
_ = l
|
||||
if m.PhantomValidatorEvidence != nil {
|
||||
l = m.PhantomValidatorEvidence.Size()
|
||||
n += 1 + l + sovEvidence(uint64(l))
|
||||
}
|
||||
return n
|
||||
}
|
||||
func (m *EvidenceData) Size() (n int) {
|
||||
if m == nil {
|
||||
return 0
|
||||
@@ -2121,114 +1961,6 @@ func (m *LunaticValidatorEvidence) Unmarshal(dAtA []byte) error {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func (m *PhantomValidatorEvidence) Unmarshal(dAtA []byte) error {
|
||||
l := len(dAtA)
|
||||
iNdEx := 0
|
||||
for iNdEx < l {
|
||||
preIndex := iNdEx
|
||||
var wire uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowEvidence
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
wire |= uint64(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
fieldNum := int32(wire >> 3)
|
||||
wireType := int(wire & 0x7)
|
||||
if wireType == 4 {
|
||||
return fmt.Errorf("proto: PhantomValidatorEvidence: wiretype end group for non-group")
|
||||
}
|
||||
if fieldNum <= 0 {
|
||||
return fmt.Errorf("proto: PhantomValidatorEvidence: illegal tag %d (wire type %d)", fieldNum, wire)
|
||||
}
|
||||
switch fieldNum {
|
||||
case 1:
|
||||
if wireType != 2 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field Vote", 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 m.Vote == nil {
|
||||
m.Vote = &Vote{}
|
||||
}
|
||||
if err := m.Vote.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
|
||||
return err
|
||||
}
|
||||
iNdEx = postIndex
|
||||
case 2:
|
||||
if wireType != 0 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field LastHeightValidatorWasInSet", wireType)
|
||||
}
|
||||
m.LastHeightValidatorWasInSet = 0
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowEvidence
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
m.LastHeightValidatorWasInSet |= int64(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
default:
|
||||
iNdEx = preIndex
|
||||
skippy, err := skipEvidence(dAtA[iNdEx:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if skippy < 0 {
|
||||
return ErrInvalidLengthEvidence
|
||||
}
|
||||
if (iNdEx + skippy) < 0 {
|
||||
return ErrInvalidLengthEvidence
|
||||
}
|
||||
if (iNdEx + skippy) > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
iNdEx += skippy
|
||||
}
|
||||
}
|
||||
|
||||
if iNdEx > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func (m *Evidence) Unmarshal(dAtA []byte) error {
|
||||
l := len(dAtA)
|
||||
iNdEx := 0
|
||||
@@ -2433,41 +2165,6 @@ func (m *Evidence) Unmarshal(dAtA []byte) error {
|
||||
}
|
||||
m.Sum = &Evidence_AmnesiaEvidence{v}
|
||||
iNdEx = postIndex
|
||||
case 6:
|
||||
if wireType != 2 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field PhantomValidatorEvidence", 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
|
||||
}
|
||||
v := &PhantomValidatorEvidence{}
|
||||
if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
|
||||
return err
|
||||
}
|
||||
m.Sum = &Evidence_PhantomValidatorEvidence{v}
|
||||
iNdEx = postIndex
|
||||
default:
|
||||
iNdEx = preIndex
|
||||
skippy, err := skipEvidence(dAtA[iNdEx:])
|
||||
|
||||
@@ -37,11 +37,6 @@ message LunaticValidatorEvidence {
|
||||
string invalid_header_field = 3;
|
||||
}
|
||||
|
||||
message PhantomValidatorEvidence {
|
||||
Vote vote = 1;
|
||||
int64 last_height_validator_was_in_set = 2;
|
||||
}
|
||||
|
||||
message Evidence {
|
||||
oneof sum {
|
||||
DuplicateVoteEvidence duplicate_vote_evidence = 1;
|
||||
@@ -49,7 +44,6 @@ message Evidence {
|
||||
LunaticValidatorEvidence lunatic_validator_evidence = 3;
|
||||
PotentialAmnesiaEvidence potential_amnesia_evidence = 4;
|
||||
AmnesiaEvidence amnesia_evidence = 5;
|
||||
PhantomValidatorEvidence phantom_validator_evidence = 6;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+12
-42
@@ -225,51 +225,21 @@ func VerifyEvidence(stateDB dbm.DB, state State, evidence types.Evidence, commit
|
||||
addr := evidence.Address()
|
||||
var val *types.Validator
|
||||
|
||||
// For PhantomValidatorEvidence, check evidence.Address was not part of the
|
||||
// validator set at height evidence.Height, but was a validator before OR
|
||||
// after.
|
||||
if phve, ok := evidence.(*types.PhantomValidatorEvidence); ok {
|
||||
// confirm that it hasn't been forged
|
||||
|
||||
_, val = valset.GetByAddress(addr)
|
||||
if val != nil {
|
||||
return fmt.Errorf("address %X was a validator at height %d", addr, evidence.Height())
|
||||
}
|
||||
|
||||
// check if last height validator was in the validator set is within
|
||||
// MaxAgeNumBlocks.
|
||||
if height-phve.LastHeightValidatorWasInSet > evidenceParams.MaxAgeNumBlocks {
|
||||
return fmt.Errorf("last time validator was in the set at height %d, min: %d",
|
||||
phve.LastHeightValidatorWasInSet, height-phve.LastHeightValidatorWasInSet)
|
||||
}
|
||||
|
||||
valset, err := LoadValidators(stateDB, phve.LastHeightValidatorWasInSet)
|
||||
if err != nil {
|
||||
// TODO: if err is just that we cant find it cuz we pruned, ignore.
|
||||
// TODO: if its actually bad evidence, punish peer
|
||||
return err
|
||||
}
|
||||
_, val = valset.GetByAddress(addr)
|
||||
if val == nil {
|
||||
return fmt.Errorf("phantom validator %X not found", addr)
|
||||
}
|
||||
} else {
|
||||
if ae, ok := evidence.(*types.AmnesiaEvidence); ok {
|
||||
// check the validator set against the polc to make sure that a majority of valid votes was reached
|
||||
if !ae.Polc.IsAbsent() {
|
||||
err = ae.Polc.ValidateVotes(valset, state.ChainID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("amnesia evidence contains invalid polc, err: %w", err)
|
||||
}
|
||||
if ae, ok := evidence.(*types.AmnesiaEvidence); ok {
|
||||
// check the validator set against the polc to make sure that a majority of valid votes was reached
|
||||
if !ae.Polc.IsAbsent() {
|
||||
err = ae.Polc.ValidateVotes(valset, state.ChainID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("amnesia evidence contains invalid polc, err: %w", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// For all other types, expect evidence.Address to be a validator at height
|
||||
// evidence.Height.
|
||||
_, val = valset.GetByAddress(addr)
|
||||
if val == nil {
|
||||
return fmt.Errorf("address %X was not a validator at height %d", addr, evidence.Height())
|
||||
}
|
||||
// For all other types, expect evidence.Address to be a validator at height
|
||||
// evidence.Height.
|
||||
_, val = valset.GetByAddress(addr)
|
||||
if val == nil {
|
||||
return fmt.Errorf("address %X was not a validator at height %d", addr, evidence.Height())
|
||||
}
|
||||
|
||||
if err := evidence.Verify(state.ChainID, val.PubKey); err != nil {
|
||||
|
||||
@@ -16,7 +16,6 @@ import (
|
||||
"github.com/tendermint/tendermint/crypto/tmhash"
|
||||
"github.com/tendermint/tendermint/libs/log"
|
||||
memmock "github.com/tendermint/tendermint/mempool/mock"
|
||||
protostate "github.com/tendermint/tendermint/proto/tendermint/state"
|
||||
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
|
||||
sm "github.com/tendermint/tendermint/state"
|
||||
"github.com/tendermint/tendermint/state/mocks"
|
||||
@@ -622,85 +621,6 @@ func TestVerifyEvidenceWithLunaticValidatorEvidence(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestVerifyEvidenceWithPhantomValidatorEvidence(t *testing.T) {
|
||||
state, stateDB, vals := makeState(4, 4)
|
||||
state.ConsensusParams.Evidence.MaxAgeNumBlocks = 1
|
||||
addr, val := state.Validators.GetByIndex(0)
|
||||
vote := makeVote(3, 1, 0, addr, blockID)
|
||||
v := vote.ToProto()
|
||||
err := vals[val.Address.String()].SignVote(chainID, v)
|
||||
vote.Signature = v.Signature
|
||||
require.NoError(t, err)
|
||||
ev := &types.PhantomValidatorEvidence{
|
||||
Vote: vote,
|
||||
LastHeightValidatorWasInSet: 1,
|
||||
}
|
||||
err = ev.ValidateBasic()
|
||||
require.NoError(t, err)
|
||||
err = sm.VerifyEvidence(stateDB, state, ev, nil)
|
||||
if assert.Error(t, err) {
|
||||
assert.Equal(t, "address 576585A00DD4D58318255611D8AAC60E8E77CB32 was a validator at height 3", err.Error())
|
||||
}
|
||||
|
||||
privVal := types.NewMockPV()
|
||||
pubKey, _ := privVal.GetPubKey()
|
||||
vote2 := makeVote(3, 1, 0, pubKey.Address(), blockID)
|
||||
v2 := vote2.ToProto()
|
||||
err = privVal.SignVote(chainID, v2)
|
||||
vote2.Signature = v2.Signature
|
||||
require.NoError(t, err)
|
||||
ev = &types.PhantomValidatorEvidence{
|
||||
Vote: vote2,
|
||||
LastHeightValidatorWasInSet: 1,
|
||||
}
|
||||
err = ev.ValidateBasic()
|
||||
assert.NoError(t, err)
|
||||
err = sm.VerifyEvidence(stateDB, state, ev, nil)
|
||||
if assert.Error(t, err) {
|
||||
assert.Equal(t, "last time validator was in the set at height 1, min: 2", err.Error())
|
||||
}
|
||||
|
||||
ev = &types.PhantomValidatorEvidence{
|
||||
Vote: vote2,
|
||||
LastHeightValidatorWasInSet: 2,
|
||||
}
|
||||
err = ev.ValidateBasic()
|
||||
assert.NoError(t, err)
|
||||
err = sm.VerifyEvidence(stateDB, state, ev, nil)
|
||||
errMsg := "phantom validator"
|
||||
if assert.Error(t, err) {
|
||||
assert.Equal(t, errMsg, err.Error()[:len(errMsg)])
|
||||
}
|
||||
|
||||
vals2, err := sm.LoadValidators(stateDB, 2)
|
||||
require.NoError(t, err)
|
||||
vals2.Validators = append(vals2.Validators, types.NewValidator(pubKey, 1000))
|
||||
valKey := []byte("validatorsKey:2")
|
||||
protoVals, err := vals2.ToProto()
|
||||
require.NoError(t, err)
|
||||
valInfo := &protostate.ValidatorsInfo{
|
||||
LastHeightChanged: 2,
|
||||
ValidatorSet: protoVals,
|
||||
}
|
||||
|
||||
bz, err := valInfo.Marshal()
|
||||
require.NoError(t, err)
|
||||
|
||||
err = stateDB.Set(valKey, bz)
|
||||
require.NoError(t, err)
|
||||
ev = &types.PhantomValidatorEvidence{
|
||||
Vote: vote2,
|
||||
LastHeightValidatorWasInSet: 2,
|
||||
}
|
||||
err = ev.ValidateBasic()
|
||||
assert.NoError(t, err)
|
||||
err = sm.VerifyEvidence(stateDB, state, ev, nil)
|
||||
if !assert.NoError(t, err) {
|
||||
t.Log(err)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func makeVote(height int64, round, index int32, addr bytes.HexBytes, blockID types.BlockID) *types.Vote {
|
||||
return &types.Vote{
|
||||
Type: tmproto.SignedMsgType(2),
|
||||
|
||||
+3
-170
@@ -80,7 +80,7 @@ type Evidence interface {
|
||||
|
||||
type CompositeEvidence interface {
|
||||
VerifyComposite(committedHeader *Header, valSet *ValidatorSet) error
|
||||
Split(committedHeader *Header, valSet *ValidatorSet, valToLastHeight map[string]int64) []Evidence
|
||||
Split(committedHeader *Header, valSet *ValidatorSet) []Evidence
|
||||
}
|
||||
|
||||
func EvidenceToProto(evidence Evidence) (*tmproto.Evidence, error) {
|
||||
@@ -119,17 +119,6 @@ func EvidenceToProto(evidence Evidence) (*tmproto.Evidence, error) {
|
||||
|
||||
return tp, nil
|
||||
|
||||
case *PhantomValidatorEvidence:
|
||||
pbevi := evi.ToProto()
|
||||
|
||||
tp := &tmproto.Evidence{
|
||||
Sum: &tmproto.Evidence_PhantomValidatorEvidence{
|
||||
PhantomValidatorEvidence: pbevi,
|
||||
},
|
||||
}
|
||||
|
||||
return tp, nil
|
||||
|
||||
case *PotentialAmnesiaEvidence:
|
||||
pbevi := evi.ToProto()
|
||||
|
||||
@@ -172,8 +161,6 @@ func EvidenceFromProto(evidence *tmproto.Evidence) (Evidence, error) {
|
||||
return PotentialAmnesiaEvidenceFromProto(evi.PotentialAmnesiaEvidence)
|
||||
case *tmproto.Evidence_AmnesiaEvidence:
|
||||
return AmnesiaEvidenceFromProto(evi.AmnesiaEvidence)
|
||||
case *tmproto.Evidence_PhantomValidatorEvidence:
|
||||
return PhantomValidatorEvidenceFromProto(evi.PhantomValidatorEvidence)
|
||||
default:
|
||||
return nil, errors.New("evidence is not recognized")
|
||||
}
|
||||
@@ -182,7 +169,6 @@ func EvidenceFromProto(evidence *tmproto.Evidence) (Evidence, error) {
|
||||
func init() {
|
||||
tmjson.RegisterType(&DuplicateVoteEvidence{}, "tendermint/DuplicateVoteEvidence")
|
||||
tmjson.RegisterType(&ConflictingHeadersEvidence{}, "tendermint/ConflictingHeadersEvidence")
|
||||
tmjson.RegisterType(&PhantomValidatorEvidence{}, "tendermint/PhantomValidatorEvidence")
|
||||
tmjson.RegisterType(&LunaticValidatorEvidence{}, "tendermint/LunaticValidatorEvidence")
|
||||
tmjson.RegisterType(&PotentialAmnesiaEvidence{}, "tendermint/PotentialAmnesiaEvidence")
|
||||
tmjson.RegisterType(&AmnesiaEvidence{}, "tendermint/AmnesiaEvidence")
|
||||
@@ -417,17 +403,13 @@ func NewConflictingHeadersEvidence(h1, h2 *SignedHeader) *ConflictingHeadersEvid
|
||||
return &ConflictingHeadersEvidence{H1: h1, H2: h2}
|
||||
}
|
||||
|
||||
// Split breaks up evidence into smaller chunks (one per validator except for
|
||||
// PotentialAmnesiaEvidence): PhantomValidatorEvidence,
|
||||
// Split breaks up evidence into smaller chunks of evidence:
|
||||
// LunaticValidatorEvidence, DuplicateVoteEvidence and
|
||||
// PotentialAmnesiaEvidence.
|
||||
//
|
||||
// committedHeader - header at height H1.Height == H2.Height
|
||||
// valSet - validator set at height H1.Height == H2.Height
|
||||
// valToLastHeight - map between active validators and respective last heights
|
||||
func (ev *ConflictingHeadersEvidence) Split(committedHeader *Header, valSet *ValidatorSet,
|
||||
valToLastHeight map[string]int64) []Evidence {
|
||||
|
||||
func (ev *ConflictingHeadersEvidence) Split(committedHeader *Header, valSet *ValidatorSet) []Evidence {
|
||||
evList := make([]Evidence, 0)
|
||||
|
||||
var alternativeHeader *SignedHeader
|
||||
@@ -437,28 +419,6 @@ func (ev *ConflictingHeadersEvidence) Split(committedHeader *Header, valSet *Val
|
||||
alternativeHeader = ev.H1
|
||||
}
|
||||
|
||||
// If there are signers(alternativeHeader) that are not part of
|
||||
// validators(committedHeader), they misbehaved as they are signing protocol
|
||||
// messages in heights they are not validators => immediately slashable
|
||||
// (#F4).
|
||||
for i, sig := range alternativeHeader.Commit.Signatures {
|
||||
if sig.Absent() {
|
||||
continue
|
||||
}
|
||||
|
||||
lastHeightValidatorWasInSet, ok := valToLastHeight[string(sig.ValidatorAddress)]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
if !valSet.HasAddress(sig.ValidatorAddress) {
|
||||
evList = append(evList, &PhantomValidatorEvidence{
|
||||
Vote: alternativeHeader.Commit.GetVote(int32(i)),
|
||||
LastHeightValidatorWasInSet: lastHeightValidatorWasInSet,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// If ValidatorsHash, NextValidatorsHash, ConsensusHash, AppHash, and
|
||||
// LastResultsHash in alternativeHeader are different (incorrect application
|
||||
// state transition), then it is a lunatic misbehavior => immediately
|
||||
@@ -707,133 +667,6 @@ func ConflictingHeadersEvidenceFromProto(pb *tmproto.ConflictingHeadersEvidence)
|
||||
|
||||
//-------------------------------------------
|
||||
|
||||
type PhantomValidatorEvidence struct {
|
||||
Vote *Vote `json:"vote"`
|
||||
LastHeightValidatorWasInSet int64 `json:"last_height_validator_was_in_set"`
|
||||
}
|
||||
|
||||
var _ Evidence = &PhantomValidatorEvidence{}
|
||||
|
||||
// NewPhantomValidatorEvidence creates a new instance of the respective evidence
|
||||
func NewPhantomValidatorEvidence(vote *Vote, lastHeightValidatorWasInSet int64) *PhantomValidatorEvidence {
|
||||
return &PhantomValidatorEvidence{
|
||||
Vote: vote,
|
||||
LastHeightValidatorWasInSet: lastHeightValidatorWasInSet,
|
||||
}
|
||||
}
|
||||
|
||||
func (e *PhantomValidatorEvidence) Height() int64 {
|
||||
return e.Vote.Height
|
||||
}
|
||||
|
||||
func (e *PhantomValidatorEvidence) Time() time.Time {
|
||||
return e.Vote.Timestamp
|
||||
}
|
||||
|
||||
func (e *PhantomValidatorEvidence) Address() []byte {
|
||||
return e.Vote.ValidatorAddress
|
||||
}
|
||||
|
||||
func (e *PhantomValidatorEvidence) Hash() []byte {
|
||||
pbe := e.ToProto()
|
||||
|
||||
bz, err := pbe.Marshal()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return tmhash.Sum(bz)
|
||||
}
|
||||
|
||||
func (e *PhantomValidatorEvidence) Bytes() []byte {
|
||||
pbe := e.ToProto()
|
||||
|
||||
bz, err := pbe.Marshal()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return bz
|
||||
}
|
||||
|
||||
func (e *PhantomValidatorEvidence) Verify(chainID string, pubKey crypto.PubKey) error {
|
||||
|
||||
v := e.Vote.ToProto()
|
||||
if !pubKey.VerifyBytes(VoteSignBytes(chainID, v), e.Vote.Signature) {
|
||||
return errors.New("invalid signature")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *PhantomValidatorEvidence) Equal(ev Evidence) bool {
|
||||
if e2, ok := ev.(*PhantomValidatorEvidence); ok {
|
||||
return e.Vote.Height == e2.Vote.Height &&
|
||||
bytes.Equal(e.Vote.ValidatorAddress, e2.Vote.ValidatorAddress)
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func (e *PhantomValidatorEvidence) ValidateBasic() error {
|
||||
if e == nil {
|
||||
return errors.New("empty phantom validator evidence")
|
||||
}
|
||||
|
||||
if e.Vote == nil {
|
||||
return errors.New("empty vote")
|
||||
}
|
||||
|
||||
if err := e.Vote.ValidateBasic(); err != nil {
|
||||
return fmt.Errorf("invalid vote: %w", err)
|
||||
}
|
||||
|
||||
if !e.Vote.BlockID.IsComplete() {
|
||||
return errors.New("expected vote for block")
|
||||
}
|
||||
|
||||
if e.LastHeightValidatorWasInSet <= 0 {
|
||||
return errors.New("negative or zero LastHeightValidatorWasInSet")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *PhantomValidatorEvidence) String() string {
|
||||
return fmt.Sprintf("PhantomValidatorEvidence{%X voted at height %d}",
|
||||
e.Vote.ValidatorAddress, e.Vote.Height)
|
||||
}
|
||||
|
||||
func (e *PhantomValidatorEvidence) ToProto() *tmproto.PhantomValidatorEvidence {
|
||||
vpb := e.Vote.ToProto()
|
||||
|
||||
tp := &tmproto.PhantomValidatorEvidence{
|
||||
Vote: vpb,
|
||||
LastHeightValidatorWasInSet: e.LastHeightValidatorWasInSet,
|
||||
}
|
||||
|
||||
return tp
|
||||
}
|
||||
|
||||
func PhantomValidatorEvidenceFromProto(pb *tmproto.PhantomValidatorEvidence) (*PhantomValidatorEvidence, error) {
|
||||
if pb == nil {
|
||||
return nil, errors.New("nil PhantomValidatorEvidence")
|
||||
}
|
||||
|
||||
vpb, err := VoteFromProto(pb.Vote)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
tp := &PhantomValidatorEvidence{
|
||||
Vote: vpb,
|
||||
LastHeightValidatorWasInSet: pb.LastHeightValidatorWasInSet,
|
||||
}
|
||||
|
||||
return tp, tp.ValidateBasic()
|
||||
}
|
||||
|
||||
//-------------------------------------------
|
||||
|
||||
type LunaticValidatorEvidence struct {
|
||||
Header *Header `json:"header"`
|
||||
Vote *Vote `json:"vote"`
|
||||
|
||||
@@ -118,13 +118,6 @@ func TestMaxEvidenceBytes(t *testing.T) {
|
||||
// InvalidHeaderField: "",
|
||||
// }
|
||||
|
||||
// evp := &PhantomValidatorEvidence{
|
||||
// Header: makeHeaderRandom(),
|
||||
// Vote: makeVote(t, val, chainID, math.MaxInt64, math.MaxInt64, math.MaxInt64, math.MaxInt64, blockID2),
|
||||
|
||||
// LastHeightValidatorWasInSet: math.MaxInt64,
|
||||
// }
|
||||
|
||||
// signedHeader := SignedHeader{Header: makeHeaderRandom(), Commit: randCommit(time.Now())}
|
||||
// evc := &ConflictingHeadersEvidence{
|
||||
// H1: &signedHeader,
|
||||
@@ -137,7 +130,6 @@ func TestMaxEvidenceBytes(t *testing.T) {
|
||||
}{
|
||||
{"DuplicateVote", ev},
|
||||
// {"LunaticValidatorEvidence", evl},
|
||||
// {"PhantomValidatorEvidence", evp},
|
||||
// {"ConflictingHeadersEvidence", evc},
|
||||
}
|
||||
|
||||
@@ -270,33 +262,6 @@ func TestLunaticValidatorEvidence(t *testing.T) {
|
||||
|
||||
}
|
||||
|
||||
func TestPhantomValidatorEvidence(t *testing.T) {
|
||||
var (
|
||||
blockID = makeBlockIDRandom()
|
||||
header = makeHeaderRandom()
|
||||
val = NewMockPV()
|
||||
vote = makeVote(t, val, header.ChainID, 0, header.Height, 0, 2, blockID, defaultVoteTime)
|
||||
)
|
||||
|
||||
ev := NewPhantomValidatorEvidence(vote, header.Height-1)
|
||||
|
||||
assert.Equal(t, header.Height, ev.Height())
|
||||
assert.Equal(t, defaultVoteTime, ev.Time())
|
||||
assert.EqualValues(t, vote.ValidatorAddress, ev.Address())
|
||||
assert.NotEmpty(t, ev.Hash())
|
||||
assert.NotEmpty(t, ev.Bytes())
|
||||
pubKey, err := val.GetPubKey()
|
||||
require.NoError(t, err)
|
||||
assert.NoError(t, ev.Verify(header.ChainID, pubKey))
|
||||
assert.Error(t, ev.Verify("other", pubKey))
|
||||
privKey2 := ed25519.GenPrivKey()
|
||||
pubKey2 := privKey2.PubKey()
|
||||
assert.Error(t, ev.Verify("other", pubKey2))
|
||||
assert.True(t, ev.Equal(ev))
|
||||
assert.NoError(t, ev.ValidateBasic())
|
||||
assert.NotEmpty(t, ev.String())
|
||||
}
|
||||
|
||||
func TestConflictingHeadersEvidence(t *testing.T) {
|
||||
const (
|
||||
chainID = "TestConflictingHeadersEvidence"
|
||||
@@ -739,11 +704,6 @@ func TestEvidenceProto(t *testing.T) {
|
||||
{"PotentialAmnesiaEvidence nil VoteB", &PotentialAmnesiaEvidence{VoteA: v, VoteB: nil}, false, true},
|
||||
{"PotentialAmnesiaEvidence nil VoteA", &PotentialAmnesiaEvidence{VoteA: nil, VoteB: v2}, false, true},
|
||||
{"PotentialAmnesiaEvidence success", &PotentialAmnesiaEvidence{VoteA: v2, VoteB: v}, false, false},
|
||||
{"PhantomValidatorEvidence empty fail", &PhantomValidatorEvidence{}, false, true},
|
||||
{"PhantomValidatorEvidence nil LastHeightValidatorWasInSet", &PhantomValidatorEvidence{Vote: v}, false, true},
|
||||
{"PhantomValidatorEvidence nil Vote", &PhantomValidatorEvidence{LastHeightValidatorWasInSet: 2}, false, true},
|
||||
{"PhantomValidatorEvidence success", &PhantomValidatorEvidence{Vote: v2, LastHeightValidatorWasInSet: 2},
|
||||
false, false},
|
||||
{"AmnesiaEvidence nil ProofOfLockChange", &AmnesiaEvidence{PotentialAmnesiaEvidence: &PotentialAmnesiaEvidence{},
|
||||
Polc: NewEmptyPOLC()}, false, true},
|
||||
{"AmnesiaEvidence nil Polc",
|
||||
|
||||
@@ -17,7 +17,6 @@ import (
|
||||
|
||||
const (
|
||||
ABCIEvidenceTypeDuplicateVote = "duplicate/vote"
|
||||
ABCIEvidenceTypePhantom = "phantom"
|
||||
ABCIEvidenceTypeLunatic = "lunatic"
|
||||
ABCIEvidenceTypeAmnesia = "amnesia"
|
||||
)
|
||||
@@ -132,8 +131,6 @@ func (tm2pb) Evidence(ev Evidence, valSet *ValidatorSet, evTime time.Time) abci.
|
||||
switch ev.(type) {
|
||||
case *DuplicateVoteEvidence:
|
||||
evType = ABCIEvidenceTypeDuplicateVote
|
||||
case *PhantomValidatorEvidence:
|
||||
evType = ABCIEvidenceTypePhantom
|
||||
case *LunaticValidatorEvidence:
|
||||
evType = ABCIEvidenceTypeLunatic
|
||||
case *AmnesiaEvidence:
|
||||
|
||||
Reference in New Issue
Block a user