@@ -114,9 +114,23 @@ func (app *Application) maybeElect(ctx *api.Context) error {
114114
115115// shouldElect determines whether elections should be performed.
116116func (app * Application ) shouldElect (ctx * api.Context ) (* electionDecision , error ) {
117+ // The 0th epoch will not have suitable entropy for elections, nor
118+ // will it have useful node registrations.
119+ baseEpoch , err := app .state .GetBaseEpoch ()
120+ if err != nil {
121+ return nil , fmt .Errorf ("cometbft/scheduler: couldn't get base epoch: %w" , err )
122+ }
123+
124+ epochChanged , epoch := app .state .EpochChanged (ctx )
125+ if epoch == baseEpoch {
126+ ctx .Logger ().Info ("system in bootstrap period, skipping election" ,
127+ "epoch" , epoch ,
128+ )
129+ return & electionDecision {}, nil
130+ }
131+
117132 // Check if epoch has changed.
118133 // TODO: We'll later have this for each type of committee.
119- epochChanged , epoch := app .state .EpochChanged (ctx )
120134 if epochChanged {
121135 // For elections on epoch changes, distribute rewards.
122136 return & electionDecision {
@@ -149,20 +163,6 @@ func (app *Application) elect(ctx *api.Context, epoch beacon.EpochTime, reward b
149163 return fmt .Errorf ("cometbft/scheduler: before schedule notification failed: %w" , err )
150164 }
151165
152- // The 0th epoch will not have suitable entropy for elections, nor
153- // will it have useful node registrations.
154- baseEpoch , err := app .state .GetBaseEpoch ()
155- if err != nil {
156- return fmt .Errorf ("cometbft/scheduler: couldn't get base epoch: %w" , err )
157- }
158-
159- if epoch == baseEpoch {
160- ctx .Logger ().Info ("system in bootstrap period, skipping election" ,
161- "epoch" , epoch ,
162- )
163- return nil
164- }
165-
166166 state := schedulerState .NewMutableState (ctx .State ())
167167 schedulerParameters , err := state .ConsensusParameters (ctx )
168168 if err != nil {
@@ -177,6 +177,20 @@ func (app *Application) elect(ctx *api.Context, epoch beacon.EpochTime, reward b
177177 if err != nil {
178178 return fmt .Errorf ("cometbft/scheduler: couldn't get beacon parameters: %w" , err )
179179 }
180+ entropy , err := beaconState .Beacon (ctx )
181+ if err != nil {
182+ return fmt .Errorf ("cometbft/scheduler: couldn't get beacon: %w" , err )
183+ }
184+
185+ var vrf * beacon.PrevVRFState
186+ if beaconParameters .Backend == beacon .BackendVRF {
187+ vrfState , err := beaconState .VRFState (ctx )
188+ if err != nil {
189+ return fmt .Errorf ("cometbft/scheduler: failed to query VRF state: %w" , err )
190+ }
191+ vrf = vrfState .PrevState
192+ }
193+
180194 // If weak alphas are allowed then skip the eligibility check as
181195 // well because the byzantine node and associated tests are extremely
182196 // fragile, and breaks in hard-to-debug ways if timekeeping isn't
@@ -231,12 +245,13 @@ func (app *Application) elect(ctx *api.Context, epoch beacon.EpochTime, reward b
231245 validatorEntities , err := electValidators (
232246 ctx ,
233247 epoch ,
234- beaconState ,
235248 beaconParameters ,
236249 stakeAcc ,
237250 rewardableEntities ,
238251 nodes ,
239252 schedulerParameters ,
253+ entropy ,
254+ vrf ,
240255 )
241256 if err != nil {
242257 // It is unclear what the behavior should be if the validator
@@ -255,13 +270,14 @@ func (app *Application) elect(ctx *api.Context, epoch beacon.EpochTime, reward b
255270 ctx ,
256271 epoch ,
257272 schedulerParameters ,
258- beaconState ,
259273 beaconParameters ,
260274 registryParameters ,
261275 stakeAcc ,
262276 rewardableEntities ,
263277 validatorEntities ,
264278 committeeNodes ,
279+ entropy ,
280+ vrf ,
265281 isFeatureVersion242 ,
266282 ); err != nil {
267283 return fmt .Errorf ("cometbft/scheduler: couldn't elect committees: %w" , err )
@@ -301,39 +317,49 @@ func (app *Application) ExecuteTx(*api.Context, *transaction.Transaction) error
301317func (app * Application ) EndBlock (ctx * api.Context ) (types.ResponseEndBlock , error ) {
302318 var resp types.ResponseEndBlock
303319
320+ validatorUpdates , err := updateValidators (ctx , resp )
321+ if err != nil {
322+ return resp , err
323+ }
324+
325+ resp .ValidatorUpdates = validatorUpdates
326+
327+ return resp , nil
328+ }
329+
330+ func updateValidators (ctx * api.Context , resp types.ResponseEndBlock ) ([]types.ValidatorUpdate , error ) {
304331 state := schedulerState .NewMutableState (ctx .State ())
305332 pendingValidators , err := state .PendingValidators (ctx )
306333 if err != nil {
307- return resp , fmt .Errorf ("cometbft/scheduler: failed to query pending validators: %w" , err )
334+ return nil , fmt .Errorf ("cometbft/scheduler: failed to query pending validators: %w" , err )
308335 }
309336 if pendingValidators == nil {
310337 // No validator updates to apply.
311- return resp , nil
338+ return nil , nil
312339 }
313340
314341 currentValidators , err := state .CurrentValidators (ctx )
315342 if err != nil {
316- return resp , fmt .Errorf ("cometbft/scheduler: failed to query current validators: %w" , err )
343+ return nil , fmt .Errorf ("cometbft/scheduler: failed to query current validators: %w" , err )
317344 }
318345
319346 // Clear out the pending validator update.
320347 if err = state .PutPendingValidators (ctx , nil ); err != nil {
321- return resp , fmt .Errorf ("cometbft/scheduler: failed to clear validators: %w" , err )
348+ return nil , fmt .Errorf ("cometbft/scheduler: failed to clear validators: %w" , err )
322349 }
323350
324351 // CometBFT expects a vector of ValidatorUpdate that expresses
325352 // the difference between the current validator set (tracked manually
326353 // from InitChain), and the new validator set, which is a huge pain
327354 // in the ass.
328355
329- resp . ValidatorUpdates = diffValidators (ctx .Logger (), currentValidators , pendingValidators )
356+ validatorUpdates : = diffValidators (ctx .Logger (), currentValidators , pendingValidators )
330357
331358 // Stash the updated validator set.
332359 if err = state .PutCurrentValidators (ctx , pendingValidators ); err != nil {
333- return resp , fmt .Errorf ("cometbft/scheduler: failed to set validators: %w" , err )
360+ return nil , fmt .Errorf ("cometbft/scheduler: failed to set validators: %w" , err )
334361 }
335-
336- return resp , nil
362+ return validatorUpdates , nil
337363}
338364
339365func diffValidators (logger * logging.Logger , current , pending map [signature.PublicKey ]* scheduler.Validator ) []types.ValidatorUpdate {
@@ -433,13 +459,14 @@ func (app *Application) electCommittees(
433459 ctx * api.Context ,
434460 epoch beacon.EpochTime ,
435461 schedulerParameters * scheduler.ConsensusParameters ,
436- beaconState * beaconState.MutableState ,
437462 beaconParameters * beacon.ConsensusParameters ,
438463 registryParameters * registry.ConsensusParameters ,
439464 stakeAcc * stakingState.StakeAccumulatorCache ,
440465 rewardableEntities map [staking.Address ]struct {},
441466 validatorEntities map [staking.Address ]struct {},
442467 nodes []* nodeWithStatus ,
468+ entropy []byte ,
469+ vrf * beacon.PrevVRFState ,
443470 isFeatureVersion242 bool ,
444471) error {
445472 runtimes , err := fetchRuntimes (ctx )
@@ -457,7 +484,6 @@ func (app *Application) electCommittees(
457484 ctx ,
458485 epoch ,
459486 schedulerParameters ,
460- beaconState ,
461487 beaconParameters ,
462488 registryParameters ,
463489 stakeAcc ,
@@ -466,6 +492,8 @@ func (app *Application) electCommittees(
466492 runtime ,
467493 nodes ,
468494 kind ,
495+ entropy ,
496+ vrf ,
469497 isFeatureVersion242 ,
470498 ); err != nil {
471499 return err
@@ -481,12 +509,13 @@ func (app *Application) electCommittees(
481509func electValidators (
482510 ctx * api.Context ,
483511 epoch beacon.EpochTime ,
484- beaconState * beaconState.MutableState ,
485512 beaconParameters * beacon.ConsensusParameters ,
486513 stakeAcc * stakingState.StakeAccumulatorCache ,
487514 rewardableEntities map [staking.Address ]struct {},
488515 nodes []* node.Node ,
489516 schedulerParameters * scheduler.ConsensusParameters ,
517+ entropy []byte ,
518+ vrf * beacon.PrevVRFState ,
490519) (map [staking.Address ]struct {}, error ) {
491520 // Filter nodes based on eligibility and minimum required entity stake.
492521 var validators []* node.Node
@@ -509,17 +538,13 @@ func electValidators(
509538
510539 // Sort all of the entities that are actually running eligible validator
511540 // nodes by descending stake.
512- weakEntropy , err := beaconState .Beacon (ctx )
513- if err != nil {
514- return nil , fmt .Errorf ("cometbft/scheduler: couldn't get beacon: %w" , err )
515- }
516- sortedEntities , err := stakingAddressMapToSliceByStake (entities , stakeAcc , weakEntropy , schedulerParameters )
541+ sortedEntities , err := stakingAddressMapToSliceByStake (entities , stakeAcc , entropy , schedulerParameters )
517542 if err != nil {
518543 return nil , err
519544 }
520545
521546 // Shuffle validator nodes.
522- shuffledNodes , err := shuffleValidators (ctx , epoch , schedulerParameters , beaconState , beaconParameters , validators )
547+ shuffledNodes , err := shuffleValidators (ctx , epoch , schedulerParameters , beaconParameters , validators , entropy , vrf )
523548 if err != nil {
524549 return nil , err
525550 }
0 commit comments