Skip to content

Commit b7f6e47

Browse files
authoredAug 20, 2020
evidence: modularise evidence by moving verification function into evidence package (#5234)

19 files changed

+546
-717
lines changed
 

‎consensus/byzantine_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ func TestByzantinePrevoteEquivocation(t *testing.T) {
7070

7171
// Make a full instance of the evidence pool
7272
evidenceDB := dbm.NewMemDB()
73-
evpool, err := evidence.NewPool(stateDB, evidenceDB, blockStore)
73+
evpool, err := evidence.NewPool(evidenceDB, evidence.NewEvidenceStateStore(stateDB), blockStore)
7474
require.NoError(t, err)
7575
evpool.SetLogger(logger.With("module", "evidence"))
7676

‎consensus/common_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -452,7 +452,7 @@ func randStateWithEvpool(t *testing.T, nValidators int) (*State, []*validatorStu
452452
}
453453
stateDB := dbm.NewMemDB()
454454
sm.SaveState(stateDB, state)
455-
evpool, err := evidence.NewPool(stateDB, evidenceDB, blockStore)
455+
evpool, err := evidence.NewPool(evidenceDB, evidence.NewEvidenceStateStore(stateDB), blockStore)
456456
require.NoError(t, err)
457457
blockExec := sm.NewBlockExecutor(stateDB, log.TestingLogger(), proxyAppConnCon, mempool, evpool)
458458
cs := NewState(config.Consensus, state, blockExec, blockStore, mempool, evpool)

‎consensus/reactor_test.go

+1-12
Original file line numberDiff line numberDiff line change
@@ -224,19 +224,8 @@ func (m *mockEvidencePool) Update(block *types.Block, state sm.State) {
224224
}
225225
m.height++
226226
}
227-
func (m *mockEvidencePool) IsCommitted(types.Evidence) bool { return false }
228-
func (m *mockEvidencePool) IsPending(evidence types.Evidence) bool {
229-
if m.height > 0 {
230-
for _, e := range m.ev {
231-
if e.Equal(evidence) {
232-
return true
233-
}
234-
}
235-
}
236-
return false
237-
}
227+
func (m *mockEvidencePool) Verify(types.Evidence) error { return nil }
238228
func (m *mockEvidencePool) AddPOLC(*types.ProofOfLockChange) error { return nil }
239-
func (m *mockEvidencePool) Header(int64) *types.Header { return &types.Header{Time: defaultTestTime} }
240229

241230
//------------------------------------
242231

‎consensus/replay_stubs.go

+1
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ var _ sm.EvidencePool = emptyEvidencePool{}
5454
func (emptyEvidencePool) PendingEvidence(uint32) []types.Evidence { return nil }
5555
func (emptyEvidencePool) AddEvidence(types.Evidence) error { return nil }
5656
func (emptyEvidencePool) Update(*types.Block, sm.State) {}
57+
func (emptyEvidencePool) Verify(types.Evidence) error { return nil }
5758
func (emptyEvidencePool) IsCommitted(types.Evidence) bool { return false }
5859
func (emptyEvidencePool) IsPending(types.Evidence) bool { return false }
5960
func (emptyEvidencePool) AddPOLC(*types.ProofOfLockChange) error { return nil }

‎evidence/mocks/block_store.go

-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎evidence/pool.go

+42-35
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package evidence
22

33
import (
4+
"errors"
45
"fmt"
56
"sync"
67
"time"
@@ -31,7 +32,7 @@ type Pool struct {
3132
evidenceList *clist.CList // concurrent linked-list of evidence
3233

3334
// needed to load validators to verify evidence
34-
stateDB dbm.DB
35+
stateDB StateStore
3536
// needed to load headers to verify evidence
3637
blockStore BlockStore
3738

@@ -45,11 +46,11 @@ type Pool struct {
4546
nextEvidenceTrialEndedHeight int64
4647
}
4748

48-
// Creates a new pool. If using an existing evidence store, it will add all pending evidence
49-
// to the concurrent list.
50-
func NewPool(stateDB, evidenceDB dbm.DB, blockStore BlockStore) (*Pool, error) {
49+
// NewPool creates an evidence pool. If using an existing evidence store,
50+
// it will add all pending evidence to the concurrent list.
51+
func NewPool(evidenceDB dbm.DB, stateDB StateStore, blockStore BlockStore) (*Pool, error) {
5152
var (
52-
state = sm.LoadState(stateDB)
53+
state = stateDB.LoadState()
5354
)
5455

5556
pool := &Pool{
@@ -145,14 +146,11 @@ func (evpool *Pool) AddPOLC(polc *types.ProofOfLockChange) error {
145146
// evidence is composite (ConflictingHeadersEvidence), it will be broken up
146147
// into smaller pieces.
147148
func (evpool *Pool) AddEvidence(evidence types.Evidence) error {
148-
var (
149-
state = evpool.State()
150-
evList = []types.Evidence{evidence}
151-
)
149+
var evList = []types.Evidence{evidence}
152150

153151
evpool.logger.Debug("Attempting to add evidence", "ev", evidence)
154152

155-
valSet, err := sm.LoadValidators(evpool.stateDB, evidence.Height())
153+
valSet, err := evpool.stateDB.LoadValidators(evidence.Height())
156154
if err != nil {
157155
return fmt.Errorf("can't load validators at height #%d: %w", evidence.Height(), err)
158156
}
@@ -177,36 +175,14 @@ func (evpool *Pool) AddEvidence(evidence types.Evidence) error {
177175

178176
if evpool.Has(ev) {
179177
// if it is an amnesia evidence we have but POLC is not absent then
180-
// we should still process it
178+
// we should still process it else we loop to the next piece of evidence
181179
if ae, ok := ev.(*types.AmnesiaEvidence); !ok || ae.Polc.IsAbsent() {
182180
continue
183181
}
184182
}
185183

186-
// A header needs to be fetched. For lunatic evidence this is so we can verify
187-
// that some of the fields are different to the ones we have. For all evidence it
188-
// it so we can verify that the time of the evidence is correct
189-
190-
var header *types.Header
191-
// if the evidence is from the current height - this means the evidence is fresh from the consensus
192-
// and we won't have it in the block store. We thus check that the time isn't before the previous block
193-
if ev.Height() == evpool.State().LastBlockHeight+1 {
194-
if ev.Time().Before(evpool.State().LastBlockTime) {
195-
return fmt.Errorf("evidence is from an earlier time than the previous block: %v < %v",
196-
ev.Time(),
197-
evpool.State().LastBlockTime)
198-
}
199-
header = &types.Header{Time: ev.Time()}
200-
} else { // if the evidence is from a prior height
201-
header = evpool.Header(ev.Height())
202-
if header == nil {
203-
return fmt.Errorf("don't have header at height #%d", ev.Height())
204-
}
205-
}
206-
207184
// 1) Verify against state.
208-
if err := sm.VerifyEvidence(evpool.stateDB, state, ev, header); err != nil {
209-
evpool.logger.Debug("Inbound evidence is invalid", "evidence", ev, "err", err)
185+
if err := evpool.verify(ev); err != nil {
210186
return types.NewErrEvidenceInvalid(ev, err)
211187
}
212188

@@ -256,6 +232,37 @@ func (evpool *Pool) AddEvidence(evidence types.Evidence) error {
256232
return nil
257233
}
258234

235+
// Verify verifies the evidence against the node's (or evidence pool's) state. More specifically, to validate
236+
// evidence against state is to validate it against the nodes own header and validator set for that height. This ensures
237+
// as well as meeting the evidence's own validation rules, that the evidence hasn't expired, that the validator is still
238+
// bonded and that the evidence can be committed to the chain.
239+
func (evpool *Pool) Verify(evidence types.Evidence) error {
240+
if evpool.IsCommitted(evidence) {
241+
return errors.New("evidence was already committed")
242+
}
243+
// We have already verified this piece of evidence - no need to do it again
244+
if evpool.IsPending(evidence) {
245+
return nil
246+
}
247+
248+
// if we don't already have amnesia evidence we need to add it to start our own trial period unless
249+
// a) a valid polc has already been attached
250+
// b) the accused node voted back on an earlier round
251+
if ae, ok := evidence.(*types.AmnesiaEvidence); ok && ae.Polc.IsAbsent() && ae.PotentialAmnesiaEvidence.VoteA.Round <
252+
ae.PotentialAmnesiaEvidence.VoteB.Round {
253+
if err := evpool.AddEvidence(ae.PotentialAmnesiaEvidence); err != nil {
254+
return fmt.Errorf("unknown amnesia evidence, trying to add to evidence pool, err: %w", err)
255+
}
256+
return errors.New("amnesia evidence is new and hasn't undergone trial period yet")
257+
}
258+
259+
return evpool.verify(evidence)
260+
}
261+
262+
func (evpool *Pool) verify(evidence types.Evidence) error {
263+
return VerifyEvidence(evidence, evpool.State(), evpool.stateDB, evpool.blockStore)
264+
}
265+
259266
// MarkEvidenceAsCommitted marks all the evidence as committed and removes it
260267
// from the queue.
261268
func (evpool *Pool) MarkEvidenceAsCommitted(height int64, evidence []types.Evidence) {
@@ -543,7 +550,7 @@ func (evpool *Pool) pruneExpiredPOLC() {
543550
evpool.logger.Error("Unable to transition POLC from protobuf", "err", err)
544551
continue
545552
}
546-
if !evpool.IsExpired(proof.Height()-1, proof.Time()) {
553+
if !evpool.IsExpired(proof.Height(), proof.Time()) {
547554
return
548555
}
549556
err = evpool.evidenceStore.Delete(iter.Key())

0 commit comments

Comments
 (0)
Please sign in to comment.