Skip to content

Commit

Permalink
Merge pull request #157 from Layr-Labs/jb/fix-find-2
Browse files Browse the repository at this point in the history
Fix `find-stale-pods` logic
  • Loading branch information
jbrower95 authored Sep 25, 2024
2 parents 9ee8c91 + 1d12112 commit f6492b1
Showing 1 changed file with 57 additions and 18 deletions.
75 changes: 57 additions & 18 deletions cli/core/findStalePods.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,12 @@ type Cache struct {
PodOwnerShares map[string]PodOwnerShare
}

// multiply by a fraction
func FracMul(a *big.Int, x *big.Int, y *big.Int) *big.Int {
_a := new(big.Int).Mul(a, x)
return _a.Div(_a, y)
}

func keys[A comparable, B any](coll map[A]B) []A {
if len(coll) == 0 {
return []A{}
Expand All @@ -42,8 +48,8 @@ func keys[A comparable, B any](coll map[A]B) []A {
}

type PodOwnerShare struct {
SharesWei uint64
ExecutionLayerBalanceWei uint64
SharesWei *big.Int
ExecutionLayerBalanceWei *big.Int
IsEigenpod bool
}

Expand All @@ -60,8 +66,8 @@ func isEigenpod(eth *ethclient.Client, chainId uint64, eigenpodAddress string) (

// default to false
cache.PodOwnerShares[eigenpodAddress] = PodOwnerShare{
SharesWei: 0,
ExecutionLayerBalanceWei: 0,
SharesWei: big.NewInt(0),
ExecutionLayerBalanceWei: big.NewInt(0),
IsEigenpod: false,
}

Expand Down Expand Up @@ -109,8 +115,8 @@ func isEigenpod(eth *ethclient.Client, chainId uint64, eigenpodAddress string) (
// Simulate fetching from contracts
// Implement contract fetching logic here
cache.PodOwnerShares[eigenpodAddress] = PodOwnerShare{
SharesWei: podOwnerShares.Uint64(),
ExecutionLayerBalanceWei: balance.Uint64(),
SharesWei: podOwnerShares,
ExecutionLayerBalanceWei: balance,
IsEigenpod: true,
}

Expand Down Expand Up @@ -205,7 +211,7 @@ func FindStaleEigenpods(ctx context.Context, eth *ethclient.Client, nodeUrl stri

if verbose {
log.Printf("%d EigenValidators have been slashed\n", len(allSlashedValidatorsBelongingToEigenpods))
log.Printf("%d EigenValidators have been slashed AND were active\n", len(allActiveSlashedValidatorsBelongingToEigenpods))
log.Printf("%d EigenValidators have been slashed + active\n", len(allActiveSlashedValidatorsBelongingToEigenpods))
}

slashedEigenpods := utils.Reduce(allActiveSlashedValidatorsBelongingToEigenpods, func(pods map[string][]ValidatorWithIndex, validator ValidatorWithIndex) map[string][]ValidatorWithIndex {
Expand All @@ -224,42 +230,75 @@ func FindStaleEigenpods(ctx context.Context, eth *ethclient.Client, nodeUrl stri
return nil, err
}

totalAssetsWeiByEigenpod := utils.Reduce(keys(slashedEigenpods), func(allBalances map[string]uint64, eigenpod string) map[string]uint64 {
totalAssetsWeiByEigenpod := utils.Reduce(keys(slashedEigenpods), func(allBalances map[string]*big.Int, eigenpod string) map[string]*big.Int {
// total assets of an eigenpod are determined as;
// SUM(
// - native ETH in the pod
// - any active validators and their associated balances
// )
allActiveValidatorsForEigenpod := utils.Filter(allValidatorsWithIndices, func(v ValidatorWithIndex) bool {
if allValidatorInfo[v.Index].Status != 1 {
validatorsForEigenpod := utils.Filter(allValidatorsWithIndices, func(v ValidatorWithIndex) bool {
withdrawal := executionWithdrawalAddress(v.Validator.WithdrawalCredentials)
return withdrawal != nil && strings.EqualFold(*withdrawal, eigenpod)
})

podValidatorInfo, err := FetchMultipleOnchainValidatorInfo(ctx, eth, eigenpod, validatorsForEigenpod)
if err != nil {
return allBalances
}

allActiveValidatorsForEigenpod := utils.Filter(podValidatorInfo, func(v ValidatorWithOnchainInfo) bool {
if v.Info.Status != 1 { // ignore any inactive validators
return false
}

withdrawal := executionWithdrawalAddress(v.Validator.WithdrawalCredentials)
return withdrawal != nil && strings.EqualFold(*withdrawal, eigenpod)
})

allActiveValidatorBalancesSummedGwei := utils.Reduce(allActiveValidatorsForEigenpod, func(accum phase0.Gwei, validator ValidatorWithIndex) phase0.Gwei {
allActiveValidatorBalancesSummedGwei := utils.Reduce(allActiveValidatorsForEigenpod, func(accum phase0.Gwei, validator ValidatorWithOnchainInfo) phase0.Gwei {
return accum + allValidatorBalances[validator.Index]
}, phase0.Gwei(0))
// converting gwei to wei
allBalances[eigenpod] = cache.PodOwnerShares[eigenpod].ExecutionLayerBalanceWei + (uint64(allActiveValidatorBalancesSummedGwei) * params.GWei)
activeValidatorBalancesSum := new(big.Int).Mul(
new(big.Int).SetUint64(uint64(allActiveValidatorBalancesSummedGwei)),
new(big.Int).SetUint64(params.GWei),
)

if verbose {
log.Printf("[%s] podOwnerShares(%sETH), anticipated balance = beacon(%s across %d validators) + executionBalance(%sETH)\n",
eigenpod,
IweiToEther(cache.PodOwnerShares[eigenpod].SharesWei).String(),
IweiToEther(activeValidatorBalancesSum).String(),
len(allActiveValidatorsForEigenpod),
IweiToEther(cache.PodOwnerShares[eigenpod].ExecutionLayerBalanceWei).String(),
) // converting gwei to wei
}

allBalances[eigenpod] = new(big.Int).Add(cache.PodOwnerShares[eigenpod].ExecutionLayerBalanceWei, activeValidatorBalancesSum)
return allBalances
}, map[string]uint64{})
}, map[string]*big.Int{})

if verbose {
log.Printf("%d EigenPods were slashed\n", len(slashedEigenpods))
}

unhealthyEigenpods := utils.Filter(keys(slashedEigenpods), func(eigenpod string) bool {
balance, ok := totalAssetsWeiByEigenpod[eigenpod]
currentTotalAssets, ok := totalAssetsWeiByEigenpod[eigenpod]
if !ok {
return false
}
executionBalance := cache.PodOwnerShares[eigenpod].SharesWei
if balance <= uint64(float64(executionBalance)*(1-(tolerance/100))) {
currentShares := cache.PodOwnerShares[eigenpod].SharesWei

delta := new(big.Int).Sub(currentShares, currentTotalAssets)
allowableDelta := FracMul(currentShares, big.NewInt(int64(tolerance)), big.NewInt(100))
if delta.Cmp(allowableDelta) >= 0 {
if verbose {
log.Printf("[%s] %.2f%% deviation (beacon: %d -> execution: %d)\n", eigenpod, 100*(float64(executionBalance)-float64(balance))/float64(executionBalance), balance, executionBalance)
log.Printf("[%s] %sETH drop in assets (max drop allowed: %sETH, current shares: %sETH, anticipated shares: %sETH)\n",
eigenpod,
IweiToEther(delta).String(),
IweiToEther(allowableDelta).String(),
IweiToEther(currentShares).String(),
IweiToEther(currentTotalAssets).String(),
)
}
return true
}
Expand Down

0 comments on commit f6492b1

Please sign in to comment.