mirror of
https://github.com/tendermint/tendermint.git
synced 2026-01-05 13:05:09 +00:00
evidence: modularise evidence by moving verification function into evidence package (#5234)
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
package evidence
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"sync"
|
||||
"time"
|
||||
@@ -31,7 +32,7 @@ type Pool struct {
|
||||
evidenceList *clist.CList // concurrent linked-list of evidence
|
||||
|
||||
// needed to load validators to verify evidence
|
||||
stateDB dbm.DB
|
||||
stateDB StateStore
|
||||
// needed to load headers to verify evidence
|
||||
blockStore BlockStore
|
||||
|
||||
@@ -45,11 +46,11 @@ type Pool struct {
|
||||
nextEvidenceTrialEndedHeight 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 BlockStore) (*Pool, error) {
|
||||
// NewPool creates an evidence pool. If using an existing evidence store,
|
||||
// it will add all pending evidence to the concurrent list.
|
||||
func NewPool(evidenceDB dbm.DB, stateDB StateStore, blockStore BlockStore) (*Pool, error) {
|
||||
var (
|
||||
state = sm.LoadState(stateDB)
|
||||
state = stateDB.LoadState()
|
||||
)
|
||||
|
||||
pool := &Pool{
|
||||
@@ -145,14 +146,11 @@ func (evpool *Pool) AddPOLC(polc *types.ProofOfLockChange) error {
|
||||
// evidence is composite (ConflictingHeadersEvidence), it will be broken up
|
||||
// into smaller pieces.
|
||||
func (evpool *Pool) AddEvidence(evidence types.Evidence) error {
|
||||
var (
|
||||
state = evpool.State()
|
||||
evList = []types.Evidence{evidence}
|
||||
)
|
||||
var evList = []types.Evidence{evidence}
|
||||
|
||||
evpool.logger.Debug("Attempting to add evidence", "ev", evidence)
|
||||
|
||||
valSet, err := sm.LoadValidators(evpool.stateDB, evidence.Height())
|
||||
valSet, err := evpool.stateDB.LoadValidators(evidence.Height())
|
||||
if err != nil {
|
||||
return fmt.Errorf("can't load validators at height #%d: %w", evidence.Height(), err)
|
||||
}
|
||||
@@ -177,36 +175,14 @@ func (evpool *Pool) AddEvidence(evidence types.Evidence) error {
|
||||
|
||||
if evpool.Has(ev) {
|
||||
// if it is an amnesia evidence we have but POLC is not absent then
|
||||
// we should still process it
|
||||
// we should still process it else we loop to the next piece of evidence
|
||||
if ae, ok := ev.(*types.AmnesiaEvidence); !ok || ae.Polc.IsAbsent() {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
// A header needs to be fetched. For lunatic evidence this is so we can verify
|
||||
// that some of the fields are different to the ones we have. For all evidence it
|
||||
// it so we can verify that the time of the evidence is correct
|
||||
|
||||
var header *types.Header
|
||||
// if the evidence is from the current height - this means the evidence is fresh from the consensus
|
||||
// and we won't have it in the block store. We thus check that the time isn't before the previous block
|
||||
if ev.Height() == evpool.State().LastBlockHeight+1 {
|
||||
if ev.Time().Before(evpool.State().LastBlockTime) {
|
||||
return fmt.Errorf("evidence is from an earlier time than the previous block: %v < %v",
|
||||
ev.Time(),
|
||||
evpool.State().LastBlockTime)
|
||||
}
|
||||
header = &types.Header{Time: ev.Time()}
|
||||
} else { // if the evidence is from a prior height
|
||||
header = evpool.Header(ev.Height())
|
||||
if header == nil {
|
||||
return fmt.Errorf("don't have header at height #%d", ev.Height())
|
||||
}
|
||||
}
|
||||
|
||||
// 1) Verify against state.
|
||||
if err := sm.VerifyEvidence(evpool.stateDB, state, ev, header); err != nil {
|
||||
evpool.logger.Debug("Inbound evidence is invalid", "evidence", ev, "err", err)
|
||||
if err := evpool.verify(ev); err != nil {
|
||||
return types.NewErrEvidenceInvalid(ev, err)
|
||||
}
|
||||
|
||||
@@ -256,6 +232,37 @@ func (evpool *Pool) AddEvidence(evidence types.Evidence) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Verify verifies the evidence against the node's (or evidence pool's) state. More specifically, to validate
|
||||
// evidence against state is to validate it against the nodes own header and validator set for that height. This ensures
|
||||
// as well as meeting the evidence's own validation rules, that the evidence hasn't expired, that the validator is still
|
||||
// bonded and that the evidence can be committed to the chain.
|
||||
func (evpool *Pool) Verify(evidence types.Evidence) error {
|
||||
if evpool.IsCommitted(evidence) {
|
||||
return errors.New("evidence was already committed")
|
||||
}
|
||||
// We have already verified this piece of evidence - no need to do it again
|
||||
if evpool.IsPending(evidence) {
|
||||
return nil
|
||||
}
|
||||
|
||||
// if we don't already have amnesia evidence we need to add it to start our own trial period unless
|
||||
// a) a valid polc has already been attached
|
||||
// b) the accused node voted back on an earlier round
|
||||
if ae, ok := evidence.(*types.AmnesiaEvidence); ok && ae.Polc.IsAbsent() && ae.PotentialAmnesiaEvidence.VoteA.Round <
|
||||
ae.PotentialAmnesiaEvidence.VoteB.Round {
|
||||
if err := evpool.AddEvidence(ae.PotentialAmnesiaEvidence); err != nil {
|
||||
return fmt.Errorf("unknown amnesia evidence, trying to add to evidence pool, err: %w", err)
|
||||
}
|
||||
return errors.New("amnesia evidence is new and hasn't undergone trial period yet")
|
||||
}
|
||||
|
||||
return evpool.verify(evidence)
|
||||
}
|
||||
|
||||
func (evpool *Pool) verify(evidence types.Evidence) error {
|
||||
return VerifyEvidence(evidence, evpool.State(), evpool.stateDB, evpool.blockStore)
|
||||
}
|
||||
|
||||
// MarkEvidenceAsCommitted marks all the evidence as committed and removes it
|
||||
// from the queue.
|
||||
func (evpool *Pool) MarkEvidenceAsCommitted(height int64, evidence []types.Evidence) {
|
||||
@@ -543,7 +550,7 @@ func (evpool *Pool) pruneExpiredPOLC() {
|
||||
evpool.logger.Error("Unable to transition POLC from protobuf", "err", err)
|
||||
continue
|
||||
}
|
||||
if !evpool.IsExpired(proof.Height()-1, proof.Time()) {
|
||||
if !evpool.IsExpired(proof.Height(), proof.Time()) {
|
||||
return
|
||||
}
|
||||
err = evpool.evidenceStore.Delete(iter.Key())
|
||||
|
||||
Reference in New Issue
Block a user