Skip to content

Commit f6492b1

Browse files
authored
Merge pull request #157 from Layr-Labs/jb/fix-find-2
Fix `find-stale-pods` logic
2 parents 9ee8c91 + 1d12112 commit f6492b1

File tree

1 file changed

+57
-18
lines changed

1 file changed

+57
-18
lines changed

cli/core/findStalePods.go

Lines changed: 57 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,12 @@ type Cache struct {
2828
PodOwnerShares map[string]PodOwnerShare
2929
}
3030

31+
// multiply by a fraction
32+
func FracMul(a *big.Int, x *big.Int, y *big.Int) *big.Int {
33+
_a := new(big.Int).Mul(a, x)
34+
return _a.Div(_a, y)
35+
}
36+
3137
func keys[A comparable, B any](coll map[A]B) []A {
3238
if len(coll) == 0 {
3339
return []A{}
@@ -42,8 +48,8 @@ func keys[A comparable, B any](coll map[A]B) []A {
4248
}
4349

4450
type PodOwnerShare struct {
45-
SharesWei uint64
46-
ExecutionLayerBalanceWei uint64
51+
SharesWei *big.Int
52+
ExecutionLayerBalanceWei *big.Int
4753
IsEigenpod bool
4854
}
4955

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

6167
// default to false
6268
cache.PodOwnerShares[eigenpodAddress] = PodOwnerShare{
63-
SharesWei: 0,
64-
ExecutionLayerBalanceWei: 0,
69+
SharesWei: big.NewInt(0),
70+
ExecutionLayerBalanceWei: big.NewInt(0),
6571
IsEigenpod: false,
6672
}
6773

@@ -109,8 +115,8 @@ func isEigenpod(eth *ethclient.Client, chainId uint64, eigenpodAddress string) (
109115
// Simulate fetching from contracts
110116
// Implement contract fetching logic here
111117
cache.PodOwnerShares[eigenpodAddress] = PodOwnerShare{
112-
SharesWei: podOwnerShares.Uint64(),
113-
ExecutionLayerBalanceWei: balance.Uint64(),
118+
SharesWei: podOwnerShares,
119+
ExecutionLayerBalanceWei: balance,
114120
IsEigenpod: true,
115121
}
116122

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

206212
if verbose {
207213
log.Printf("%d EigenValidators have been slashed\n", len(allSlashedValidatorsBelongingToEigenpods))
208-
log.Printf("%d EigenValidators have been slashed AND were active\n", len(allActiveSlashedValidatorsBelongingToEigenpods))
214+
log.Printf("%d EigenValidators have been slashed + active\n", len(allActiveSlashedValidatorsBelongingToEigenpods))
209215
}
210216

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

227-
totalAssetsWeiByEigenpod := utils.Reduce(keys(slashedEigenpods), func(allBalances map[string]uint64, eigenpod string) map[string]uint64 {
233+
totalAssetsWeiByEigenpod := utils.Reduce(keys(slashedEigenpods), func(allBalances map[string]*big.Int, eigenpod string) map[string]*big.Int {
228234
// total assets of an eigenpod are determined as;
229235
// SUM(
230236
// - native ETH in the pod
231237
// - any active validators and their associated balances
232238
// )
233-
allActiveValidatorsForEigenpod := utils.Filter(allValidatorsWithIndices, func(v ValidatorWithIndex) bool {
234-
if allValidatorInfo[v.Index].Status != 1 {
239+
validatorsForEigenpod := utils.Filter(allValidatorsWithIndices, func(v ValidatorWithIndex) bool {
240+
withdrawal := executionWithdrawalAddress(v.Validator.WithdrawalCredentials)
241+
return withdrawal != nil && strings.EqualFold(*withdrawal, eigenpod)
242+
})
243+
244+
podValidatorInfo, err := FetchMultipleOnchainValidatorInfo(ctx, eth, eigenpod, validatorsForEigenpod)
245+
if err != nil {
246+
return allBalances
247+
}
248+
249+
allActiveValidatorsForEigenpod := utils.Filter(podValidatorInfo, func(v ValidatorWithOnchainInfo) bool {
250+
if v.Info.Status != 1 { // ignore any inactive validators
235251
return false
236252
}
237253

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

242-
allActiveValidatorBalancesSummedGwei := utils.Reduce(allActiveValidatorsForEigenpod, func(accum phase0.Gwei, validator ValidatorWithIndex) phase0.Gwei {
258+
allActiveValidatorBalancesSummedGwei := utils.Reduce(allActiveValidatorsForEigenpod, func(accum phase0.Gwei, validator ValidatorWithOnchainInfo) phase0.Gwei {
243259
return accum + allValidatorBalances[validator.Index]
244260
}, phase0.Gwei(0))
245-
// converting gwei to wei
246-
allBalances[eigenpod] = cache.PodOwnerShares[eigenpod].ExecutionLayerBalanceWei + (uint64(allActiveValidatorBalancesSummedGwei) * params.GWei)
261+
activeValidatorBalancesSum := new(big.Int).Mul(
262+
new(big.Int).SetUint64(uint64(allActiveValidatorBalancesSummedGwei)),
263+
new(big.Int).SetUint64(params.GWei),
264+
)
265+
266+
if verbose {
267+
log.Printf("[%s] podOwnerShares(%sETH), anticipated balance = beacon(%s across %d validators) + executionBalance(%sETH)\n",
268+
eigenpod,
269+
IweiToEther(cache.PodOwnerShares[eigenpod].SharesWei).String(),
270+
IweiToEther(activeValidatorBalancesSum).String(),
271+
len(allActiveValidatorsForEigenpod),
272+
IweiToEther(cache.PodOwnerShares[eigenpod].ExecutionLayerBalanceWei).String(),
273+
) // converting gwei to wei
274+
}
275+
276+
allBalances[eigenpod] = new(big.Int).Add(cache.PodOwnerShares[eigenpod].ExecutionLayerBalanceWei, activeValidatorBalancesSum)
247277
return allBalances
248-
}, map[string]uint64{})
278+
}, map[string]*big.Int{})
249279

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

254284
unhealthyEigenpods := utils.Filter(keys(slashedEigenpods), func(eigenpod string) bool {
255-
balance, ok := totalAssetsWeiByEigenpod[eigenpod]
285+
currentTotalAssets, ok := totalAssetsWeiByEigenpod[eigenpod]
256286
if !ok {
257287
return false
258288
}
259-
executionBalance := cache.PodOwnerShares[eigenpod].SharesWei
260-
if balance <= uint64(float64(executionBalance)*(1-(tolerance/100))) {
289+
currentShares := cache.PodOwnerShares[eigenpod].SharesWei
290+
291+
delta := new(big.Int).Sub(currentShares, currentTotalAssets)
292+
allowableDelta := FracMul(currentShares, big.NewInt(int64(tolerance)), big.NewInt(100))
293+
if delta.Cmp(allowableDelta) >= 0 {
261294
if verbose {
262-
log.Printf("[%s] %.2f%% deviation (beacon: %d -> execution: %d)\n", eigenpod, 100*(float64(executionBalance)-float64(balance))/float64(executionBalance), balance, executionBalance)
295+
log.Printf("[%s] %sETH drop in assets (max drop allowed: %sETH, current shares: %sETH, anticipated shares: %sETH)\n",
296+
eigenpod,
297+
IweiToEther(delta).String(),
298+
IweiToEther(allowableDelta).String(),
299+
IweiToEther(currentShares).String(),
300+
IweiToEther(currentTotalAssets).String(),
301+
)
263302
}
264303
return true
265304
}

0 commit comments

Comments
 (0)