@@ -140,91 +140,107 @@ func (d *DataAccessService) GetValidatorsByGraffiti(ctx context.Context, graffit
140140 return runQueryRows [[]t.VDBValidator ](ctx , d .readerDb , validatorsDs )
141141}
142142
143- // estimate activation for pending and deposited validators
144- // TODO support estimates for validators without index
145- func (d * DataAccessService ) getValidatorActivation (ctx context.Context , validator uint64 ) (uint64 , error ) {
143+ // fills the activation epochs for a set of validators. Tries to estimate pending validators based on current queue simulation
144+ func (d * DataAccessService ) getValidatorActivationEpochs (ctx context.Context , validators map [uint64 ]* uint64 ) error {
146145 validatorMapping , err := d .services .GetCurrentValidatorMapping ()
147146 if err != nil {
148- return 0 , err
147+ return err
149148 }
150- if validator >= uint64 (len (validatorMapping .ValidatorMetadata )) {
151- return 0 , fmt .Errorf ("validator index %d not found in validator mapping" , validator )
152- }
153- metadata := validatorMapping .ValidatorMetadata [validator ]
154- if metadata .ActivationEpoch .Valid {
155- return uint64 (metadata .ActivationEpoch .Int64 ), nil
156- }
157-
158- // estimate
159149 latestEpoch := cache .LatestFinalizedEpoch .Get ()
160- if d .config .ClConfig .ElectraForkEpoch > latestEpoch {
161- if constypes .ValidatorDbStatus (metadata .Status ) != constypes .DbPending {
162- // probably not enough deposits yet
163- return 0 , fmt .Errorf ("validator %d is not pending activation yet" , validator )
164- }
165- if ! metadata .Queues .ActivationIndex .Valid {
166- return 0 , fmt .Errorf ("validator %d has no activation index" , validator )
150+ latestStats := cache .LatestStats .Get ()
151+ activationChurnRate := uint64 (4 )
152+ if latestStats .ValidatorActivationChurnLimit == nil {
153+ log .Warnf ("Activation Churn rate not set in config, using 4 as default" )
154+ } else {
155+ activationChurnRate = * latestStats .ValidatorActivationChurnLimit
156+ }
157+ pendingValidatorsPostPectra := make ([]uint64 , 0 )
158+
159+ for validator := range validators {
160+ if validator >= uint64 (len (validatorMapping .ValidatorMetadata )) {
161+ return fmt .Errorf ("validator index %d not found in validator mapping" , validator )
167162 }
168- queuePosition := uint64 (metadata .Queues .ActivationIndex .Int64 )
169-
170- latestStats := cache .LatestStats .Get ()
171- activationChurnRate := uint64 (4 )
172- if latestStats .ValidatorActivationChurnLimit == nil {
173- log .Warnf ("Activation Churn rate not set in config, using 4 as default" )
174- } else {
175- activationChurnRate = * latestStats .ValidatorActivationChurnLimit
163+ metadata := validatorMapping .ValidatorMetadata [validator ]
164+ if metadata .ActivationEpoch .Valid {
165+ // validator already activated, easy case
166+ activationEpoch := uint64 (metadata .ActivationEpoch .Int64 )
167+ validators [validator ] = & activationEpoch
168+ continue
176169 }
177170
178- epochsToWait := (queuePosition - 1 ) / activationChurnRate
179- // calculate dequeue epoch
180- estimatedActivationEpoch := latestEpoch + epochsToWait + 1
181- // add activation offset
182- estimatedActivationEpoch += utils .Config .Chain .ClConfig .MaxSeedLookahead + 1
171+ // estimate
172+ if d .config .ClConfig .ElectraForkEpoch > latestEpoch {
173+ // pre pectra
174+ if constypes .ValidatorDbStatus (metadata .Status ) != constypes .DbPending {
175+ // probably not enough deposits yet
176+ continue
177+ }
178+ if ! metadata .Queues .ActivationIndex .Valid {
179+ // could support estimates for validators without index
180+ continue
181+ }
182+ queuePosition := uint64 (metadata .Queues .ActivationIndex .Int64 )
183183
184- return estimatedActivationEpoch , nil
185- }
184+ epochsToWait := (queuePosition - 1 ) / activationChurnRate
185+ // calculate dequeue epoch
186+ estimatedActivationEpoch := latestEpoch + epochsToWait + 1
187+ // add activation offset
188+ estimatedActivationEpoch += utils .Config .Chain .ClConfig .MaxSeedLookahead + 1
186189
187- // post pectra
188- if constypes .ValidatorDbStatus (metadata .Status ) != constypes .DbDeposited {
189- // should not happen since there's no more activation queue after deposits have been processed (see process_registry_updates)
190- return 0 , fmt .Errorf ("validator %d has no activation epoch" , validator )
190+ validators [validator ] = & estimatedActivationEpoch
191+ continue
192+ }
193+
194+ // post pectra
195+ if constypes .ValidatorDbStatus (metadata .Status ) != constypes .DbDeposited {
196+ // should not happen since there's no more activation queue after deposits have been processed (see process_registry_updates)
197+ return fmt .Errorf ("validator %d has no activation epoch" , validator )
198+ }
199+ pendingValidatorsPostPectra = append (pendingValidatorsPostPectra , validator )
191200 }
201+
192202 // determine sum of previous deposit
193203 // check if there's a pending deposit which pushes above min activation
194204 // return estimate of that from db
195205
196206 // could also simulate in db, but wouldn't be pretty
197207 ds := goqu .Dialect ("postgres" ).From ("pending_deposits_queue" ).
198208 Select (
209+ goqu .I ("validator_index" ),
199210 goqu .I ("est_clear_epoch" ),
200211 goqu .I ("amount" ),
201212 ).
202213 Where (
203- goqu .I ("validator_index" ).Eq ( validator ),
214+ goqu .I ("validator_index" ).In ( pendingValidatorsPostPectra ),
204215 ).
205216 Order (goqu .I ("id" ).Asc ())
206217
207218 type dbResult struct {
208- ClearEpoch uint64 `db:"est_clear_epoch"`
209- Amount uint64 `db:"amount"`
219+ ValidatorIndex uint64 `db:"validator_index"`
220+ ClearEpoch uint64 `db:"est_clear_epoch"`
221+ Amount uint64 `db:"amount"`
210222 }
211- results , err := runQueryRows [[]dbResult ](ctx , d .alloyReader , ds )
223+ results , err := runQueryRows [[]dbResult ](ctx , d .readerDb , ds )
212224 if err != nil {
213- return 0 , err
214- }
215-
216- effectiveBalance := metadata .EffectiveBalance
217- balance := metadata .Balance
218- upwardThreshold := utils .Config .Chain .ClConfig .EffectiveBalanceIncrement / utils .Config .Chain .ClConfig .HysteresisQuotient * utils .Config .Chain .ClConfig .HysteresisUpwardMultiplier
219- for _ , deposit := range results {
220- balance += deposit .Amount
221- if effectiveBalance + upwardThreshold < balance {
222- effectiveBalance = balance - balance % utils .Config .Chain .ClConfig .EffectiveBalanceIncrement
223- if effectiveBalance >= utils .Config .Chain .ClConfig .MinActivationBalance {
224- return deposit .ClearEpoch , nil
225+ return err
226+ }
227+
228+ for _ , result := range results {
229+ metadata := validatorMapping .ValidatorMetadata [result .ValidatorIndex ]
230+ effectiveBalance := metadata .EffectiveBalance
231+ balance := metadata .Balance
232+ upwardThreshold := utils .Config .Chain .ClConfig .EffectiveBalanceIncrement / utils .Config .Chain .ClConfig .HysteresisQuotient * utils .Config .Chain .ClConfig .HysteresisUpwardMultiplier
233+ for _ , deposit := range results {
234+ balance += deposit .Amount
235+ if effectiveBalance + upwardThreshold < balance {
236+ effectiveBalance = balance - balance % utils .Config .Chain .ClConfig .EffectiveBalanceIncrement
237+ if effectiveBalance >= utils .Config .Chain .ClConfig .MinActivationBalance {
238+ validators [deposit .ValidatorIndex ] = & deposit .ClearEpoch
239+ break
240+ }
225241 }
226242 }
227243 }
228244
229- return 0 , fmt . Errorf ( "validator %d has not enough pending ETH deposits" , validator )
245+ return nil
230246}
0 commit comments