@@ -12,6 +12,7 @@ import (
1212 "github.com/attestantio/go-eth2-client/http"
1313 "github.com/attestantio/go-eth2-client/spec"
1414 "github.com/attestantio/go-eth2-client/spec/altair"
15+ "github.com/attestantio/go-eth2-client/spec/electra"
1516 "github.com/attestantio/go-eth2-client/spec/phase0"
1617 "github.com/pkg/errors"
1718
@@ -55,7 +56,8 @@ func (p *BeaconState) Run(
5556 valKeyToIndex map[string]uint64,
5657 relayRewards *big.Int,
5758 validatorIndexToWithdrawalAmount map[uint64]*big.Int,
58- proposerTips map[uint64]*big.Int) error {
59+ proposerTips map[uint64]*big.Int,
60+ validatorIndexToProcessedConsolidation map[uint64][]*electra.PendingConsolidation) error {
5961
6062 if currentBeaconState == nil || prevBeaconState == nil {
6163 return errors.New("current or previous beacon state is nil")
@@ -89,7 +91,8 @@ func (p *BeaconState) Run(
8991 activeValidatorIndexes,
9092 currentBeaconState,
9193 prevBeaconState,
92- validatorIndexToWithdrawalAmount)
94+ validatorIndexToWithdrawalAmount,
95+ validatorIndexToProcessedConsolidation)
9396
9497 if err != nil {
9598 return errors.Wrap(err, "error populating participation and balance")
@@ -179,7 +182,8 @@ func (p *BeaconState) PopulateParticipationAndBalance(
179182 activeValidatorIndexes []uint64,
180183 beaconState *spec.VersionedBeaconState,
181184 prevBeaconState *spec.VersionedBeaconState,
182- validatorIndexToWithdrawalAmount map[uint64]*big.Int) (schemas.ValidatorPerformanceMetrics, error) {
185+ validatorIndexToWithdrawalAmount map[uint64]*big.Int,
186+ validatorIndexToProcessedConsolidation map[uint64][]*electra.PendingConsolidation) (schemas.ValidatorPerformanceMetrics, error) {
183187
184188 metrics := schemas.ValidatorPerformanceMetrics{
185189 EarnedBalance: big.NewInt(0),
@@ -212,7 +216,8 @@ func (p *BeaconState) PopulateParticipationAndBalance(
212216 activeValidatorIndexes,
213217 prevBeaconState,
214218 beaconState,
215- validatorIndexToWithdrawalAmount)
219+ validatorIndexToWithdrawalAmount,
220+ validatorIndexToProcessedConsolidation)
216221
217222 if err != nil {
218223 return schemas.ValidatorPerformanceMetrics{}, err
@@ -340,7 +345,8 @@ func (p *BeaconState) GetValidatorsWithLessBalance(
340345 activeValidatorIndexes []uint64,
341346 prevBeaconState *spec.VersionedBeaconState,
342347 currentBeaconState *spec.VersionedBeaconState,
343- validatorIndexToWithdrawalAmount map[uint64]*big.Int) ([]uint64, *big.Int, *big.Int, error) {
348+ validatorIndexToWithdrawalAmount map[uint64]*big.Int,
349+ validatorIndexToProcessedConsolidation map[uint64][]*electra.PendingConsolidation) ([]uint64, *big.Int, *big.Int, error) {
344350
345351 prevEpoch := GetSlot(prevBeaconState) / p.networkParameters.slotsInEpoch
346352 currEpoch := GetSlot(currentBeaconState) / p.networkParameters.slotsInEpoch
@@ -367,9 +373,18 @@ func (p *BeaconState) GetValidatorsWithLessBalance(
367373
368374 prevEpochValBalance := big.NewInt(0).SetUint64(prevBalances[valIdx])
369375 currentEpochValBalance := big.NewInt(0).SetUint64(currBalances[valIdx])
376+ // Check if there is a withdrawal amount and add it to the balance
370377 if valWithdrawalAmount, ok := validatorIndexToWithdrawalAmount[valIdx]; ok {
371378 currentEpochValBalance.Add(currentEpochValBalance, valWithdrawalAmount)
372379 }
380+ // Check if there are consolidations and substract source balance
381+ if consolidations, ok := validatorIndexToProcessedConsolidation[valIdx]; ok {
382+ for _, consolidation := range consolidations {
383+ sourceBalance := big.NewInt(0).SetUint64(prevBalances[consolidation.SourceIndex])
384+ currentEpochValBalance.Sub(currentEpochValBalance, sourceBalance)
385+ }
386+ }
387+
373388 delta := big.NewInt(0).Sub(currentEpochValBalance, prevEpochValBalance)
374389
375390 if delta.Cmp(big.NewInt(0)) == -1 {
@@ -474,6 +489,41 @@ func isBitSet(input uint8, n int) bool {
474489 return (input & (1 << n)) > uint8(0)
475490}
476491
492+ func GetProcessedConsolidations(
493+ prevBeaconState *spec.VersionedBeaconState,
494+ currentBeaconState *spec.VersionedBeaconState,
495+ ) map[uint64][]*electra.PendingConsolidation {
496+ consolidations := make(map[uint64][]*electra.PendingConsolidation)
497+
498+ validators := GetValidators(currentBeaconState)
499+ prevPendingConsolidations := GetPendingConsolidations(prevBeaconState)
500+ currPendingConsolidations := GetPendingConsolidations(currentBeaconState)
501+
502+ if prevPendingConsolidations == nil {
503+ return consolidations
504+ }
505+
506+ // Set of current pending consolidations
507+ currPendingConsolidationsSet := make(map[string]bool)
508+ for _, consolidation := range currPendingConsolidations {
509+ key := fmt.Sprintf("%d-%d", consolidation.SourceIndex, consolidation.TargetIndex)
510+ currPendingConsolidationsSet[key] = true
511+ }
512+
513+ // If the consolidation is not in the current set, it was processed or source slashed
514+ for _, consolidation := range prevPendingConsolidations {
515+ key := fmt.Sprintf("%d-%d", consolidation.SourceIndex, consolidation.TargetIndex)
516+ if _, ok := currPendingConsolidationsSet[key]; !ok {
517+ sourceValidator := validators[consolidation.SourceIndex]
518+ if sourceValidator.Slashed {
519+ continue
520+ }
521+ consolidations[uint64(consolidation.TargetIndex)] = append(consolidations[uint64(consolidation.TargetIndex)], consolidation)
522+ }
523+ }
524+ return consolidations
525+ }
526+
477527func logMetrics(
478528 metrics schemas.ValidatorPerformanceMetrics,
479529 poolName string) {
@@ -632,3 +682,15 @@ func GetCurrentSyncCommittee(beaconState *spec.VersionedBeaconState) []phase0.BL
632682 }
633683 return pubKeys
634684}
685+
686+ func GetPendingConsolidations(beaconState *spec.VersionedBeaconState) []*electra.PendingConsolidation {
687+ var pendingConsolidations []*electra.PendingConsolidation
688+ if beaconState.Electra != nil {
689+ pendingConsolidations = beaconState.Electra.PendingConsolidations
690+ } else if beaconState.Fulu != nil {
691+ pendingConsolidations = beaconState.Fulu.PendingConsolidations
692+ } else {
693+ log.Fatal("Beacon state was empty")
694+ }
695+ return pendingConsolidations
696+ }
0 commit comments