/
indexed_lachesis.go
107 lines (89 loc) · 2.89 KB
/
indexed_lachesis.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
package abft
import (
"math/big"
"github.com/ethereum/go-ethereum/common"
"github.com/Deepchain-foundation/lachesis-base/abft/dagidx"
"github.com/Deepchain-foundation/lachesis-base/hash"
"github.com/Deepchain-foundation/lachesis-base/inter/dag"
"github.com/Deepchain-foundation/lachesis-base/inter/idx"
"github.com/Deepchain-foundation/lachesis-base/inter/pos"
"github.com/Deepchain-foundation/lachesis-base/kvdb"
"github.com/Deepchain-foundation/lachesis-base/lachesis"
)
var _ lachesis.Consensus = (*IndexedLachesis)(nil)
// IndexedLachesis performs events ordering and detects cheaters
// It's a wrapper around Orderer, which adds features which might potentially be application-specific:
// confirmed events traversal, DAG index updates and cheaters detection.
// Use this structure if need a general-purpose consensus. Instead, use lower-level abft.Orderer.
type IndexedLachesis struct {
*Lachesis
dagIndexer DagIndexer
uniqueDirtyID uniqueID
}
type DagIndexer interface {
dagidx.VectorClock
dagidx.ForklessCause
Add(dag.Event) error
Flush()
DropNotFlushed()
Reset(validators *pos.Validators, db kvdb.Store, getEvent func(hash.Event) dag.Event)
}
// New creates IndexedLachesis instance.
func NewIndexedLachesis(store *Store, input EventSource, dagIndexer DagIndexer, crit func(error), config Config) *IndexedLachesis {
p := &IndexedLachesis{
Lachesis: NewLachesis(store, input, dagIndexer, crit, config),
dagIndexer: dagIndexer,
uniqueDirtyID: uniqueID{new(big.Int)},
}
return p
}
// Build fills consensus-related fields: Frame, IsRoot
// returns error if event should be dropped
func (p *IndexedLachesis) Build(e dag.MutableEvent) error {
e.SetID(p.uniqueDirtyID.sample())
defer p.dagIndexer.DropNotFlushed()
err := p.dagIndexer.Add(e)
if err != nil {
return err
}
return p.Lachesis.Build(e)
}
// Process takes event into processing.
// Event order matter: parents first.
// All the event checkers must be launched.
// Process is not safe for concurrent use.
func (p *IndexedLachesis) Process(e dag.Event) (err error) {
defer p.dagIndexer.DropNotFlushed()
err = p.dagIndexer.Add(e)
if err != nil {
return err
}
err = p.Lachesis.Process(e)
if err != nil {
return err
}
p.dagIndexer.Flush()
return nil
}
func (p *IndexedLachesis) Bootstrap(callback lachesis.ConsensusCallbacks) error {
base := p.Lachesis.OrdererCallbacks()
ordererCallbacks := OrdererCallbacks{
ApplyAtropos: base.ApplyAtropos,
EpochDBLoaded: func(epoch idx.Epoch) {
if base.EpochDBLoaded != nil {
base.EpochDBLoaded(epoch)
}
p.dagIndexer.Reset(p.store.GetValidators(), p.store.epochTable.VectorIndex, p.input.GetEvent)
},
}
return p.Lachesis.BootstrapWithOrderer(callback, ordererCallbacks)
}
type uniqueID struct {
counter *big.Int
}
func (u *uniqueID) sample() [24]byte {
u.counter = u.counter.Add(u.counter, common.Big1)
var id [24]byte
copy(id[:], u.counter.Bytes())
return id
}