Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[do not merge] Alex/analyze pods #153

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 54 additions & 0 deletions cli/commands/analyze.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package commands

import (
"context"
"encoding/csv"
"os"

"github.com/Layr-Labs/eigenpod-proofs-generation/cli/core"
"github.com/ethereum/go-ethereum/common"
"github.com/fatih/color"
)

type TAnalyzeArgs struct {
EigenpodAddress string
DisableColor bool
UseJSON bool
Node string
BeaconNode string
Verbose bool
}

var podDataPath = "../pod_deployed.csv"

func AnalyzeCommand(args TAnalyzeArgs) error {
ctx := context.Background()
if args.DisableColor {
color.NoColor = true
}

isVerbose := !args.UseJSON

eth, beaconClient, _, err := core.GetClients(ctx, args.Node, args.BeaconNode, isVerbose)
core.PanicOnError("failed to load ethereum clients", err)

file, err := os.Open(podDataPath)
defer file.Close()
core.PanicOnError("failed to open csv: %w", err)

reader := csv.NewReader(file)
records, err := reader.ReadAll()
core.PanicOnError("error reading records: %w", err)

pods := make(map[string]core.PodInfo)
for _, record := range records {
pods[record[0]] = core.PodInfo{
PodAddress: common.HexToAddress(record[0]),
Owner: common.HexToAddress(record[1]),
}
}

core.AnalyzePods(ctx, pods, eth, beaconClient)

return nil
}
113 changes: 113 additions & 0 deletions cli/core/analyze.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
package core

import (
"context"
"fmt"
"math"
"math/big"

gethCommon "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/ethclient"
)

type PodInfo struct {
PodAddress gethCommon.Address
Owner gethCommon.Address
}

type PodAnalysis struct {
Validators map[string]Validator

ActiveCheckpoint *Checkpoint

NumberValidatorsToCheckpoint int

CurrentTotalSharesETH *big.Float
Status int

// if you completed a new checkpoint right now, how many shares would you get?
//
// this is computed as:
// - If checkpoint is already started:
// sum(beacon chain balances) + currentCheckpoint.podBalanceGwei + pod.withdrawableRestakedExecutionLayerGwei()
// - If no checkpoint is started:
// total_shares_after_checkpoint = sum(validator[i].regular_balance) + (balanceOf(pod) rounded down to gwei) - withdrawableRestakedExecutionLayerGwei
TotalSharesAfterCheckpointGwei *big.Float
TotalSharesAfterCheckpointETH *big.Float

PodOwner gethCommon.Address
ProofSubmitter gethCommon.Address

// Whether the checkpoint would need to be started with the `--force` flag.
// This would be due to the pod not having any uncheckpointed native ETH
MustForceCheckpoint bool
}

func AnalyzePods(ctx context.Context, pods map[string]PodInfo, eth *ethclient.Client, beaconClient BeaconClient) PodAnalysis {
fmt.Printf("Analyzing %d pods\n", len(pods))

beaconState, err := beaconClient.GetBeaconState(ctx, "head")
PanicOnError("failed to fetch beacon state: %w", err)

var inactiveFound bool
var problemsFound bool
podsAnalyzed := 0
validatorsAnalyzed := 0
numWithExitEpochs := 0

for addr, _ := range pods {
podValidators, err := FindAllValidatorsForEigenpod(addr, beaconState)
PanicOnError("failed to fetch validators for pod: %w", err)

podsAnalyzed++
validatorsAnalyzed += len(podValidators)

if podsAnalyzed%100 == 0 {
fmt.Printf("Analyzed %d/%d pods (%d total validators | %d total exited)...\n", podsAnalyzed, len(pods), validatorsAnalyzed, numWithExitEpochs)
}

var inactiveValidators []ValidatorWithIndex
for _, validator := range podValidators {
if validator.Validator.ActivationEpoch == math.MaxUint64 {
inactiveFound = true
inactiveValidators = append(inactiveValidators, validator)
}

if validator.Validator.ExitEpoch != math.MaxUint64 {
numWithExitEpochs++
}
}

if len(inactiveValidators) == 0 {
continue
}

fmt.Printf("Found %d inactive validators in pod %s\n", len(inactiveValidators), addr)

inactiveValidatorsWithInfo, err := FetchMultipleOnchainValidatorInfo(context.Background(), eth, addr, inactiveValidators)
PanicOnError("failed to fetch onchain info for pod: %w", err)

var problemValidators []ValidatorWithOnchainInfo
for _, validator := range inactiveValidatorsWithInfo {
if validator.Info.Status == ValidatorStatusActive {
problemValidators = append(problemValidators, validator)
}
}

if len(problemValidators) == 0 {
continue
}

fmt.Printf("Found %d problematic validators in pod %s\n", len(problemValidators), addr)
}

if !inactiveFound {
fmt.Printf("Didn't find any inactive validators!\n")
}

if !problemsFound {
fmt.Printf("Didn't find any problematic validators!\n")
}

return PodAnalysis{}
}
18 changes: 18 additions & 0 deletions cli/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,24 @@ func main() {
})
},
},
{
Name: "analyze",
Usage: "Checks for inactive validators with verified withdrawal credentials",
Flags: []cli.Flag{
BeaconNodeFlag,
ExecNodeFlag,
},
Action: func(_ *cli.Context) error {
return commands.AnalyzeCommand(commands.TAnalyzeArgs{
EigenpodAddress: eigenpodAddress,
DisableColor: disableColor,
UseJSON: useJSON,
Node: node,
BeaconNode: beacon,
Verbose: verbose,
})
},
},
{
Name: "checkpoint",
Aliases: []string{"cp"},
Expand Down
Loading