-
Notifications
You must be signed in to change notification settings - Fork 212
/
util.go
117 lines (103 loc) · 2.66 KB
/
util.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
108
109
110
111
112
113
114
115
116
117
package tortoise
import (
"sort"
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
"github.com/spacemeshos/go-spacemesh/common/types"
)
const (
support sign = 1
against sign = -1
abstain sign = 0
neutral = abstain
)
type sign int8
func (a sign) String() string {
switch a {
case 1:
return "support"
case -1:
return "against"
case 0:
return "abstain"
default:
panic("sign should be 0/-1/1")
}
}
type voteReason string
func (v voteReason) String() string {
return string(v)
}
const (
reasonHareOutput voteReason = "hare"
reasonValidity voteReason = "validity"
reasonLocalThreshold voteReason = "local_threshold"
reasonCoinflip voteReason = "coinflip"
reasonMissingData voteReason = "missing data"
)
func maxLayer(i, j types.LayerID) types.LayerID {
if i.After(j) {
return i
}
return j
}
func verifyLayer(logger *zap.Logger, blocks []*blockInfo, getDecision func(*blockInfo) sign) (bool, bool) {
// order blocks by height in ascending order
// if there is a support before any abstain
// and a previous height is lower than the current one
// the layer is verified
//
// it will modify original slice
sort.Slice(blocks, func(i, j int) bool {
return blocks[i].height < blocks[j].height
})
var (
decisions = make([]sign, 0, len(blocks))
supported *blockInfo
)
for i, block := range blocks {
decision := getDecision(block)
logger.Debug("decision for a block",
zap.Int("ith", i),
zap.Stringer("block", block.id),
zap.Stringer("lid", block.layer),
zap.Stringer("decision", decision),
zap.Stringer("weight", block.margin),
zap.Uint64("height", block.height),
)
if decision == abstain {
// all blocks with the same height should be finalized
if supported != nil && block.height > supported.height {
decision = against
} else {
return false, false
}
} else if decision == support {
supported = block
}
decisions = append(decisions, decision)
}
changes := false
for i, decision := range decisions {
if blocks[i].validity != decision {
changes = true
}
blocks[i].validity = decision
}
return true, changes
}
func zapBlocks(blocks []*blockInfo) zap.Field {
return zap.Array("blocks", zapcore.ArrayMarshalerFunc(func(encoder zapcore.ArrayEncoder) error {
for i := range blocks {
encoder.AppendObject(zapcore.ObjectMarshalerFunc(func(encoder zapcore.ObjectEncoder) error {
encoder.AddString("decision", blocks[i].validity.String())
encoder.AddString("id", blocks[i].id.String())
encoder.AddString("weight", blocks[i].margin.String())
encoder.AddUint64("height", blocks[i].height)
encoder.AddBool("data", blocks[i].data)
return nil
}))
}
return nil
}))
}