@@ -15,11 +15,11 @@ import (
15
15
16
16
// Voter records chits received from [vdr] once its dependencies are met.
17
17
type voter struct {
18
- t * Transitive
19
- vdr ids.NodeID
20
- requestID uint32
21
- response ids.ID
22
- deps set.Set [ids.ID ]
18
+ t * Transitive
19
+ vdr ids.NodeID
20
+ requestID uint32
21
+ responseOptions [] ids.ID
22
+ deps set.Set [ids.ID ]
23
23
}
24
24
25
25
func (v * voter ) Dependencies () set.Set [ids.ID ] {
@@ -42,11 +42,24 @@ func (v *voter) Update(ctx context.Context) {
42
42
return
43
43
}
44
44
45
+ var (
46
+ vote ids.ID
47
+ shouldVote bool
48
+ )
49
+ for _ , voteOption := range v .responseOptions {
50
+ // To prevent any potential deadlocks with undisclosed dependencies,
51
+ // votes must be bubbled to the nearest valid block
52
+ vote , shouldVote = v .getProcessingAncestor (ctx , voteOption )
53
+ if shouldVote {
54
+ break
55
+ }
56
+ }
57
+
45
58
var results []bag.Bag [ids.ID ]
46
- if v . response == ids . Empty {
47
- results = v .t .polls .Drop (v .requestID , v .vdr )
59
+ if shouldVote {
60
+ results = v .t .polls .Vote (v .requestID , v .vdr , vote )
48
61
} else {
49
- results = v .t .polls .Vote (v .requestID , v .vdr , v . response )
62
+ results = v .t .polls .Drop (v .requestID , v .vdr )
50
63
}
51
64
52
65
if len (results ) == 0 {
@@ -55,13 +68,6 @@ func (v *voter) Update(ctx context.Context) {
55
68
56
69
for _ , result := range results {
57
70
result := result
58
- v .t .Ctx .Log .Debug ("filtering poll results" ,
59
- zap .Stringer ("result" , & result ),
60
- )
61
-
62
- // To prevent any potential deadlocks with un-disclosed dependencies,
63
- // votes must be bubbled to the nearest valid block
64
- result = v .bubbleVotes (ctx , result )
65
71
v .t .Ctx .Log .Debug ("finishing poll" ,
66
72
zap .Stringer ("result" , & result ),
67
73
)
@@ -88,92 +94,48 @@ func (v *voter) Update(ctx context.Context) {
88
94
v .t .repoll (ctx )
89
95
}
90
96
91
- // bubbleVotes bubbles the [votes] a set of the number of votes for specific
92
- // blkIDs that received votes in consensus, to their most recent ancestor that
93
- // has been issued to consensus.
97
+ // getProcessingAncestor finds [initialVote]'s most recent ancestor that is
98
+ // processing in consensus. If no ancestor could be found, false is returned.
94
99
//
95
- // Note: bubbleVotes does not bubbleVotes to all of the ancestors in consensus,
96
- // just the most recent one. bubbling to the rest of the ancestors, which may
97
- // also be in consensus is handled in RecordPoll.
98
- func (v * voter ) bubbleVotes (ctx context.Context , votes bag.Bag [ids.ID ]) bag.Bag [ids.ID ] {
99
- bubbledVotes := bag.Bag [ids.ID ]{}
100
-
101
- votesLoop:
102
- for _ , vote := range votes .List () {
103
- count := votes .Count (vote )
104
- // use rootID in case of this is a non-verified block ID
105
- rootID := v .t .nonVerifieds .GetAncestor (vote )
106
- v .t .Ctx .Log .Verbo ("bubbling vote(s) through unverified blocks" ,
107
- zap .Int ("numVotes" , count ),
108
- zap .Stringer ("voteID" , vote ),
109
- zap .Stringer ("parentID" , rootID ),
110
- )
111
-
112
- blk , err := v .t .GetBlock (ctx , rootID )
100
+ // Note: If [initialVote] is processing, then [initialVote] will be returned.
101
+ func (v * voter ) getProcessingAncestor (ctx context.Context , initialVote ids.ID ) (ids.ID , bool ) {
102
+ // If [bubbledVote] != [initialVote], it is guaranteed that [bubbledVote] is
103
+ // in processing. Otherwise, we attempt to iterate through any blocks we
104
+ // have at our disposal as a best-effort mechanism to find a valid ancestor.
105
+ bubbledVote := v .t .nonVerifieds .GetAncestor (initialVote )
106
+ for {
107
+ blk , err := v .t .GetBlock (ctx , bubbledVote )
113
108
// If we cannot retrieve the block, drop [vote]
114
109
if err != nil {
115
- v .t .Ctx .Log .Debug ("dropping vote(s)" ,
116
- zap .String ("reason" , "parent couldn't be fetched" ),
117
- zap .Stringer ("parentID" , rootID ),
118
- zap .Int ("numVotes" , count ),
119
- zap .Stringer ("voteID" , vote ),
110
+ v .t .Ctx .Log .Debug ("dropping vote" ,
111
+ zap .String ("reason" , "ancestor couldn't be fetched" ),
112
+ zap .Stringer ("initialVoteID" , initialVote ),
113
+ zap .Stringer ("bubbledVoteID" , bubbledVote ),
120
114
zap .Error (err ),
121
115
)
122
- continue
116
+ return ids . Empty , false
123
117
}
124
118
125
- status := blk .Status ()
126
- blkID := blk .ID ()
127
- // If we have not fetched [blkID] break from the loop. We will drop the
128
- // vote below and move on to the next vote.
129
- //
130
- // If [blk] has already been decided, break from the loop, we will drop
131
- // the vote below since there is no need to count the votes for a [blk]
132
- // we've already finalized.
133
- //
134
- // If [blk] is currently in consensus, break from the loop, we have
135
- // reached the first ancestor of the original [vote] that has been
136
- // issued consensus. In this case, the votes will be bubbled further
137
- // from [blk] to any of its ancestors that are also in consensus.
138
- for status .Fetched () && ! (v .t .Consensus .Decided (blk ) || v .t .Consensus .Processing (blkID )) {
139
- parentID := blk .Parent ()
140
- v .t .Ctx .Log .Verbo ("pushing vote(s)" ,
141
- zap .Int ("numVotes" , count ),
142
- zap .Stringer ("voteID" , vote ),
143
- zap .Stringer ("parentID" , rootID ),
119
+ if v .t .Consensus .Decided (blk ) {
120
+ v .t .Ctx .Log .Debug ("dropping vote" ,
121
+ zap .String ("reason" , "bubbled vote already decided" ),
122
+ zap .Stringer ("initialVoteID" , initialVote ),
123
+ zap .Stringer ("bubbledVoteID" , bubbledVote ),
124
+ zap .Stringer ("status" , blk .Status ()),
125
+ zap .Uint64 ("height" , blk .Height ()),
144
126
)
145
-
146
- blkID = parentID
147
- blk , err = v .t .GetBlock (ctx , blkID )
148
- // If we cannot retrieve the block, drop [vote]
149
- if err != nil {
150
- v .t .Ctx .Log .Debug ("dropping vote(s)" ,
151
- zap .String ("reason" , "block couldn't be fetched" ),
152
- zap .Stringer ("blkID" , blkID ),
153
- zap .Int ("numVotes" , count ),
154
- zap .Stringer ("voteID" , vote ),
155
- zap .Error (err ),
156
- )
157
- continue votesLoop
158
- }
159
- status = blk .Status ()
127
+ return ids .Empty , false
160
128
}
161
129
162
- // If [blkID] is currently in consensus, count the votes
163
- if v .t .Consensus .Processing (blkID ) {
164
- v .t .Ctx .Log .Verbo ("applying vote(s)" ,
165
- zap .Int ("numVotes" , count ),
166
- zap .Stringer ("blkID" , blkID ),
167
- zap .Stringer ("status" , status ),
168
- )
169
- bubbledVotes .AddCount (blkID , count )
170
- } else {
171
- v .t .Ctx .Log .Verbo ("dropping vote(s)" ,
172
- zap .Int ("numVotes" , count ),
173
- zap .Stringer ("blkID" , blkID ),
174
- zap .Stringer ("status" , status ),
130
+ if v .t .Consensus .Processing (bubbledVote ) {
131
+ v .t .Ctx .Log .Verbo ("applying vote" ,
132
+ zap .Stringer ("initialVoteID" , initialVote ),
133
+ zap .Stringer ("bubbledVoteID" , bubbledVote ),
134
+ zap .Uint64 ("height" , blk .Height ()),
175
135
)
136
+ return bubbledVote , true
176
137
}
138
+
139
+ bubbledVote = blk .Parent ()
177
140
}
178
- return bubbledVotes
179
141
}
0 commit comments