diff --git a/cli/core/status.go b/cli/core/status.go index d2990d52..a6676104 100644 --- a/cli/core/status.go +++ b/cli/core/status.go @@ -23,6 +23,7 @@ type Validator struct { Index uint64 Status int PublicKey string + IsAwaitingActivationQueue bool IsAwaitingWithdrawalCredentialProof bool EffectiveBalance uint64 CurrentBalance uint64 @@ -101,18 +102,20 @@ func GetStatus(ctx context.Context, eigenpodAddress string, eth *ethclient.Clien sumRegularBalancesGwei := sumActiveValidatorBalancesGwei(activeValidators, allBalances, state) for i := 0; i < len(allValidators); i++ { - validatorInfo, err := eigenPod.ValidatorPubkeyToInfo(nil, allValidators[i].Validator.PublicKey[:]) - PanicOnError("failed to fetch validator info", err) - + validator := allValidators[i].Validator validatorIndex := allValidators[i].Index + validatorInfo, err := eigenPod.ValidatorPubkeyToInfo(nil, validator.PublicKey[:]) + PanicOnError("failed to fetch validator info", err) + validators[fmt.Sprintf("%d", validatorIndex)] = Validator{ Index: validatorIndex, Status: int(validatorInfo.Status), - Slashed: allValidators[i].Validator.Slashed, - PublicKey: allValidators[i].Validator.PublicKey.String(), - IsAwaitingWithdrawalCredentialProof: (validatorInfo.Status == ValidatorStatusInactive) && allValidators[i].Validator.ExitEpoch == FAR_FUTURE_EPOCH, - EffectiveBalance: uint64(allValidators[i].Validator.EffectiveBalance), + Slashed: validator.Slashed, + PublicKey: validator.PublicKey.String(), + IsAwaitingActivationQueue: validator.ActivationEpoch == FAR_FUTURE_EPOCH, + IsAwaitingWithdrawalCredentialProof: (validatorInfo.Status == ValidatorStatusInactive) && validator.ExitEpoch == FAR_FUTURE_EPOCH && validator.ActivationEpoch != FAR_FUTURE_EPOCH, + EffectiveBalance: uint64(validator.EffectiveBalance), CurrentBalance: uint64(allBalances[validatorIndex]), } } diff --git a/cli/core/utils.go b/cli/core/utils.go index 0023036f..c51385eb 100644 --- a/cli/core/utils.go +++ b/cli/core/utils.go @@ -171,14 +171,18 @@ func GetCurrentCheckpoint(eigenpodAddress string, client *ethclient.Client) (uin return timestamp, nil } -func SortByStatus(validators map[string]Validator) ([]Validator, []Validator, []Validator) { - var inactiveValidators, activeValidators, withdrawnValidators []Validator +func SortByStatus(validators map[string]Validator) ([]Validator, []Validator, []Validator, []Validator) { + var awaitingActivationQueueValidators, inactiveValidators, activeValidators, withdrawnValidators []Validator // Iterate over all `validators` and sort them into inactive, active, or withdrawn. for _, validator := range validators { switch validator.Status { case ValidatorStatusInactive: - inactiveValidators = append(inactiveValidators, validator) + if validator.IsAwaitingActivationQueue { + awaitingActivationQueueValidators = append(awaitingActivationQueueValidators, validator) + } else { + inactiveValidators = append(inactiveValidators, validator) + } case ValidatorStatusActive: activeValidators = append(activeValidators, validator) case ValidatorStatusWithdrawn: @@ -197,7 +201,7 @@ func SortByStatus(validators map[string]Validator) ([]Validator, []Validator, [] return withdrawnValidators[i].Index < withdrawnValidators[j].Index }) - return inactiveValidators, activeValidators, withdrawnValidators + return awaitingActivationQueueValidators, inactiveValidators, activeValidators, withdrawnValidators } // search through beacon state for validators whose withdrawal address is set to eigenpod. @@ -428,6 +432,24 @@ func SelectCheckpointableValidators( // (https://github.com/Layr-Labs/eigenlayer-contracts/blob/d148952a2942a97a218a2ab70f9b9f1792796081/src/contracts/libraries/BeaconChainProofs.sol#L64) const FAR_FUTURE_EPOCH = math.MaxUint64 +// Validators whose deposits have been processed but are awaiting activation on the beacon chain +// If the validator has 32 ETH effective balance, they should +func SelectAwaitingActivationValidators( + client *ethclient.Client, + eigenpodAddress string, + validators []ValidatorWithIndex, +) ([]ValidatorWithIndex, error) { + var awaitingActivationValidators = []ValidatorWithIndex{} + for i := 0; i < len(validators); i++ { + validator := validators[i] + + if validator.Validator.ActivationEpoch == FAR_FUTURE_EPOCH { + awaitingActivationValidators = append(awaitingActivationValidators, validator) + } + } + return awaitingActivationValidators, nil +} + func SelectAwaitingCredentialValidators( client *ethclient.Client, eigenpodAddress string, @@ -444,7 +466,8 @@ func SelectAwaitingCredentialValidators( validatorInfo := validatorInfos[i] if (validatorInfo.Status == ValidatorStatusInactive) && - (validator.Validator.ExitEpoch == FAR_FUTURE_EPOCH) { + (validator.Validator.ExitEpoch == FAR_FUTURE_EPOCH) && + (validator.Validator.ActivationEpoch != FAR_FUTURE_EPOCH) { awaitingCredentialValidators = append(awaitingCredentialValidators, validator) } } diff --git a/cli/main.go b/cli/main.go index b4be80d8..7d7cddb2 100644 --- a/cli/main.go +++ b/cli/main.go @@ -228,12 +228,41 @@ func main() { fmt.Println() // sort validators by status - inactiveValidators, activeValidators, withdrawnValidators := core.SortByStatus(status.Validators) + awaitingActivationQueueValidators, inactiveValidators, activeValidators, withdrawnValidators := + core.SortByStatus(status.Validators) var targetColor *color.Color bold.Printf("Eigenpod validators:\n============\n") ital.Printf("Format: #ValidatorIndex (pubkey) [effective balance] [current balance]\n") + // print info on validators who are not yet in the activation queue + // + // if these validators have 32 ETH effective balance, they will be + // activated soon and can then have their credentials verified + // + // if these validators do NOT have 32 ETH effective balance yet, the + // staker needs to deposit more ETH. + if len(awaitingActivationQueueValidators) != 0 { + targetColor = color.New(color.FgHiRed) + + color.New(color.Bold, color.FgHiRed).Printf("- [AWAITING ACTIVATION QUEUE] - These validators have deposited, but either do not meet the minimum balance to be activated, or are awaiting activation:\n") + + for _, validator := range awaitingActivationQueueValidators { + publicKey := validator.PublicKey + if !verbose { + publicKey = shortenHex(publicKey) + } + + if validator.Slashed { + targetColor.Printf("\t- #%d (%s) [%d] [%d] (slashed on beacon chain)\n", validator.Index, publicKey, validator.EffectiveBalance, validator.CurrentBalance) + } else { + targetColor.Printf("\t- #%d (%s) [%d] [%d]\n", validator.Index, publicKey, validator.EffectiveBalance, validator.CurrentBalance) + } + } + + fmt.Println() + } + // print info on inactive validators // these validators can be added to the pod's active validator set // by running the `credentials` command