-
Notifications
You must be signed in to change notification settings - Fork 212
/
algorithm.go
83 lines (70 loc) · 2.59 KB
/
algorithm.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
package tortoise
import (
"github.com/spacemeshos/go-spacemesh/common/types"
"github.com/spacemeshos/go-spacemesh/log"
"github.com/spacemeshos/go-spacemesh/mesh"
)
// Tortoise represents an instance of a vote counting algorithm
type Tortoise interface {
HandleLateBlock(b *types.Block) (types.LayerID, types.LayerID)
HandleIncomingLayer(ll *types.Layer) (types.LayerID, types.LayerID)
LatestComplete() types.LayerID
Persist() error
}
type tortoise struct {
*ninjaTortoise
}
// NewTortoise returns a new Tortoise instance
func NewTortoise(layerSize int, mdb *mesh.DB, hdist int, lg log.Log) Tortoise {
alg := &tortoise{ninjaTortoise: newNinjaTortoise(layerSize, mdb, hdist, lg)}
alg.HandleIncomingLayer(mesh.GenesisLayer())
return alg
}
// NewRecoveredTortoise recovers a previously persisted tortoise copy from mesh.DB
func NewRecoveredTortoise(mdb *mesh.DB, lg log.Log) Tortoise {
tmp, err := RecoverTortoise(mdb)
if err != nil {
lg.Panic("could not recover tortoise state from disc ", err)
}
trtl := tmp.(*ninjaTortoise)
lg.Info("recovered tortoise from disc")
trtl.db = mdb
trtl.logger = lg
return &tortoise{ninjaTortoise: trtl}
}
// HandleLateBlock processes a late blocks votes (for late block definition see white paper)
// returns the old pbase and new pbase after taking into account the blocks votes
func (trtl *tortoise) HandleLateBlock(b *types.Block) (types.LayerID, types.LayerID) {
//todo feed all layers from b's layer to tortoise
l := types.NewLayer(b.Layer())
l.AddBlock(b)
oldPbase, newPbase := trtl.HandleIncomingLayer(l)
log.With().Info("late block", b.Layer(), b.ID())
return oldPbase, newPbase
}
// Persist saves a copy of the current tortoise state to the database
func (trtl *tortoise) Persist() error {
trtl.mutex.Lock()
defer trtl.mutex.Unlock()
trtl.logger.With().Info("persist tortoise", trtl.PBase)
return trtl.ninjaTortoise.persist()
}
// HandleIncomingLayer processes all layer block votes
// returns the old pbase and new pbase after taking into account the blocks votes
func (trtl *tortoise) HandleIncomingLayer(ll *types.Layer) (types.LayerID, types.LayerID) {
trtl.mutex.Lock()
defer trtl.mutex.Unlock()
oldPbase := trtl.latestComplete()
trtl.ninjaTortoise.handleIncomingLayer(ll)
newPbase := trtl.latestComplete()
updateMetrics(trtl, ll)
return oldPbase, newPbase
}
// LatestComplete returns the latest complete (a.k.a irreversible) layer
func (trtl *tortoise) LatestComplete() types.LayerID {
return trtl.latestComplete()
}
func updateMetrics(alg *tortoise, ll *types.Layer) {
pbaseCount.Set(float64(alg.latestComplete()))
processedCount.Set(float64(ll.Index()))
}