-
Notifications
You must be signed in to change notification settings - Fork 211
/
verifying.go
135 lines (121 loc) · 3.91 KB
/
verifying.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
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
package tortoise
import (
"time"
"go.uber.org/zap"
"github.com/spacemeshos/go-spacemesh/common/types"
"github.com/spacemeshos/go-spacemesh/log"
)
func newVerifying(config Config, state *state) *verifying {
return &verifying{
Config: config,
state: state,
}
}
type verifying struct {
Config
*state
// total weight of good ballots from verified + 1 up to last processed
totalGoodWeight weight
}
// reset all weight that can vote on a voted layer.
func (v *verifying) resetWeights(voted types.LayerID) {
vlayer := v.layer(voted)
v.totalGoodWeight = vlayer.verifying.goodUncounted
for lid := voted.Add(1); !lid.After(v.processed); lid = lid.Add(1) {
layer := v.layer(lid)
layer.verifying.goodUncounted = vlayer.verifying.goodUncounted
}
}
func (v *verifying) countBallot(logger *zap.Logger, ballot *ballotInfo) {
start := time.Now()
prev := v.layer(ballot.layer.Sub(1))
counted := !(ballot.conditions.badBeacon ||
prev.opinion != ballot.opinion() ||
prev.verifying.referenceHeight > ballot.reference.height)
logger.Debug("count ballot in verifying mode",
zap.Uint32("lid", ballot.layer.Uint32()),
zap.Stringer("ballot", ballot.id),
log.ZShortStringer("ballot opinion", ballot.opinion()),
log.ZShortStringer("local opinion", prev.opinion),
zap.Bool("bad beacon", ballot.conditions.badBeacon),
zap.Float64("weight", ballot.weight.Float()),
zap.Uint64("reference height", prev.verifying.referenceHeight),
zap.Uint64("ballot height", ballot.reference.height),
zap.Bool("counted", counted),
)
if !counted {
return
}
for lid := ballot.layer; !lid.After(v.processed); lid = lid.Add(1) {
layer := v.layer(lid)
layer.verifying.goodUncounted = layer.verifying.goodUncounted.Add(ballot.weight)
}
v.totalGoodWeight = v.totalGoodWeight.Add(ballot.weight)
vcountBallotDuration.Observe(float64(time.Since(start).Nanoseconds()))
}
func (v *verifying) countVotes(logger *zap.Logger, ballots []*ballotInfo) {
for _, ballot := range ballots {
v.countBallot(logger, ballot)
}
}
func (v *verifying) verify(logger *zap.Logger, lid types.LayerID) (bool, bool) {
layer := v.layer(lid)
if !layer.hareTerminated {
logger.Debug("hare is not terminated")
return false, false
}
margin := v.totalGoodWeight.
Sub(layer.verifying.goodUncounted)
uncounted := v.expectedWeight(v.Config, lid).
Sub(margin)
// GreaterThan(zero) returns true even if value with negative sign
if uncounted.Float() > 0 {
margin = margin.Sub(uncounted)
}
threshold := v.globalThreshold(v.Config, lid)
if crossesThreshold(margin, threshold) != support {
logger.Debug("doesn't cross global threshold",
zap.Uint32("candidate layer", lid.Uint32()),
zap.Float64("margin", margin.Float()),
zap.Float64("global threshold", threshold.Float()),
)
return false, false
} else {
logger.Debug("crosses global threshold",
zap.Uint32("candidate layer", lid.Uint32()),
zap.Float64("margin", margin.Float()),
zap.Float64("global threshold", threshold.Float()),
)
}
if len(layer.blocks) == 0 {
logger.Debug("candidate layer is empty",
zap.Uint32("candidate layer", lid.Uint32()),
zap.Float64("margin", margin.Float()),
zap.Float64("global threshold", threshold.Float()),
)
}
rst, changes := verifyLayer(
logger,
layer.blocks,
func(block *blockInfo) sign {
if block.height > layer.verifying.referenceHeight {
return neutral
}
decision, _ := getLocalVote(v.Config, v.state.verified, v.state.last, block)
return decision
},
)
if changes {
logger.Info("candidate layer is verified",
zapBlocks(layer.blocks),
zap.String("verifier", "verifying"),
zap.Uint32("candidate layer", lid.Uint32()),
zap.Float64("margin", margin.Float()),
zap.Float64("global threshold", threshold.Float()),
zap.Float64("uncounted", uncounted.Float()),
zap.Float64("total good weight", v.totalGoodWeight.Float()),
zap.Float64("good uncounted", layer.verifying.goodUncounted.Float()),
)
}
return rst, changes
}