types: evidence cleanup

This commit is contained in:
Ethan Buchman
2017-11-19 22:18:43 +00:00
parent 4854c231e1
commit 3271634e7a
5 changed files with 24 additions and 88 deletions

View File

@ -309,7 +309,7 @@ func (s *State) validateBlock(b *types.Block) error {
} }
} }
for _, ev := range block.Evidence.Evidences { for _, ev := range block.Evidence.Evidence {
if _, err := s.VerifyEvidence(ev); err != nil { if _, err := s.VerifyEvidence(ev); err != nil {
return types.NewEvidenceInvalidErr(ev, err) return types.NewEvidenceInvalidErr(ev, err)
} }

View File

@ -386,7 +386,7 @@ func (s *State) GetValidators() (last *types.ValidatorSet, current *types.Valida
// VerifyEvidence verifies the evidence fully by checking it is internally // VerifyEvidence verifies the evidence fully by checking it is internally
// consistent and corresponds to an existing or previous validator. // consistent and corresponds to an existing or previous validator.
// It returns the priority of this evidence, or an error. // It returns the priority of this evidence, or an error.
// NOTE: return error may be ErrLoadValidators, in which case the validator set // NOTE: return error may be ErrNoValSetForHeight, in which case the validator set
// for the evidence height could not be loaded. // for the evidence height could not be loaded.
func (s *State) VerifyEvidence(evidence types.Evidence) (priority int, err error) { func (s *State) VerifyEvidence(evidence types.Evidence) (priority int, err error) {
if err := evidence.Verify(s.ChainID); err != nil { if err := evidence.Verify(s.ChainID); err != nil {

View File

@ -43,7 +43,7 @@ func MakeBlock(height int64, txs []Tx, commit *Commit) *Block {
// AddEvidence appends the given evidence to the block // AddEvidence appends the given evidence to the block
func (b *Block) AddEvidence(evidence []Evidence) { func (b *Block) AddEvidence(evidence []Evidence) {
b.Evidence.Evidences = append(b.Evidence.Evidences, evidence...) b.Evidence.Evidence = append(b.Evidence.Evidence, evidence...)
} }
// ValidateBasic performs basic validation that doesn't involve state data. // ValidateBasic performs basic validation that doesn't involve state data.
@ -437,8 +437,7 @@ func (data *Data) StringIndented(indent string) string {
// EvidenceData contains any evidence of malicious wrong-doing by validators // EvidenceData contains any evidence of malicious wrong-doing by validators
type EvidenceData struct { type EvidenceData struct {
// TODO: FIXME Evidence EvidenceList `json:"evidence"`
Evidences evidences `json:"evidence"`
// Volatile // Volatile
hash data.Bytes hash data.Bytes
@ -447,7 +446,7 @@ type EvidenceData struct {
// Hash returns the hash of the data. // Hash returns the hash of the data.
func (data *EvidenceData) Hash() data.Bytes { func (data *EvidenceData) Hash() data.Bytes {
if data.hash == nil { if data.hash == nil {
data.hash = data.Evidences.Hash() data.hash = data.Evidence.Hash()
} }
return data.hash return data.hash
} }
@ -457,10 +456,10 @@ func (data *EvidenceData) StringIndented(indent string) string {
if data == nil { if data == nil {
return "nil-Evidence" return "nil-Evidence"
} }
evStrings := make([]string, cmn.MinInt(len(data.Evidences), 21)) evStrings := make([]string, cmn.MinInt(len(data.Evidence), 21))
for i, ev := range data.Evidences { for i, ev := range data.Evidence {
if i == 20 { if i == 20 {
evStrings[i] = fmt.Sprintf("... (%v total)", len(data.Evidences)) evStrings[i] = fmt.Sprintf("... (%v total)", len(data.Evidence))
break break
} }
evStrings[i] = fmt.Sprintf("Evidence:%v", ev) evStrings[i] = fmt.Sprintf("Evidence:%v", ev)

View File

@ -3,7 +3,6 @@ package types
import ( import (
"bytes" "bytes"
"fmt" "fmt"
"sync"
"github.com/tendermint/go-crypto" "github.com/tendermint/go-crypto"
"github.com/tendermint/tmlibs/merkle" "github.com/tendermint/tmlibs/merkle"
@ -26,10 +25,6 @@ func (err *ErrEvidenceInvalid) Error() string {
//------------------------------------------- //-------------------------------------------
type HistoricalValidators interface {
LoadValidators(height int) (*ValidatorSet, error)
}
// Evidence represents any provable malicious activity by a validator // Evidence represents any provable malicious activity by a validator
type Evidence interface { type Evidence interface {
Height() int // height of the equivocation Height() int // height of the equivocation
@ -44,96 +39,36 @@ type Evidence interface {
//------------------------------------------- //-------------------------------------------
//EvidenceSet is a thread-safe set of evidence. // EvidenceList is a list of Evidence. Evidences is not a word.
type EvidenceSet struct { type EvidenceList []Evidence
sync.RWMutex
evidences evidences
}
//Evidence returns a copy of all the evidence. // Hash returns the simple merkle root hash of the EvidenceList.
func (evset EvidenceSet) Evidence() []Evidence { func (evl EvidenceList) Hash() []byte {
evset.RLock()
defer evset.RUnlock()
evCopy := make([]Evidence, len(evset.evidences))
for i, ev := range evset.evidences {
evCopy[i] = ev
}
return evCopy
}
// Size returns the number of pieces of evidence in the set.
func (evset EvidenceSet) Size() int {
evset.RLock()
defer evset.RUnlock()
return len(evset.evidences)
}
// Hash returns a merkle hash of the evidence.
func (evset EvidenceSet) Hash() []byte {
evset.RLock()
defer evset.RUnlock()
return evset.evidences.Hash()
}
// Has returns true if the given evidence is in the set.
func (evset EvidenceSet) Has(evidence Evidence) bool {
evset.RLock()
defer evset.RUnlock()
return evset.evidences.Has(evidence)
}
// String returns a string representation of the evidence.
func (evset EvidenceSet) String() string {
evset.RLock()
defer evset.RUnlock()
return evset.evidences.String()
}
// Add adds the given evidence to the set.
// TODO: and persists it to disk.
func (evset EvidenceSet) Add(evidence Evidence) {
evset.Lock()
defer evset.Unlock()
evset.evidences = append(evset.evidences, evidence)
}
// Reset empties the evidence set.
func (evset EvidenceSet) Reset() {
evset.Lock()
defer evset.Unlock()
evset.evidences = make(evidences, 0)
}
//-------------------------------------------
type evidences []Evidence
func (evs evidences) Hash() []byte {
// Recursive impl. // Recursive impl.
// Copied from tmlibs/merkle to avoid allocations // Copied from tmlibs/merkle to avoid allocations
switch len(evs) { switch len(evl) {
case 0: case 0:
return nil return nil
case 1: case 1:
return evs[0].Hash() return evl[0].Hash()
default: default:
left := evidences(evs[:(len(evs)+1)/2]).Hash() left := EvidenceList(evl[:(len(evl)+1)/2]).Hash()
right := evidences(evs[(len(evs)+1)/2:]).Hash() right := EvidenceList(evl[(len(evl)+1)/2:]).Hash()
return merkle.SimpleHashFromTwoHashes(left, right) return merkle.SimpleHashFromTwoHashes(left, right)
} }
} }
func (evs evidences) String() string { func (evl EvidenceList) String() string {
s := "" s := ""
for _, e := range evs { for _, e := range evl {
s += fmt.Sprintf("%s\t\t", e) s += fmt.Sprintf("%s\t\t", e)
} }
return s return s
} }
func (evs evidences) Has(evidence Evidence) bool { // Has returns true if the evidence is in the EvidenceList.
for _, ev := range evs { func (evl EvidenceList) Has(evidence Evidence) bool {
for _, ev := range evl {
if ev.Equal(evidence) { if ev.Equal(evidence) {
return true return true
} }

View File

@ -4,7 +4,7 @@ import (
abci "github.com/tendermint/abci/types" abci "github.com/tendermint/abci/types"
) )
// NOTE: all types in this file are considered UNSTABLE // NOTE/XXX: all type definitions in this file are considered UNSTABLE
//------------------------------------------------------ //------------------------------------------------------
// blockchain services types // blockchain services types
@ -73,6 +73,8 @@ type BlockStore interface {
//------------------------------------------------------ //------------------------------------------------------
// state // state
// State defines the stateful interface used to verify evidence.
// UNSTABLE
type State interface { type State interface {
VerifyEvidence(Evidence) (priority int, err error) VerifyEvidence(Evidence) (priority int, err error)
} }