From c7d9a8e6850fb26ecc8f4b2c2b2c978bb9a9f9f4 Mon Sep 17 00:00:00 2001 From: Justin Brower <jbrower95@gmail.com> Date: Tue, 20 Aug 2024 12:44:27 -0400 Subject: [PATCH 1/7] update healthcheck logic --- cli/commands/checkpoint.go | 3 +- cli/commands/credentials.go | 5 +- cli/commands/status.go | 8 +-- cli/commands/utils.go | 21 -------- cli/core/findStalePods.go | 105 ++++++++++++++++++++++-------------- cli/utils/utils.go | 43 +++++++++++++-- 6 files changed, 113 insertions(+), 72 deletions(-) diff --git a/cli/commands/checkpoint.go b/cli/commands/checkpoint.go index 8beb62c9..c0b27eaf 100644 --- a/cli/commands/checkpoint.go +++ b/cli/commands/checkpoint.go @@ -5,6 +5,7 @@ import ( "github.com/Layr-Labs/eigenpod-proofs-generation/cli/core" "github.com/Layr-Labs/eigenpod-proofs-generation/cli/core/onchain" + "github.com/Layr-Labs/eigenpod-proofs-generation/cli/utils" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" @@ -94,7 +95,7 @@ func CheckpointCommand(args TCheckpointCommandArgs) error { txns, err := core.SubmitCheckpointProof(ctx, args.Sender, args.EigenpodAddress, chainId, proof, eth, args.BatchSize, args.NoPrompt, args.SimulateTransaction) if args.SimulateTransaction { - printableTxns := aMap(txns, func(txn *types.Transaction) Transaction { + printableTxns := utils.Map(txns, func(txn *types.Transaction, _ uint64) Transaction { return Transaction{ To: txn.To().Hex(), CallData: common.Bytes2Hex(txn.Data()), diff --git a/cli/commands/credentials.go b/cli/commands/credentials.go index c445cec0..cc230af8 100644 --- a/cli/commands/credentials.go +++ b/cli/commands/credentials.go @@ -7,6 +7,7 @@ import ( "math/big" "github.com/Layr-Labs/eigenpod-proofs-generation/cli/core" + "github.com/Layr-Labs/eigenpod-proofs-generation/cli/utils" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" "github.com/fatih/color" @@ -65,7 +66,7 @@ func CredentialsCommand(args TCredentialCommandArgs) error { }()), err) if args.SimulateTransaction { - out := aMap(txns, func(txn *types.Transaction) CredentialProofTransaction { + out := utils.Map(txns, func(txn *types.Transaction, _ uint64) CredentialProofTransaction { gas := txn.Gas() return CredentialProofTransaction{ Transaction: Transaction{ @@ -79,7 +80,7 @@ func CredentialsCommand(args TCredentialCommandArgs) error { return nil }(), }, - ValidatorIndices: aMap(aFlatten(indices), func(index *big.Int) uint64 { + ValidatorIndices: utils.Map(utils.Flatten(indices), func(index *big.Int, _ uint64) uint64 { return index.Uint64() }), } diff --git a/cli/commands/status.go b/cli/commands/status.go index 701ba539..bb9b90a2 100644 --- a/cli/commands/status.go +++ b/cli/commands/status.go @@ -74,7 +74,7 @@ func StatusCommand(args TStatusArgs) error { for _, validator := range awaitingActivationQueueValidators { publicKey := validator.PublicKey if !isVerbose { - publicKey = shortenHex(publicKey) + publicKey = utils.ShortenHex(publicKey) } targetColor = color.New(color.FgHiRed) @@ -97,7 +97,7 @@ func StatusCommand(args TStatusArgs) error { for _, validator := range inactiveValidators { publicKey := validator.PublicKey if !isVerbose { - publicKey = shortenHex(publicKey) + publicKey = utils.ShortenHex(publicKey) } if validator.Slashed { @@ -120,7 +120,7 @@ func StatusCommand(args TStatusArgs) error { for _, validator := range activeValidators { publicKey := validator.PublicKey if !isVerbose { - publicKey = shortenHex(publicKey) + publicKey = utils.ShortenHex(publicKey) } if validator.Slashed { @@ -143,7 +143,7 @@ func StatusCommand(args TStatusArgs) error { for _, validator := range withdrawnValidators { publicKey := validator.PublicKey if !isVerbose { - publicKey = shortenHex(publicKey) + publicKey = utils.ShortenHex(publicKey) } if validator.Slashed { diff --git a/cli/commands/utils.go b/cli/commands/utils.go index f0f8fbbb..49059b16 100644 --- a/cli/commands/utils.go +++ b/cli/commands/utils.go @@ -25,24 +25,3 @@ func printProofs(txns any) { core.PanicOnError("failed to serialize proofs", err) fmt.Println(string(out)) } - -// imagine if golang had a standard library -func aMap[A any, B any](coll []A, mapper func(i A) B) []B { - out := make([]B, len(coll)) - for i, item := range coll { - out[i] = mapper(item) - } - return out -} - -func aFlatten[A any](coll [][]A) []A { - out := []A{} - for _, arr := range coll { - out = append(out, arr...) - } - return out -} - -func shortenHex(publicKey string) string { - return publicKey[0:6] + ".." + publicKey[len(publicKey)-4:] -} diff --git a/cli/core/findStalePods.go b/cli/core/findStalePods.go index 52f7f662..638620dc 100644 --- a/cli/core/findStalePods.go +++ b/cli/core/findStalePods.go @@ -5,8 +5,10 @@ import ( "fmt" "log" "math/big" + "strings" "github.com/Layr-Labs/eigenpod-proofs-generation/cli/core/onchain" + "github.com/Layr-Labs/eigenpod-proofs-generation/cli/utils" "github.com/attestantio/go-eth2-client/spec/phase0" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" @@ -25,8 +27,20 @@ type Cache struct { PodOwnerShares map[string]PodOwnerShare } +func keys[A comparable, B any](coll map[A]B) []A { + if len(coll) == 0 { + return []A{} + } + out := make([]A, len(coll)) + for key, _ := range coll { + out[len(out)] = key + } + return out +} + type PodOwnerShare struct { Shares uint64 + NativeETH phase0.Gwei IsEigenpod bool } @@ -46,6 +60,7 @@ func isEigenpod(eth *ethclient.Client, chainId uint64, eigenpodAddress string) ( // default to false cache.PodOwnerShares[eigenpodAddress] = PodOwnerShare{ Shares: 0, + NativeETH: phase0.Gwei(0), IsEigenpod: false, } @@ -85,10 +100,16 @@ func isEigenpod(eth *ethclient.Client, chainId uint64, eigenpodAddress string) ( return false, fmt.Errorf("PodOwnerShares() failed: %s", err.Error()) } + balance, err := eth.BalanceAt(context.Background(), common.HexToAddress(eigenpodAddress), nil) + if err != nil { + return false, fmt.Errorf("balance check failed: %s", err.Error()) + } + // Simulate fetching from contracts // Implement contract fetching logic here cache.PodOwnerShares[eigenpodAddress] = PodOwnerShare{ Shares: podOwnerShares.Uint64(), + NativeETH: phase0.Gwei(balance.Uint64()), IsEigenpod: true, } @@ -103,24 +124,6 @@ func executionWithdrawalAddress(withdrawalCredentials []byte) *string { return &addr } -func aFilter[T any](coll []T, criteria func(T) bool) []T { - var result []T - for _, item := range coll { - if criteria(item) { - result = append(result, item) - } - } - return result -} - -func aMap[T any, A any](coll []T, mapper func(T, uint64) A) []A { - var result []A - for idx, item := range coll { - result = append(result, mapper(item, uint64(idx))) - } - return result -} - func FindStaleEigenpods(ctx context.Context, eth *ethclient.Client, nodeUrl string, beacon BeaconClient, chainId *big.Int, verbose bool) (map[string][]ValidatorWithIndex, error) { beaconState, err := beacon.GetBeaconState(ctx, "head") if err != nil { @@ -133,7 +136,7 @@ func FindStaleEigenpods(ctx context.Context, eth *ethclient.Client, nodeUrl stri return nil, err } - allValidatorsWithIndices := aMap(_allValidators, func(validator *phase0.Validator, index uint64) ValidatorWithIndex { + allValidatorsWithIndices := utils.Map(_allValidators, func(validator *phase0.Validator, index uint64) ValidatorWithIndex { return ValidatorWithIndex{ Validator: validator, Index: index, @@ -141,7 +144,7 @@ func FindStaleEigenpods(ctx context.Context, eth *ethclient.Client, nodeUrl stri }) // TODO(pectra): this logic changes after the pectra upgrade. - allSlashedValidators := aFilter(allValidatorsWithIndices, func(v ValidatorWithIndex) bool { + allSlashedValidators := utils.Filter(allValidatorsWithIndices, func(v ValidatorWithIndex) bool { if !v.Validator.Slashed { return false // we only care about slashed validators. } @@ -163,7 +166,7 @@ func FindStaleEigenpods(ctx context.Context, eth *ethclient.Client, nodeUrl stri validatorToPod := map[uint64]string{} - allSlashedValidatorsBelongingToEigenpods := aFilter(allSlashedValidators, func(validator ValidatorWithIndex) bool { + allSlashedValidatorsBelongingToEigenpods := utils.Filter(allSlashedValidators, func(validator ValidatorWithIndex) bool { isPod, err := isEigenpod(eth, chainId.Uint64(), *executionWithdrawalAddress(validator.Validator.WithdrawalCredentials)) if err != nil { return false @@ -172,11 +175,13 @@ func FindStaleEigenpods(ctx context.Context, eth *ethclient.Client, nodeUrl stri }) allValidatorInfo := make(map[uint64]onchain.IEigenPodValidatorInfo) - for _, validator := range allSlashedValidatorsBelongingToEigenpods { eigenpodAddress := *executionWithdrawalAddress(validator.Validator.WithdrawalCredentials) pod, err := onchain.NewEigenPod(common.HexToAddress(eigenpodAddress), eth) - PanicOnError("failed to dial eigenpod", err) + if err != nil { + // failed to load validator info. + return map[string][]ValidatorWithIndex{}, fmt.Errorf("failed to dial eigenpod: %s", err.Error()) + } info, err := pod.ValidatorPubkeyToInfo(nil, validator.Validator.PublicKey[:]) if err != nil { @@ -186,9 +191,9 @@ func FindStaleEigenpods(ctx context.Context, eth *ethclient.Client, nodeUrl stri allValidatorInfo[validator.Index] = info } - allActiveSlashedValidatorsBelongingToEigenpods := aFilter(allSlashedValidatorsBelongingToEigenpods, func(validator ValidatorWithIndex) bool { + allActiveSlashedValidatorsBelongingToEigenpods := utils.Filter(allSlashedValidatorsBelongingToEigenpods, func(validator ValidatorWithIndex) bool { validatorInfo := allValidatorInfo[validator.Index] - return validatorInfo.Status == 1 + return validatorInfo.Status == 1 // "ACTIVE" }) if verbose { @@ -204,30 +209,50 @@ func FindStaleEigenpods(ctx context.Context, eth *ethclient.Client, nodeUrl stri } } - if verbose { - log.Printf("%d EigenPods were slashed\n", len(slashedEigenpods)) - } - allValidatorBalances, err := beaconState.ValidatorBalances() if err != nil { return nil, err } - var unhealthyEigenpods map[string]bool = make(map[string]bool) - for _, validator := range allActiveSlashedValidatorsBelongingToEigenpods { - balance := allValidatorBalances[validator.Index] - pod := validatorToPod[validator.Index] - executionBalance := cache.PodOwnerShares[pod].Shares - if executionBalance == 0 { - continue + totalAssetsGweiByEigenpod := utils.Reduce(keys(slashedEigenpods), func(allBalances map[string]phase0.Gwei, eigenpod string) map[string]phase0.Gwei { + // total assets of an eigenpod are determined as; + // SUM( + // - native ETH in the pod + // - any active validators and their associated balances + // ) + allEigenpodsForValidator := utils.Filter(allValidatorsWithIndices, func(v ValidatorWithIndex) bool { + withdrawal := executionWithdrawalAddress(v.Validator.WithdrawalCredentials) + return withdrawal != nil && strings.EqualFold(*withdrawal, eigenpod) + }) + + allValidatorBalancesSummed := utils.Reduce(allEigenpodsForValidator, func(accum phase0.Gwei, validator ValidatorWithIndex) phase0.Gwei { + return accum + allValidatorBalances[validator.Index] + }, phase0.Gwei(0)) + + balance := phase0.Gwei(cache.PodOwnerShares[eigenpod].NativeETH) + allValidatorBalancesSummed + allBalances[eigenpod] = phase0.Gwei(balance) + return allBalances + }, map[string]phase0.Gwei{}) + + if verbose { + log.Printf("%d EigenPods were slashed\n", len(slashedEigenpods)) + } + + unhealthyEigenpods := utils.Filter(keys(slashedEigenpods), func(eigenpod string) bool { + balance, ok := totalAssetsGweiByEigenpod[eigenpod] + if !ok { + return false } + executionBalance := cache.PodOwnerShares[eigenpod].Shares if balance <= phase0.Gwei(float64(executionBalance)*ACCEPTABLE_BALANCE_DEVIATION) { - unhealthyEigenpods[pod] = true if verbose { - log.Printf("[%s] %.2f%% deviation (beacon: %d -> execution: %d)\n", pod, 100*(float64(executionBalance)-float64(balance))/float64(executionBalance), balance, executionBalance) + log.Printf("[%s] %.2f%% deviation (beacon: %d -> execution: %d)\n", eigenpod, 100*(float64(executionBalance)-float64(balance))/float64(executionBalance), balance, executionBalance) } + return true } - } + + return false + }) if len(unhealthyEigenpods) == 0 { if verbose { @@ -241,7 +266,7 @@ func FindStaleEigenpods(ctx context.Context, eth *ethclient.Client, nodeUrl stri } var entries map[string][]ValidatorWithIndex = make(map[string][]ValidatorWithIndex) - for val := range unhealthyEigenpods { + for _, val := range unhealthyEigenpods { entries[val] = slashedEigenpods[val] } diff --git a/cli/utils/utils.go b/cli/utils/utils.go index 341d348f..c84626ed 100644 --- a/cli/utils/utils.go +++ b/cli/utils/utils.go @@ -1,9 +1,44 @@ package utils -func ShortenHex(publicKey string) string { - return publicKey[0:6] + ".." + publicKey[len(publicKey)-4:] -} - // maximum number of proofs per txn for each of the following proof types: const DEFAULT_BATCH_CREDENTIALS = 60 const DEFAULT_BATCH_CHECKPOINT = 80 + +// imagine if golang had a standard library +func Map[A any, B any](coll []A, mapper func(i A, index uint64) B) []B { + out := make([]B, len(coll)) + for i, item := range coll { + out[i] = mapper(item, uint64(i)) + } + return out +} + +func Filter[A any](coll []A, criteria func(i A) bool) []A { + out := []A{} + for _, item := range coll { + if criteria(item) { + out = append(out, item) + } + } + return out +} + +func Reduce[A any, B any](coll []A, processor func(accum B, next A) B, initialState B) B { + val := initialState + for _, item := range coll { + val = processor(val, item) + } + return val +} + +func Flatten[A any](coll [][]A) []A { + out := []A{} + for _, arr := range coll { + out = append(out, arr...) + } + return out +} + +func ShortenHex(publicKey string) string { + return publicKey[0:6] + ".." + publicKey[len(publicKey)-4:] +} From 263c5c183c4c13bc02a1f32b8c3ea7488d94e0ea Mon Sep 17 00:00:00 2001 From: Justin Brower <jbrower95@gmail.com> Date: Tue, 20 Aug 2024 13:09:47 -0400 Subject: [PATCH 2/7] use reduce instead --- cli/core/findStalePods.go | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/cli/core/findStalePods.go b/cli/core/findStalePods.go index 638620dc..fe10489f 100644 --- a/cli/core/findStalePods.go +++ b/cli/core/findStalePods.go @@ -200,14 +200,17 @@ func FindStaleEigenpods(ctx context.Context, eth *ethclient.Client, nodeUrl stri log.Printf("%d EigenValidators were slashed\n", len(allActiveSlashedValidatorsBelongingToEigenpods)) } - slashedEigenpods := make(map[string][]ValidatorWithIndex) - for _, validator := range allActiveSlashedValidatorsBelongingToEigenpods { + slashedEigenpods := utils.Reduce(allActiveSlashedValidatorsBelongingToEigenpods, func(pods map[string][]ValidatorWithIndex, validator ValidatorWithIndex) map[string][]ValidatorWithIndex { podAddress := executionWithdrawalAddress(validator.Validator.WithdrawalCredentials) if podAddress != nil { - slashedEigenpods[*podAddress] = append(slashedEigenpods[*podAddress], validator) + if pods[*podAddress] == nil { + pods[*podAddress] = []ValidatorWithIndex{} + } + pods[*podAddress] = append(pods[*podAddress], validator) validatorToPod[validator.Index] = *podAddress } - } + return pods + }, map[string][]ValidatorWithIndex{}) allValidatorBalances, err := beaconState.ValidatorBalances() if err != nil { From bffd07e13e206d9637849791a008132d36b2c457 Mon Sep 17 00:00:00 2001 From: Justin Brower <jbrower95@gmail.com> Date: Tue, 20 Aug 2024 14:11:40 -0400 Subject: [PATCH 3/7] wei to gwei --- cli/core/findStalePods.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/cli/core/findStalePods.go b/cli/core/findStalePods.go index fe10489f..69d34e2d 100644 --- a/cli/core/findStalePods.go +++ b/cli/core/findStalePods.go @@ -13,6 +13,7 @@ import ( "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/ethclient" + "github.com/ethereum/go-ethereum/params" "github.com/pkg/errors" ) @@ -23,6 +24,10 @@ func PodManagerContracts() map[uint64]string { } } +func weiToGwei(val uint64) phase0.Gwei { + return phase0.Gwei(new(big.Int).Div(new(big.Int).SetUint64(val), big.NewInt(params.GWei)).Uint64()) +} + type Cache struct { PodOwnerShares map[string]PodOwnerShare } @@ -109,7 +114,7 @@ func isEigenpod(eth *ethclient.Client, chainId uint64, eigenpodAddress string) ( // Implement contract fetching logic here cache.PodOwnerShares[eigenpodAddress] = PodOwnerShare{ Shares: podOwnerShares.Uint64(), - NativeETH: phase0.Gwei(balance.Uint64()), + NativeETH: weiToGwei(balance.Uint64()), IsEigenpod: true, } From 7abc9d8104734353e641a375e16c1d106cef60eb Mon Sep 17 00:00:00 2001 From: Justin Brower <jbrower95@gmail.com> Date: Tue, 20 Aug 2024 14:32:37 -0400 Subject: [PATCH 4/7] more nits --- cli/core/findStalePods.go | 29 +++++++++++++---------------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/cli/core/findStalePods.go b/cli/core/findStalePods.go index 69d34e2d..ec098565 100644 --- a/cli/core/findStalePods.go +++ b/cli/core/findStalePods.go @@ -44,14 +44,14 @@ func keys[A comparable, B any](coll map[A]B) []A { } type PodOwnerShare struct { - Shares uint64 - NativeETH phase0.Gwei - IsEigenpod bool + Shares uint64 + ExecutionLayerBalance phase0.Gwei + IsEigenpod bool } const ACCEPTABLE_BALANCE_DEVIATION = float64(0.95) -var cache Cache +var cache Cache // valid for the duration of a command. func isEigenpod(eth *ethclient.Client, chainId uint64, eigenpodAddress string) (bool, error) { if cache.PodOwnerShares == nil { @@ -64,9 +64,9 @@ func isEigenpod(eth *ethclient.Client, chainId uint64, eigenpodAddress string) ( // default to false cache.PodOwnerShares[eigenpodAddress] = PodOwnerShare{ - Shares: 0, - NativeETH: phase0.Gwei(0), - IsEigenpod: false, + Shares: 0, + ExecutionLayerBalance: phase0.Gwei(0), + IsEigenpod: false, } podManAddress, ok := PodManagerContracts()[chainId] @@ -113,9 +113,9 @@ func isEigenpod(eth *ethclient.Client, chainId uint64, eigenpodAddress string) ( // Simulate fetching from contracts // Implement contract fetching logic here cache.PodOwnerShares[eigenpodAddress] = PodOwnerShare{ - Shares: podOwnerShares.Uint64(), - NativeETH: weiToGwei(balance.Uint64()), - IsEigenpod: true, + Shares: podOwnerShares.Uint64(), + ExecutionLayerBalance: weiToGwei(balance.Uint64()), + IsEigenpod: true, } return true, nil @@ -169,8 +169,6 @@ func FindStaleEigenpods(ctx context.Context, eth *ethclient.Client, nodeUrl stri return map[string][]ValidatorWithIndex{}, nil } - validatorToPod := map[uint64]string{} - allSlashedValidatorsBelongingToEigenpods := utils.Filter(allSlashedValidators, func(validator ValidatorWithIndex) bool { isPod, err := isEigenpod(eth, chainId.Uint64(), *executionWithdrawalAddress(validator.Validator.WithdrawalCredentials)) if err != nil { @@ -212,7 +210,6 @@ func FindStaleEigenpods(ctx context.Context, eth *ethclient.Client, nodeUrl stri pods[*podAddress] = []ValidatorWithIndex{} } pods[*podAddress] = append(pods[*podAddress], validator) - validatorToPod[validator.Index] = *podAddress } return pods }, map[string][]ValidatorWithIndex{}) @@ -228,16 +225,16 @@ func FindStaleEigenpods(ctx context.Context, eth *ethclient.Client, nodeUrl stri // - native ETH in the pod // - any active validators and their associated balances // ) - allEigenpodsForValidator := utils.Filter(allValidatorsWithIndices, func(v ValidatorWithIndex) bool { + allValidatorsForEigenpod := utils.Filter(allValidatorsWithIndices, func(v ValidatorWithIndex) bool { withdrawal := executionWithdrawalAddress(v.Validator.WithdrawalCredentials) return withdrawal != nil && strings.EqualFold(*withdrawal, eigenpod) }) - allValidatorBalancesSummed := utils.Reduce(allEigenpodsForValidator, func(accum phase0.Gwei, validator ValidatorWithIndex) phase0.Gwei { + allValidatorBalancesSummed := utils.Reduce(allValidatorsForEigenpod, func(accum phase0.Gwei, validator ValidatorWithIndex) phase0.Gwei { return accum + allValidatorBalances[validator.Index] }, phase0.Gwei(0)) - balance := phase0.Gwei(cache.PodOwnerShares[eigenpod].NativeETH) + allValidatorBalancesSummed + balance := phase0.Gwei(cache.PodOwnerShares[eigenpod].ExecutionLayerBalance) + allValidatorBalancesSummed allBalances[eigenpod] = phase0.Gwei(balance) return allBalances }, map[string]phase0.Gwei{}) From e2ccdafab3b8a3a230aea39cc671f8d090f461e2 Mon Sep 17 00:00:00 2001 From: Justin Brower <jbrower95@gmail.com> Date: Tue, 20 Aug 2024 14:33:45 -0400 Subject: [PATCH 5/7] one line --- cli/core/findStalePods.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/cli/core/findStalePods.go b/cli/core/findStalePods.go index ec098565..e90f376c 100644 --- a/cli/core/findStalePods.go +++ b/cli/core/findStalePods.go @@ -234,8 +234,7 @@ func FindStaleEigenpods(ctx context.Context, eth *ethclient.Client, nodeUrl stri return accum + allValidatorBalances[validator.Index] }, phase0.Gwei(0)) - balance := phase0.Gwei(cache.PodOwnerShares[eigenpod].ExecutionLayerBalance) + allValidatorBalancesSummed - allBalances[eigenpod] = phase0.Gwei(balance) + allBalances[eigenpod] = phase0.Gwei(cache.PodOwnerShares[eigenpod].ExecutionLayerBalance) + allValidatorBalancesSummed return allBalances }, map[string]phase0.Gwei{}) From 6d5873f5c9fa0db819e56cf5938cb68ed1d89373 Mon Sep 17 00:00:00 2001 From: Justin Brower <jbrower95@gmail.com> Date: Tue, 20 Aug 2024 17:44:51 -0400 Subject: [PATCH 6/7] update logic to be in wei --- cli/core/findStalePods.go | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/cli/core/findStalePods.go b/cli/core/findStalePods.go index e90f376c..3a92d4c3 100644 --- a/cli/core/findStalePods.go +++ b/cli/core/findStalePods.go @@ -44,9 +44,9 @@ func keys[A comparable, B any](coll map[A]B) []A { } type PodOwnerShare struct { - Shares uint64 - ExecutionLayerBalance phase0.Gwei - IsEigenpod bool + SharesWei uint64 + ExecutionLayerBalanceWei uint64 + IsEigenpod bool } const ACCEPTABLE_BALANCE_DEVIATION = float64(0.95) @@ -64,9 +64,9 @@ func isEigenpod(eth *ethclient.Client, chainId uint64, eigenpodAddress string) ( // default to false cache.PodOwnerShares[eigenpodAddress] = PodOwnerShare{ - Shares: 0, - ExecutionLayerBalance: phase0.Gwei(0), - IsEigenpod: false, + SharesWei: 0, + ExecutionLayerBalanceWei: 0, + IsEigenpod: false, } podManAddress, ok := PodManagerContracts()[chainId] @@ -113,9 +113,9 @@ func isEigenpod(eth *ethclient.Client, chainId uint64, eigenpodAddress string) ( // Simulate fetching from contracts // Implement contract fetching logic here cache.PodOwnerShares[eigenpodAddress] = PodOwnerShare{ - Shares: podOwnerShares.Uint64(), - ExecutionLayerBalance: weiToGwei(balance.Uint64()), - IsEigenpod: true, + SharesWei: podOwnerShares.Uint64(), + ExecutionLayerBalanceWei: balance.Uint64(), + IsEigenpod: true, } return true, nil @@ -219,7 +219,7 @@ func FindStaleEigenpods(ctx context.Context, eth *ethclient.Client, nodeUrl stri return nil, err } - totalAssetsGweiByEigenpod := utils.Reduce(keys(slashedEigenpods), func(allBalances map[string]phase0.Gwei, eigenpod string) map[string]phase0.Gwei { + totalAssetsWeiByEigenpod := utils.Reduce(keys(slashedEigenpods), func(allBalances map[string]uint64, eigenpod string) map[string]uint64 { // total assets of an eigenpod are determined as; // SUM( // - native ETH in the pod @@ -230,25 +230,25 @@ func FindStaleEigenpods(ctx context.Context, eth *ethclient.Client, nodeUrl stri return withdrawal != nil && strings.EqualFold(*withdrawal, eigenpod) }) - allValidatorBalancesSummed := utils.Reduce(allValidatorsForEigenpod, func(accum phase0.Gwei, validator ValidatorWithIndex) phase0.Gwei { + allValidatorBalancesSummedGwei := utils.Reduce(allValidatorsForEigenpod, func(accum phase0.Gwei, validator ValidatorWithIndex) phase0.Gwei { return accum + allValidatorBalances[validator.Index] }, phase0.Gwei(0)) - - allBalances[eigenpod] = phase0.Gwei(cache.PodOwnerShares[eigenpod].ExecutionLayerBalance) + allValidatorBalancesSummed + // converting gwei to wei + allBalances[eigenpod] = cache.PodOwnerShares[eigenpod].ExecutionLayerBalanceWei + (uint64(allValidatorBalancesSummedGwei) * params.GWei) return allBalances - }, map[string]phase0.Gwei{}) + }, map[string]uint64{}) if verbose { log.Printf("%d EigenPods were slashed\n", len(slashedEigenpods)) } unhealthyEigenpods := utils.Filter(keys(slashedEigenpods), func(eigenpod string) bool { - balance, ok := totalAssetsGweiByEigenpod[eigenpod] + balance, ok := totalAssetsWeiByEigenpod[eigenpod] if !ok { return false } - executionBalance := cache.PodOwnerShares[eigenpod].Shares - if balance <= phase0.Gwei(float64(executionBalance)*ACCEPTABLE_BALANCE_DEVIATION) { + executionBalance := cache.PodOwnerShares[eigenpod].SharesWei + if balance <= uint64(float64(executionBalance)*ACCEPTABLE_BALANCE_DEVIATION) { if verbose { log.Printf("[%s] %.2f%% deviation (beacon: %d -> execution: %d)\n", eigenpod, 100*(float64(executionBalance)-float64(balance))/float64(executionBalance), balance, executionBalance) } From a5391282cdb19075ed77f2361842dab9dd6715b1 Mon Sep 17 00:00:00 2001 From: Justin Brower <jbrower95@gmail.com> Date: Tue, 20 Aug 2024 17:47:33 -0400 Subject: [PATCH 7/7] fix lint --- cli/commands/staleBalance.go | 6 +++--- cli/main.go | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/cli/commands/staleBalance.go b/cli/commands/staleBalance.go index d7382132..1e55dfaf 100644 --- a/cli/commands/staleBalance.go +++ b/cli/commands/staleBalance.go @@ -18,7 +18,7 @@ type TFixStaleBalanceArgs struct { BeaconNode string Sender string EigenpodAddress string - SlashedValidatorIndex int64 + SlashedValidatorIndex uint64 Verbose bool CheckpointBatchSize uint64 NoPrompt bool @@ -39,7 +39,7 @@ func FixStaleBalance(args TFixStaleBalanceArgs) error { eth, beacon, chainId, err := core.GetClients(ctx, args.EthNode, args.BeaconNode, args.Verbose) core.PanicOnError("failed to get clients", err) - validator, err := beacon.GetValidator(ctx, uint64(args.SlashedValidatorIndex)) + validator, err := beacon.GetValidator(ctx, args.SlashedValidatorIndex) core.PanicOnError("failed to fetch validator state", err) if !validator.Validator.Slashed { @@ -75,7 +75,7 @@ func FixStaleBalance(args TFixStaleBalanceArgs) error { } } - proof, oracleBeaconTimesetamp, err := core.GenerateValidatorProof(ctx, args.EigenpodAddress, eth, chainId, beacon, new(big.Int).SetUint64(uint64(args.SlashedValidatorIndex)), args.Verbose) + proof, oracleBeaconTimesetamp, err := core.GenerateValidatorProof(ctx, args.EigenpodAddress, eth, chainId, beacon, new(big.Int).SetUint64(args.SlashedValidatorIndex), args.Verbose) core.PanicOnError("failed to generate credential proof for slashed validator", err) if !args.NoPrompt { diff --git a/cli/main.go b/cli/main.go index 33bc0bdd..82ef84d4 100644 --- a/cli/main.go +++ b/cli/main.go @@ -71,7 +71,7 @@ func main() { BeaconNode: beacon, Sender: sender, EigenpodAddress: eigenpodAddress, - SlashedValidatorIndex: int64(slashedValidatorIndex), + SlashedValidatorIndex: slashedValidatorIndex, Verbose: verbose, CheckpointBatchSize: batchSize, NoPrompt: noPrompt,