18
18
_ services.Service = & Handler {}
19
19
)
20
20
21
+ var (
22
+ ErrUnknownConsensusEngineID = errors .New ("unknown consensus engine ID" )
23
+ )
24
+
21
25
// Handler is used to handle consensus messages and relevant authority updates to BABE and GRANDPA
22
26
type Handler struct {
23
27
ctx context.Context
@@ -32,28 +36,9 @@ type Handler struct {
32
36
imported chan * types.Block
33
37
finalised chan * types.FinalisationInfo
34
38
35
- // GRANDPA changes
36
- grandpaScheduledChange * grandpaChange
37
- grandpaForcedChange * grandpaChange
38
- grandpaPause * pause
39
- grandpaResume * resume
40
-
41
39
logger log.LeveledLogger
42
40
}
43
41
44
- type grandpaChange struct {
45
- auths []types.Authority
46
- atBlock uint
47
- }
48
-
49
- type pause struct {
50
- atBlock uint
51
- }
52
-
53
- type resume struct {
54
- atBlock uint
55
- }
56
-
57
42
// NewHandler returns a new Handler
58
43
func NewHandler (lvl log.Level , blockState BlockState , epochState EpochState ,
59
44
grandpaState GrandpaState ) (* Handler , error ) {
@@ -91,44 +76,80 @@ func (h *Handler) Stop() error {
91
76
return nil
92
77
}
93
78
94
- // NextGrandpaAuthorityChange returns the block number of the next upcoming grandpa authorities change.
95
- // It returns 0 if no change is scheduled.
96
- func (h * Handler ) NextGrandpaAuthorityChange () (next uint ) {
97
- next = ^ uint (0 )
98
-
99
- if h .grandpaScheduledChange != nil {
100
- next = h .grandpaScheduledChange .atBlock
79
+ // HandleDigests handles consensus digests for an imported block
80
+ func (h * Handler ) HandleDigests (header * types.Header ) error {
81
+ consensusDigests := h .toConsensusDigests (header .Digest .Types )
82
+ consensusDigests , err := checkForGRANDPAForcedChanges (consensusDigests )
83
+ if err != nil {
84
+ return fmt .Errorf ("failed while checking GRANDPA digests: %w" , err )
101
85
}
102
86
103
- if h .grandpaForcedChange != nil && h .grandpaForcedChange .atBlock < next {
104
- next = h .grandpaForcedChange .atBlock
87
+ for i := range consensusDigests {
88
+ // avoiding implicit memory aliasing in for loop, since:
89
+ // for _, digest := range consensusDigests { &digest }
90
+ // is using the address of a loop variable
91
+ digest := consensusDigests [i ]
92
+ err := h .handleConsensusDigest (& digest , header )
93
+ if err != nil {
94
+ h .logger .Errorf ("cannot handle consensus digest: %w" , err )
95
+ }
105
96
}
106
97
107
- if h .grandpaPause != nil && h .grandpaPause .atBlock < next {
108
- next = h .grandpaPause .atBlock
109
- }
98
+ return nil
99
+ }
100
+
101
+ // toConsensusDigests converts a slice of scale.VaryingDataType to a slice of types.ConsensusDigest.
102
+ func (h * Handler ) toConsensusDigests (scaleVaryingTypes []scale.VaryingDataType ) []types.ConsensusDigest {
103
+ consensusDigests := make ([]types.ConsensusDigest , 0 , len (scaleVaryingTypes ))
104
+
105
+ for _ , d := range scaleVaryingTypes {
106
+ digest , ok := d .Value ().(types.ConsensusDigest )
107
+ if ! ok {
108
+ h .logger .Debugf ("digest type not supported: %T" , d .Value ())
109
+ continue
110
+ }
110
111
111
- if h .grandpaResume != nil && h .grandpaResume .atBlock < next {
112
- next = h .grandpaResume .atBlock
112
+ switch digest .ConsensusEngineID {
113
+ case types .GrandpaEngineID , types .BabeEngineID :
114
+ consensusDigests = append (consensusDigests , digest )
115
+ }
113
116
}
114
117
115
- return next
118
+ return consensusDigests
116
119
}
117
120
118
- // HandleDigests handles consensus digests for an imported block
119
- func (h * Handler ) HandleDigests (header * types.Header ) {
120
- for i , d := range header .Digest .Types {
121
- val , ok := d .Value ().(types.ConsensusDigest )
122
- if ! ok {
121
+ // checkForGRANDPAForcedChanges removes any GrandpaScheduledChange in the presence of a
122
+ // GrandpaForcedChange in the same block digest, returning a new slice of types.ConsensusDigest
123
+ func checkForGRANDPAForcedChanges (digests []types.ConsensusDigest ) ([]types.ConsensusDigest , error ) {
124
+ var hasForcedChange bool
125
+ digestsWithoutScheduled := make ([]types.ConsensusDigest , 0 , len (digests ))
126
+ for _ , digest := range digests {
127
+ if digest .ConsensusEngineID != types .GrandpaEngineID {
128
+ digestsWithoutScheduled = append (digestsWithoutScheduled , digest )
123
129
continue
124
130
}
125
131
126
- err := h .handleConsensusDigest (& val , header )
132
+ data := types .NewGrandpaConsensusDigest ()
133
+ err := scale .Unmarshal (digest .Data , & data )
127
134
if err != nil {
128
- h .logger .Errorf ("cannot handle digest for block number %d, index %d, digest %s: %s" ,
129
- header .Number , i , d .Value (), err )
135
+ return nil , fmt .Errorf ("cannot unmarshal GRANDPA consensus digest: %w" , err )
136
+ }
137
+
138
+ switch data .Value ().(type ) {
139
+ case types.GrandpaScheduledChange :
140
+ case types.GrandpaForcedChange :
141
+ hasForcedChange = true
142
+ digestsWithoutScheduled = append (digestsWithoutScheduled , digest )
143
+ default :
144
+ digestsWithoutScheduled = append (digestsWithoutScheduled , digest )
130
145
}
131
146
}
147
+
148
+ if hasForcedChange {
149
+ return digestsWithoutScheduled , nil
150
+ }
151
+
152
+ return digests , nil
132
153
}
133
154
134
155
func (h * Handler ) handleConsensusDigest (d * types.ConsensusDigest , header * types.Header ) error {
@@ -139,42 +160,19 @@ func (h *Handler) handleConsensusDigest(d *types.ConsensusDigest, header *types.
139
160
if err != nil {
140
161
return err
141
162
}
142
- err = h .handleGrandpaConsensusDigest (data , header )
143
- if err != nil {
144
- return err
145
- }
146
- return nil
163
+
164
+ return h .grandpaState .HandleGRANDPADigest (header , data )
147
165
case types .BabeEngineID :
148
166
data := types .NewBabeConsensusDigest ()
149
167
err := scale .Unmarshal (d .Data , & data )
150
168
if err != nil {
151
169
return err
152
170
}
153
- err = h .handleBabeConsensusDigest (data , header )
154
- if err != nil {
155
- return err
156
- }
157
- return nil
158
- }
159
-
160
- return errors .New ("unknown consensus engine ID" )
161
- }
162
171
163
- func (h * Handler ) handleGrandpaConsensusDigest (digest scale.VaryingDataType , header * types.Header ) error {
164
- switch val := digest .Value ().(type ) {
165
- case types.GrandpaScheduledChange :
166
- return h .handleScheduledChange (val , header )
167
- case types.GrandpaForcedChange :
168
- return h .handleForcedChange (val , header )
169
- case types.GrandpaOnDisabled :
170
- return nil // do nothing, as this is not implemented in substrate
171
- case types.GrandpaPause :
172
- return h .handlePause (val )
173
- case types.GrandpaResume :
174
- return h .handleResume (val )
172
+ return h .handleBabeConsensusDigest (data , header )
173
+ default :
174
+ return fmt .Errorf ("%w: 0x%x" , ErrUnknownConsensusEngineID , d .ConsensusEngineID .ToBytes ())
175
175
}
176
-
177
- return errors .New ("invalid consensus digest data" )
178
176
}
179
177
180
178
func (h * Handler ) handleBabeConsensusDigest (digest scale.VaryingDataType , header * types.Header ) error {
@@ -194,7 +192,7 @@ func (h *Handler) handleBabeConsensusDigest(digest scale.VaryingDataType, header
194
192
return nil
195
193
196
194
case types.BABEOnDisabled :
197
- return h . handleBABEOnDisabled ( val , header )
195
+ return nil
198
196
199
197
case types.NextConfigData :
200
198
currEpoch , err := h .epochState .GetEpochForBlock (header )
@@ -220,10 +218,14 @@ func (h *Handler) handleBlockImport(ctx context.Context) {
220
218
continue
221
219
}
222
220
223
- h .HandleDigests (& block .Header )
224
- err := h .handleGrandpaChangesOnImport (block .Header .Number )
221
+ err := h .HandleDigests (& block .Header )
225
222
if err != nil {
226
- h .logger .Errorf ("failed to handle grandpa changes on block import: %s" , err )
223
+ h .logger .Errorf ("failed to handle digests: %s" , err )
224
+ }
225
+
226
+ err = h .grandpaState .ApplyForcedChanges (& block .Header )
227
+ if err != nil {
228
+ h .logger .Errorf ("failed to apply forced changes: %s" , err )
227
229
}
228
230
case <- ctx .Done ():
229
231
return
@@ -249,159 +251,13 @@ func (h *Handler) handleBlockFinalisation(ctx context.Context) {
249
251
h .logger .Errorf ("failed to persist babe next epoch config: %s" , err )
250
252
}
251
253
252
- err = h .handleGrandpaChangesOnFinalization ( info .Header . Number )
254
+ err = h .grandpaState . ApplyScheduledChanges ( & info .Header )
253
255
if err != nil {
254
- h .logger .Errorf ("failed to handle grandpa changes on block finalisation : %s" , err )
256
+ h .logger .Errorf ("failed to apply scheduled change : %s" , err )
255
257
}
258
+
256
259
case <- ctx .Done ():
257
260
return
258
261
}
259
262
}
260
263
}
261
-
262
- func (h * Handler ) handleGrandpaChangesOnImport (num uint ) error {
263
- resume := h .grandpaResume
264
- if resume != nil && num >= resume .atBlock {
265
- h .grandpaResume = nil
266
- }
267
-
268
- fc := h .grandpaForcedChange
269
- if fc != nil && num >= fc .atBlock {
270
- curr , err := h .grandpaState .IncrementSetID ()
271
- if err != nil {
272
- return err
273
- }
274
-
275
- h .grandpaForcedChange = nil
276
- h .logger .Debugf ("incremented grandpa set id %d" , curr )
277
- }
278
-
279
- return nil
280
- }
281
-
282
- func (h * Handler ) handleGrandpaChangesOnFinalization (num uint ) error {
283
- pause := h .grandpaPause
284
- if pause != nil && num >= pause .atBlock {
285
- h .grandpaPause = nil
286
- }
287
-
288
- sc := h .grandpaScheduledChange
289
- if sc != nil && num >= sc .atBlock {
290
- curr , err := h .grandpaState .IncrementSetID ()
291
- if err != nil {
292
- return err
293
- }
294
-
295
- h .grandpaScheduledChange = nil
296
- h .logger .Debugf ("incremented grandpa set id %d" , curr )
297
- }
298
-
299
- // if blocks get finalised before forced change takes place, disregard it
300
- h .grandpaForcedChange = nil
301
- return nil
302
- }
303
-
304
- func (h * Handler ) handleScheduledChange (sc types.GrandpaScheduledChange , header * types.Header ) error {
305
- curr , err := h .blockState .BestBlockHeader ()
306
- if err != nil {
307
- return err
308
- }
309
-
310
- if h .grandpaScheduledChange != nil {
311
- return nil
312
- }
313
-
314
- h .logger .Debugf ("handling GrandpaScheduledChange data: %v" , sc )
315
-
316
- c , err := newGrandpaChange (sc .Auths , sc .Delay , curr .Number )
317
- if err != nil {
318
- return err
319
- }
320
-
321
- h .grandpaScheduledChange = c
322
-
323
- auths , err := types .GrandpaAuthoritiesRawToAuthorities (sc .Auths )
324
- if err != nil {
325
- return err
326
- }
327
- h .logger .Debugf ("setting GrandpaScheduledChange at block %d" ,
328
- header .Number + uint (sc .Delay ))
329
- return h .grandpaState .SetNextChange (
330
- types .NewGrandpaVotersFromAuthorities (auths ),
331
- header .Number + uint (sc .Delay ),
332
- )
333
- }
334
-
335
- func (h * Handler ) handleForcedChange (fc types.GrandpaForcedChange , header * types.Header ) error {
336
- if header == nil {
337
- return errors .New ("header is nil" )
338
- }
339
-
340
- if h .grandpaForcedChange != nil {
341
- return errors .New ("already have forced change scheduled" )
342
- }
343
-
344
- h .logger .Debugf ("handling GrandpaForcedChange with data %v" , fc )
345
-
346
- c , err := newGrandpaChange (fc .Auths , fc .Delay , header .Number )
347
- if err != nil {
348
- return err
349
- }
350
-
351
- h .grandpaForcedChange = c
352
-
353
- auths , err := types .GrandpaAuthoritiesRawToAuthorities (fc .Auths )
354
- if err != nil {
355
- return err
356
- }
357
-
358
- h .logger .Debugf ("setting GrandpaForcedChange at block %d" ,
359
- header .Number + uint (fc .Delay ))
360
- return h .grandpaState .SetNextChange (
361
- types .NewGrandpaVotersFromAuthorities (auths ),
362
- header .Number + uint (fc .Delay ),
363
- )
364
- }
365
-
366
- func (h * Handler ) handlePause (p types.GrandpaPause ) error {
367
- curr , err := h .blockState .BestBlockHeader ()
368
- if err != nil {
369
- return err
370
- }
371
-
372
- h .grandpaPause = & pause {
373
- atBlock : curr .Number + uint (p .Delay ),
374
- }
375
-
376
- return h .grandpaState .SetNextPause (h .grandpaPause .atBlock )
377
- }
378
-
379
- func (h * Handler ) handleResume (r types.GrandpaResume ) error {
380
- curr , err := h .blockState .BestBlockHeader ()
381
- if err != nil {
382
- return err
383
- }
384
-
385
- h .grandpaResume = & resume {
386
- atBlock : curr .Number + uint (r .Delay ),
387
- }
388
-
389
- return h .grandpaState .SetNextResume (h .grandpaResume .atBlock )
390
- }
391
-
392
- func newGrandpaChange (raw []types.GrandpaAuthoritiesRaw , delay uint32 , currBlock uint ) (* grandpaChange , error ) {
393
- auths , err := types .GrandpaAuthoritiesRawToAuthorities (raw )
394
- if err != nil {
395
- return nil , err
396
- }
397
-
398
- return & grandpaChange {
399
- auths : auths ,
400
- atBlock : currBlock + uint (delay ),
401
- }, nil
402
- }
403
-
404
- func (h * Handler ) handleBABEOnDisabled (_ types.BABEOnDisabled , _ * types.Header ) error {
405
- h .logger .Debug ("handling BABEOnDisabled" )
406
- return nil
407
- }
0 commit comments