-
Notifications
You must be signed in to change notification settings - Fork 12
/
witness_weight.go
110 lines (87 loc) · 3.79 KB
/
witness_weight.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
package thresholdblockgadget
import (
"github.com/iotaledger/hive.go/ds"
"github.com/iotaledger/iota-core/pkg/protocol/engine/blocks"
"github.com/iotaledger/iota-core/pkg/votes"
iotago "github.com/iotaledger/iota.go/v4"
)
func (g *Gadget) TrackWitnessWeight(votingBlock *blocks.Block) {
defer votingBlock.SetWeightPropagated()
// Only track witness weight for issuers that are part of the committee.
seat, isValid := g.isCommitteeValidationBlock(votingBlock)
if !isValid {
return
}
votingBlockEpoch := votingBlock.ProtocolBlock().API.TimeProvider().EpochFromSlot(votingBlock.ID().Slot())
var toPreAccept []*blocks.Block
toPreAcceptByID := ds.NewSet[iotago.BlockID]()
var toPreConfirm []*blocks.Block
toPreConfirmByID := ds.NewSet[iotago.BlockID]()
process := func(block *blocks.Block) bool {
shouldPreAccept, shouldPreConfirm := g.shouldPreAcceptAndPreConfirm(block)
var propagateFurther bool
if !block.IsPreAccepted() && (shouldPreAccept || anyChildInSet(block, toPreAcceptByID)) {
toPreAccept = append([]*blocks.Block{block}, toPreAccept...)
toPreAcceptByID.Add(block.ID())
propagateFurther = true
}
// Skip propagation of pre-confirmation if the block is not in the same epoch as the votingBlock.
// This might delay the (pre-)confirmation of blocks at the end of the epoch but make sure that (pre-)confirmation
// is safe in case where the minority of voters got different seats for the next epoch.
blockEpoch := block.ProtocolBlock().API.TimeProvider().EpochFromSlot(block.ID().Slot())
if !block.IsPreConfirmed() && votingBlockEpoch == blockEpoch && (shouldPreConfirm || anyChildInSet(block, toPreConfirmByID)) {
toPreConfirm = append([]*blocks.Block{block}, toPreConfirm...)
toPreConfirmByID.Add(block.ID())
propagateFurther = true
}
return propagateFurther
}
// Add the witness to the voting block itself as each block carries a vote for itself.
if votingBlock.AddWitness(seat) {
process(votingBlock)
}
evaluateFunc := func(block *blocks.Block) bool {
// Propagate further if the witness is new.
propagateFurther := block.AddWitness(seat)
if process(block) {
// Even if the witness is not new, we should preAccept or preConfirm this block just now (potentially due to OnlineCommittee changes).
// That means, we should check its parents to ensure monotonicity (at least for preAcceptance):
// 1. If they are not yet preAccepted, we will add them to the stack and preAccept them.
// 2. If they are preAccepted, we will stop the walk.
propagateFurther = true
}
return propagateFurther
}
g.propagate(votingBlock.Parents(), evaluateFunc)
var acceptanceRatifierWeights []*blocks.Block
for _, block := range toPreAccept {
if block.SetPreAccepted() {
g.events.BlockPreAccepted.Trigger(block)
acceptanceRatifierWeights = append(acceptanceRatifierWeights, block)
}
}
var confirmationRatifierWeights []*blocks.Block
for _, block := range toPreConfirm {
if block.SetPreConfirmed() {
g.events.BlockPreConfirmed.Trigger(block)
confirmationRatifierWeights = append(confirmationRatifierWeights, block)
}
}
for _, block := range acceptanceRatifierWeights {
g.trackAcceptanceRatifierWeight(block)
}
for _, block := range confirmationRatifierWeights {
g.trackConfirmationRatifierWeight(block)
}
}
func (g *Gadget) shouldPreAcceptAndPreConfirm(block *blocks.Block) (preAccept bool, preConfirm bool) {
committeeTotalSeats := g.seatManager.SeatCountInSlot(block.ID().Slot())
blockSeats := block.Witnesses().Size()
onlineCommitteeTotalSeats := g.seatManager.OnlineCommittee().Size()
if votes.IsThresholdReached(blockSeats, committeeTotalSeats, g.optsConfirmationThreshold) {
return true, true
} else if votes.IsThresholdReached(blockSeats, onlineCommitteeTotalSeats, g.optsAcceptanceThreshold) {
return true, false
}
return false, false
}