diff --git a/CHANGELOG_PENDING.md b/CHANGELOG_PENDING.md index 0f60620d0..70895dbec 100644 --- a/CHANGELOG_PENDING.md +++ b/CHANGELOG_PENDING.md @@ -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) \ No newline at end of file diff --git a/docs/architecture/adr-047-handling-evidence-from-light-client.md b/docs/architecture/adr-047-handling-evidence-from-light-client.md index 0f2566fd0..f5aaa828c 100644 --- a/docs/architecture/adr-047-handling-evidence-from-light-client.md +++ b/docs/architecture/adr-047-handling-evidence-from-light-client.md @@ -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. diff --git a/evidence/pool.go b/evidence/pool.go index 4b8a10103..a1ec01da8 100644 --- a/evidence/pool.go +++ b/evidence/pool.go @@ -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) diff --git a/evidence/pool_test.go b/evidence/pool_test.go index dde440371..09d848bcd 100644 --- a/evidence/pool_test.go +++ b/evidence/pool_test.go @@ -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) { diff --git a/proto/tendermint/types/evidence.pb.go b/proto/tendermint/types/evidence.pb.go index db6bbd0e2..0939e1fce 100644 --- a/proto/tendermint/types/evidence.pb.go +++ b/proto/tendermint/types/evidence.pb.go @@ -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:]) diff --git a/proto/tendermint/types/evidence.proto b/proto/tendermint/types/evidence.proto index 782f4cdcb..31744a938 100644 --- a/proto/tendermint/types/evidence.proto +++ b/proto/tendermint/types/evidence.proto @@ -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; } } diff --git a/state/validation.go b/state/validation.go index 3d21b7c83..6faa275d9 100644 --- a/state/validation.go +++ b/state/validation.go @@ -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 { diff --git a/state/validation_test.go b/state/validation_test.go index be4264943..a6e4c3ee4 100644 --- a/state/validation_test.go +++ b/state/validation_test.go @@ -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), diff --git a/types/evidence.go b/types/evidence.go index 091a11687..b65ac9311 100644 --- a/types/evidence.go +++ b/types/evidence.go @@ -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"` diff --git a/types/evidence_test.go b/types/evidence_test.go index dfc144fd6..a6e16bc5f 100644 --- a/types/evidence_test.go +++ b/types/evidence_test.go @@ -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", diff --git a/types/protobuf.go b/types/protobuf.go index c125528c2..9dbe9d430 100644 --- a/types/protobuf.go +++ b/types/protobuf.go @@ -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: