-
Notifications
You must be signed in to change notification settings - Fork 211
/
verifying.go
114 lines (101 loc) · 3.17 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
package tortoise
import (
"time"
"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 log.Log, 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.With().Debug("count ballot in verifying mode",
ballot.layer,
ballot.id,
log.Stringer("ballot opinion", ballot.opinion()),
log.Stringer("local opinion", prev.opinion),
log.Bool("bad beacon", ballot.conditions.badBeacon),
log.Stringer("weight", ballot.weight),
log.Uint64("reference height", prev.verifying.referenceHeight),
log.Uint64("ballot height", ballot.reference.height),
log.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 log.Log, ballots []*ballotInfo) {
for _, ballot := range ballots {
v.countBallot(logger, ballot)
}
}
func (v *verifying) verify(logger log.Log, lid types.LayerID) bool {
layer := v.layer(lid)
if !layer.hareTerminated {
logger.With().Debug("hare is not terminated")
return 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)
logger = logger.WithFields(
log.String("verifier", "verifying"),
log.Stringer("candidate layer", lid),
log.Stringer("margin", margin),
log.Stringer("uncounted", uncounted),
log.Stringer("total good weight", v.totalGoodWeight),
log.Stringer("good uncounted", layer.verifying.goodUncounted),
log.Stringer("global threshold", threshold),
)
if crossesThreshold(margin, threshold) != support {
logger.With().Debug("doesn't cross global threshold")
return false
} else {
logger.With().Debug("crosses global threshold")
}
return 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
},
)
}