diff --git a/cli/commands/assignSubmitter.go b/cli/commands/assignSubmitter.go index a6a2480c..884bb4bf 100644 --- a/cli/commands/assignSubmitter.go +++ b/cli/commands/assignSubmitter.go @@ -5,7 +5,7 @@ import ( "fmt" "github.com/Layr-Labs/eigenlayer-contracts/pkg/bindings/EigenPod" - "github.com/Layr-Labs/eigenpod-proofs-generation/cli/core" + "github.com/Layr-Labs/eigenpod-proofs-generation/cli/core/utils" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/ethclient" "github.com/fatih/color" @@ -39,7 +39,7 @@ func AssignSubmitterCommand(args TAssignSubmitterArgs) error { return fmt.Errorf("failed to reach eth node for chain id: %w", err) } - ownerAccount, err := core.PrepareAccount(&args.Sender, chainId, false /* noSend */) + ownerAccount, err := utils.PrepareAccount(&args.Sender, chainId, false /* noSend */) if err != nil { return fmt.Errorf("failed to parse --sender: %w", err) } @@ -60,7 +60,7 @@ func AssignSubmitterCommand(args TAssignSubmitterArgs) error { if !args.NoPrompt { fmt.Printf("Your pod's current proof submitter is %s.\n", currentSubmitter) - core.PanicIfNoConsent(fmt.Sprintf("This will update your EigenPod to allow %s to submit proofs on its behalf. As the EigenPod's owner, you can always change this later.", newSubmitter)) + utils.PanicIfNoConsent(fmt.Sprintf("This will update your EigenPod to allow %s to submit proofs on its behalf. As the EigenPod's owner, you can always change this later.", newSubmitter)) } txn, err := pod.SetProofSubmitter(ownerAccount.TransactionOptions, newSubmitter) diff --git a/cli/commands/checkpoint.go b/cli/commands/checkpoint.go index 04bbce60..1867c7d0 100644 --- a/cli/commands/checkpoint.go +++ b/cli/commands/checkpoint.go @@ -5,12 +5,13 @@ import ( "github.com/Layr-Labs/eigenlayer-contracts/pkg/bindings/EigenPod" "github.com/Layr-Labs/eigenpod-proofs-generation/cli/core" - "github.com/Layr-Labs/eigenpod-proofs-generation/cli/utils" + "github.com/Layr-Labs/eigenpod-proofs-generation/cli/core/utils" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" "github.com/fatih/color" "github.com/pkg/errors" + lo "github.com/samber/lo" ) type TCheckpointCommandArgs struct { @@ -36,23 +37,23 @@ func CheckpointCommand(args TCheckpointCommandArgs) error { isGasEstimate := args.SimulateTransaction && args.Sender != "" isVerbose := !args.SimulateTransaction || args.Verbose - eth, beaconClient, chainId, err := core.GetClients(ctx, args.Node, args.BeaconNode, isVerbose) - core.PanicOnError("failed to reach ethereum clients", err) + eth, beaconClient, chainId, err := utils.GetClients(ctx, args.Node, args.BeaconNode, isVerbose) + utils.PanicOnError("failed to reach ethereum clients", err) - currentCheckpoint, err := core.GetCurrentCheckpoint(args.EigenpodAddress, eth) - core.PanicOnError("failed to load checkpoint", err) + currentCheckpoint, err := utils.GetCurrentCheckpoint(args.EigenpodAddress, eth) + utils.PanicOnError("failed to load checkpoint", err) eigenpod, err := EigenPod.NewEigenPod(common.HexToAddress(args.EigenpodAddress), eth) - core.PanicOnError("failed to connect to eigenpod", err) + utils.PanicOnError("failed to connect to eigenpod", err) if currentCheckpoint == 0 { if len(args.Sender) > 0 || args.SimulateTransaction { if !args.NoPrompt && !args.SimulateTransaction { - core.PanicIfNoConsent(core.StartCheckpointProofConsent()) + utils.PanicIfNoConsent(utils.StartCheckpointProofConsent()) } - txn, err := core.StartCheckpoint(ctx, args.EigenpodAddress, args.Sender, chainId, eth, args.ForceCheckpoint, args.SimulateTransaction) - core.PanicOnError("failed to start checkpoint", err) + txn, err := utils.StartCheckpoint(ctx, args.EigenpodAddress, args.Sender, chainId, eth, args.ForceCheckpoint, args.SimulateTransaction) + utils.PanicOnError("failed to start checkpoint", err) if !args.SimulateTransaction { color.Green("starting checkpoint: %s.. (waiting for txn to be mined)", txn.Hash().Hex()) @@ -60,7 +61,7 @@ func CheckpointCommand(args TCheckpointCommandArgs) error { color.Green("started checkpoint! txn: %s", txn.Hash().Hex()) } else { gas := txn.Gas() - printAsJSON([]Transaction{ + PrintAsJSON([]Transaction{ { Type: "checkpoint_start", To: txn.To().Hex(), @@ -78,11 +79,11 @@ func CheckpointCommand(args TCheckpointCommandArgs) error { } newCheckpoint, err := eigenpod.CurrentCheckpointTimestamp(nil) - core.PanicOnError("failed to fetch current checkpoint", err) + utils.PanicOnError("failed to fetch current checkpoint", err) currentCheckpoint = newCheckpoint } else { - core.PanicOnError("no checkpoint active and no private key provided to start one", errors.New("no checkpoint")) + utils.PanicOnError("no checkpoint active and no private key provided to start one", errors.New("no checkpoint")) } } @@ -91,24 +92,24 @@ func CheckpointCommand(args TCheckpointCommandArgs) error { } proof, err := core.GenerateCheckpointProof(ctx, args.EigenpodAddress, eth, chainId, beaconClient, isVerbose) - core.PanicOnError("failed to generate checkpoint proof", err) + utils.PanicOnError("failed to generate checkpoint proof", err) txns, err := core.SubmitCheckpointProof(ctx, args.Sender, args.EigenpodAddress, chainId, proof, eth, args.BatchSize, args.NoPrompt, args.SimulateTransaction, args.Verbose) if args.SimulateTransaction { - printableTxns := utils.Map(txns, func(txn *types.Transaction, _ uint64) Transaction { + printableTxns := lo.Map(txns, func(txn *types.Transaction, _ int) Transaction { return Transaction{ To: txn.To().Hex(), CallData: common.Bytes2Hex(txn.Data()), Type: "checkpoint_proof", } }) - printAsJSON(printableTxns) + PrintAsJSON(printableTxns) } else { for i, txn := range txns { color.Green("transaction(%d): %s", i, txn.Hash().Hex()) } } - core.PanicOnError("an error occurred while submitting your checkpoint proofs", err) + utils.PanicOnError("an error occurred while submitting your checkpoint proofs", err) return nil } diff --git a/cli/commands/completeAllWithdrawals.go b/cli/commands/completeAllWithdrawals.go index abf58e95..6ca9d0ae 100644 --- a/cli/commands/completeAllWithdrawals.go +++ b/cli/commands/completeAllWithdrawals.go @@ -11,6 +11,7 @@ import ( "github.com/Layr-Labs/eigenlayer-contracts/pkg/bindings/EigenPod" "github.com/Layr-Labs/eigenlayer-contracts/pkg/bindings/IDelegationManager" "github.com/Layr-Labs/eigenpod-proofs-generation/cli/core" + "github.com/Layr-Labs/eigenpod-proofs-generation/cli/core/utils" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/ethclient" @@ -43,35 +44,35 @@ func CompleteAllWithdrawalsCommand(args TCompleteWithdrawalArgs) error { isSimulation := args.EstimateGas eth, err := ethclient.DialContext(ctx, args.EthNode) - core.PanicOnError("failed to reach eth node", err) + utils.PanicOnError("failed to reach eth node", err) chainId, err := eth.ChainID(ctx) - core.PanicOnError("failed to load chainId", err) + utils.PanicOnError("failed to load chainId", err) - acc, err := core.PrepareAccount(&args.Sender, chainId, isSimulation) - core.PanicOnError("failed to parse private key", err) + acc, err := utils.PrepareAccount(&args.Sender, chainId, isSimulation) + utils.PanicOnError("failed to parse private key", err) curBlockNumber, err := eth.BlockNumber(ctx) - core.PanicOnError("failed to load current block number", err) + utils.PanicOnError("failed to load current block number", err) pod, err := EigenPod.NewEigenPod(common.HexToAddress(args.EigenPod), eth) - core.PanicOnError("failed to reach eigenpod", err) + utils.PanicOnError("failed to reach eigenpod", err) reg, err := pod.WithdrawableRestakedExecutionLayerGwei(nil) - core.PanicOnError("failed to fetch REG", err) - rew := core.GweiToWei(new(big.Float).SetUint64(reg)) + utils.PanicOnError("failed to fetch REG", err) + rew := utils.GweiToWei(new(big.Float).SetUint64(reg)) podOwner, err := pod.PodOwner(nil) - core.PanicOnError("failed to read podOwner", err) + utils.PanicOnError("failed to read podOwner", err) delegationManager, err := IDelegationManager.NewIDelegationManager(DelegationManager(chainId), eth) - core.PanicOnError("failed to reach delegation manager", err) + utils.PanicOnError("failed to reach delegation manager", err) minDelay, err := delegationManager.MinWithdrawalDelayBlocks(nil) - core.PanicOnError("failed to read MinWithdrawalDelayBlocks", err) + utils.PanicOnError("failed to read MinWithdrawalDelayBlocks", err) queuedWithdrawals, err := delegationManager.GetQueuedWithdrawals(nil, podOwner) - core.PanicOnError("failed to read queuedWithdrawals", err) + utils.PanicOnError("failed to read queuedWithdrawals", err) eligibleWithdrawals := lo.Map(queuedWithdrawals.Withdrawals, func(withdrawal IDelegationManager.IDelegationManagerTypesWithdrawal, index int) *IDelegationManager.IDelegationManagerTypesWithdrawal { isBeaconWithdrawal := len(withdrawal.Strategies) == 1 && withdrawal.Strategies[0].Cmp(core.BeaconStrategy()) == 0 @@ -128,10 +129,10 @@ func CompleteAllWithdrawalsCommand(args TCompleteWithdrawalArgs) error { fmt.Printf("Your podOwner(%s) has %d withdrawal(s) that can be completed right now.\n", podOwner.Hex(), len(affordedWithdrawals)) runningSumWeiInt, _ := runningSumWei.Int(nil) - fmt.Printf("Total ETH on all withdrawals: %sETH\n", core.GweiToEther(core.WeiToGwei(runningSumWeiInt)).String()) + fmt.Printf("Total ETH on all withdrawals: %sETH\n", utils.GweiToEther(utils.WeiToGwei(runningSumWeiInt)).String()) if !isSimulation { - core.PanicIfNoConsent("Would you like to continue?") + utils.PanicIfNoConsent("Would you like to continue?") } else { color.Yellow("THIS IS A SIMULATION. No transaction will be recorded onchain.\n") } @@ -149,15 +150,15 @@ func CompleteAllWithdrawalsCommand(args TCompleteWithdrawalArgs) error { }) txn, err := delegationManager.CompleteQueuedWithdrawals(acc.TransactionOptions, withdrawals, tokens, receiveAsTokens) - core.PanicOnError("CompleteQueuedWithdrawals failed.", err) + utils.PanicOnError("CompleteQueuedWithdrawals failed.", err) if !isSimulation { _, err := bind.WaitMined(ctx, eth, txn) - core.PanicOnError("waitMined failed", err) + utils.PanicOnError("waitMined failed", err) color.Green("%s\n", txn.Hash().Hex()) } else { - printAsJSON(Transaction{ + PrintAsJSON(Transaction{ Type: "complete-withdrawals", To: txn.To().Hex(), CallData: common.Bytes2Hex(txn.Data()), diff --git a/cli/commands/credentials.go b/cli/commands/credentials.go index 86ee399c..2c7785de 100644 --- a/cli/commands/credentials.go +++ b/cli/commands/credentials.go @@ -7,10 +7,11 @@ import ( "math/big" "github.com/Layr-Labs/eigenpod-proofs-generation/cli/core" - "github.com/Layr-Labs/eigenpod-proofs-generation/cli/utils" + "github.com/Layr-Labs/eigenpod-proofs-generation/cli/core/utils" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" "github.com/fatih/color" + lo "github.com/samber/lo" ) type TCredentialCommandArgs struct { @@ -37,8 +38,8 @@ func CredentialsCommand(args TCredentialCommandArgs) error { isGasEstimate := args.SimulateTransaction && args.Sender != "" isVerbose := (!args.UseJSON && !args.SimulateTransaction) || args.Verbose - eth, beaconClient, chainId, err := core.GetClients(ctx, args.Node, args.BeaconNode, isVerbose) - core.PanicOnError("failed to reach ethereum clients", err) + eth, beaconClient, chainId, err := utils.GetClients(ctx, args.Node, args.BeaconNode, isVerbose) + utils.PanicOnError("failed to reach ethereum clients", err) var specificValidatorIndex *big.Int = nil if args.SpecificValidator != math.MaxUint64 && args.SpecificValidator != 0 { @@ -51,13 +52,13 @@ func CredentialsCommand(args TCredentialCommandArgs) error { validatorProofs, oracleBeaconTimestamp, err := core.GenerateValidatorProof(ctx, args.EigenpodAddress, eth, chainId, beaconClient, specificValidatorIndex, isVerbose) if err != nil || validatorProofs == nil { - core.PanicOnError("Failed to generate validator proof", err) - core.Panic("no inactive validators") + utils.PanicOnError("Failed to generate validator proof", err) + utils.Panic("no inactive validators") } if len(args.Sender) != 0 || args.SimulateTransaction { txns, indices, err := core.SubmitValidatorProof(ctx, args.Sender, args.EigenpodAddress, chainId, eth, args.BatchSize, validatorProofs, oracleBeaconTimestamp, args.NoPrompt, args.SimulateTransaction, isVerbose) - core.PanicOnError(fmt.Sprintf("failed to %s validator proof", func() string { + utils.PanicOnError(fmt.Sprintf("failed to %s validator proof", func() string { if args.SimulateTransaction { return "simulate" } else { @@ -66,7 +67,7 @@ func CredentialsCommand(args TCredentialCommandArgs) error { }()), err) if args.SimulateTransaction { - out := utils.Map(txns, func(txn *types.Transaction, _ uint64) CredentialProofTransaction { + out := lo.Map(txns, func(txn *types.Transaction, _ int) CredentialProofTransaction { gas := txn.Gas() return CredentialProofTransaction{ Transaction: Transaction{ @@ -80,12 +81,12 @@ func CredentialsCommand(args TCredentialCommandArgs) error { return nil }(), }, - ValidatorIndices: utils.Map(utils.Flatten(indices), func(index *big.Int, _ uint64) uint64 { + ValidatorIndices: lo.Map(lo.Flatten(indices), func(index *big.Int, _ int) uint64 { return index.Uint64() }), } }) - printAsJSON(out) + PrintAsJSON(out) } else { for i, txn := range txns { color.Green("transaction(%d): %s", i, txn.Hash().Hex()) diff --git a/cli/commands/findStalePods.go b/cli/commands/findStalePods.go index 32f5babc..c22a2b5a 100644 --- a/cli/commands/findStalePods.go +++ b/cli/commands/findStalePods.go @@ -5,6 +5,7 @@ import ( "fmt" "github.com/Layr-Labs/eigenpod-proofs-generation/cli/core" + "github.com/Layr-Labs/eigenpod-proofs-generation/cli/core/utils" "github.com/fatih/color" ) @@ -17,14 +18,14 @@ type TFindStalePodsCommandArgs struct { func FindStalePodsCommand(args TFindStalePodsCommandArgs) error { ctx := context.Background() - eth, beacon, chainId, err := core.GetClients(ctx, args.EthNode, args.BeaconNode /* verbose */, args.Verbose) - core.PanicOnError("failed to dial clients", err) + eth, beacon, chainId, err := utils.GetClients(ctx, args.EthNode, args.BeaconNode /* verbose */, args.Verbose) + utils.PanicOnError("failed to dial clients", err) results, err := core.FindStaleEigenpods(ctx, eth, args.EthNode, beacon, chainId, args.Verbose, args.Tolerance) - core.PanicOnError("failed to find stale eigenpods", err) + utils.PanicOnError("failed to find stale eigenpods", err) if !args.Verbose { - printAsJSON(results) + PrintAsJSON(results) return nil } diff --git a/cli/commands/queueWithdrawal.go b/cli/commands/queueWithdrawal.go index eeaed4f2..05f8912e 100644 --- a/cli/commands/queueWithdrawal.go +++ b/cli/commands/queueWithdrawal.go @@ -9,6 +9,7 @@ import ( "github.com/Layr-Labs/eigenlayer-contracts/pkg/bindings/EigenPod" "github.com/Layr-Labs/eigenlayer-contracts/pkg/bindings/IDelegationManager" "github.com/Layr-Labs/eigenpod-proofs-generation/cli/core" + "github.com/Layr-Labs/eigenpod-proofs-generation/cli/core/utils" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/ethclient" @@ -29,36 +30,36 @@ func QueueWithdrawalCommand(args TQueueWithdrawallArgs) error { isSimulation := args.EstimateGas eth, err := ethclient.DialContext(ctx, args.EthNode) - core.PanicOnError("failed to reach eth node", err) + utils.PanicOnError("failed to reach eth node", err) chainId, err := eth.ChainID(ctx) - core.PanicOnError("failed to load chainId", err) + utils.PanicOnError("failed to load chainId", err) - acc, err := core.PrepareAccount(&args.Sender, chainId, args.EstimateGas) - core.PanicOnError("failed to parse private key", err) + acc, err := utils.PrepareAccount(&args.Sender, chainId, args.EstimateGas) + utils.PanicOnError("failed to parse private key", err) dm, err := IDelegationManager.NewIDelegationManager(DelegationManager(chainId), eth) - core.PanicOnError("failed to reach delegation manager", err) + utils.PanicOnError("failed to reach delegation manager", err) pod, err := EigenPod.NewEigenPod(common.HexToAddress(args.EigenPod), eth) - core.PanicOnError("failed to reach eigenpod", err) + utils.PanicOnError("failed to reach eigenpod", err) _reg, err := pod.WithdrawableRestakedExecutionLayerGwei(nil) - core.PanicOnError("failed to load REG", err) + utils.PanicOnError("failed to load REG", err) // [withdrawable]RestakedExecutionlayerWei - rew := core.GweiToWei(new(big.Float).SetUint64(_reg)) + rew := utils.GweiToWei(new(big.Float).SetUint64(_reg)) if args.AmountWei > 0 && new(big.Float).SetUint64(args.AmountWei).Cmp(rew) > 0 { return errors.New("invalid --amountWei. must be in the range (0, pod.withdrawableRestakedExecutionLayerGwei() as wei]") } podOwner, err := pod.PodOwner(nil) - core.PanicOnError("failed to read podOwner", err) + utils.PanicOnError("failed to read podOwner", err) reg := new(big.Int).SetUint64(_reg) // TODO: maximumWithdrawalSizeGwei = reg - gwei(sumQueuedWithdrawals) - maximumWithdrawalSizeWei := core.IGweiToWei(reg) + maximumWithdrawalSizeWei := utils.IGweiToWei(reg) var requestedWithdrawalSizeWei *big.Int if args.AmountWei == 0 { // default to the number of withdrawable shares in the beacon strategy @@ -71,45 +72,45 @@ func QueueWithdrawalCommand(args TQueueWithdrawallArgs) error { if requestedWithdrawalSizeWei.Cmp(maximumWithdrawalSizeWei) > 0 { color.Red( "Error: the amount to withdraw from the native ETH strategy (%sETH) is larger than the total withdrawable amount from the pod (%sETH). Will attempt a smaller withdrawal.\n", - core.IweiToEther(requestedWithdrawalSizeWei).String(), - core.IweiToEther(maximumWithdrawalSizeWei).String(), + utils.IweiToEther(requestedWithdrawalSizeWei).String(), + utils.IweiToEther(maximumWithdrawalSizeWei).String(), ) return errors.New("requested to withdraw too many shares") } _depositShares, err := dm.ConvertToDepositShares(nil, podOwner, []common.Address{core.BeaconStrategy()}, []*big.Int{requestedWithdrawalSizeWei}) - core.PanicOnError("failed to compute deposit shares", err) + utils.PanicOnError("failed to compute deposit shares", err) depositShares := _depositShares[0] minWithdrawalDelay, err := dm.MinWithdrawalDelayBlocks(nil) - core.PanicOnError("failed to load minWithdrawalDelay", err) + utils.PanicOnError("failed to load minWithdrawalDelay", err) curBlock, err := eth.BlockNumber(ctx) - core.PanicOnError("failed to load current block number", err) + utils.PanicOnError("failed to load current block number", err) - requestedWithdrawalSizeEth := core.GweiToEther(core.WeiToGwei(requestedWithdrawalSizeWei)) + requestedWithdrawalSizeEth := utils.GweiToEther(utils.WeiToGwei(requestedWithdrawalSizeWei)) color.Blue("Withdrawing: %sETH.\n", requestedWithdrawalSizeEth.String()) color.Yellow("NOTE: If you were or become slashed on EigenLayer during the withdrawal period, the total amount received will be less any slashed amount.\n") if !isSimulation { - core.PanicIfNoConsent(fmt.Sprintf("Would you like to queue a withdrawal %sETH from the Native ETH strategy? This will be withdrawable after approximately block #%d (current block: %d)\n", requestedWithdrawalSizeEth.String(), curBlock+uint64(minWithdrawalDelay), curBlock)) + utils.PanicIfNoConsent(fmt.Sprintf("Would you like to queue a withdrawal %sETH from the Native ETH strategy? This will be withdrawable after approximately block #%d (current block: %d)\n", requestedWithdrawalSizeEth.String(), curBlock+uint64(minWithdrawalDelay), curBlock)) } else { fmt.Printf("THIS IS A SIMULATION. No transaction will be recorded onchain.\n") } txn, err := dm.QueueWithdrawals(acc.TransactionOptions, []IDelegationManager.IDelegationManagerTypesQueuedWithdrawalParams{ { - Strategies: []common.Address{core.BeaconStrategy()}, - DepositShares: []*big.Int{depositShares}, - Withdrawer: podOwner, + Strategies: []common.Address{core.BeaconStrategy()}, + DepositShares: []*big.Int{depositShares}, + DeprecatedWithdrawer: podOwner, }, }) - core.PanicOnError("failed to queue withdrawal", err) + utils.PanicOnError("failed to queue withdrawal", err) if !isSimulation { txnReceipt, err := bind.WaitMined(ctx, eth, txn) - core.PanicOnError("failed to wait for txn", err) + utils.PanicOnError("failed to wait for txn", err) color.Green("%s\n", txnReceipt.TxHash.Hex()) } else { - printAsJSON(Transaction{ + PrintAsJSON(Transaction{ Type: "queue-withdrawal", To: txn.To().Hex(), CallData: common.Bytes2Hex(txn.Data()), diff --git a/cli/commands/showWithdrawals.go b/cli/commands/showWithdrawals.go index 943b4faa..f3a19ada 100644 --- a/cli/commands/showWithdrawals.go +++ b/cli/commands/showWithdrawals.go @@ -7,6 +7,7 @@ import ( "github.com/Layr-Labs/eigenlayer-contracts/pkg/bindings/EigenPod" "github.com/Layr-Labs/eigenlayer-contracts/pkg/bindings/IDelegationManager" "github.com/Layr-Labs/eigenpod-proofs-generation/cli/core" + "github.com/Layr-Labs/eigenpod-proofs-generation/cli/core/utils" "github.com/ethereum/go-ethereum/common" ) @@ -18,23 +19,23 @@ type TShowWithdrawalArgs struct { func ShowWithdrawalsCommand(args TShowWithdrawalArgs) error { ctx := context.Background() - eth, chainId, err := core.GetEthClient(ctx, args.EthNode) - core.PanicOnError("failed to reach eth and beacon node", err) + eth, chainId, err := utils.GetEthClient(ctx, args.EthNode) + utils.PanicOnError("failed to reach eth and beacon node", err) curBlock, err := eth.BlockByNumber(ctx, nil) /* head */ - core.PanicOnError("failed to load curBlock", err) + utils.PanicOnError("failed to load curBlock", err) dm, err := IDelegationManager.NewIDelegationManager(DelegationManager(chainId), eth) - core.PanicOnError("failed to reach delegation manager", err) + utils.PanicOnError("failed to reach delegation manager", err) pod, err := EigenPod.NewEigenPod(common.HexToAddress(args.EigenPod), eth) - core.PanicOnError("failed to reach eigenpod manager", err) + utils.PanicOnError("failed to reach eigenpod manager", err) podOwner, err := pod.PodOwner(nil) - core.PanicOnError("failed to load podOwner", err) + utils.PanicOnError("failed to load podOwner", err) allWithdrawals, err := dm.GetQueuedWithdrawals(nil, podOwner) - core.PanicOnError("failed to get queued withdrawals", err) + utils.PanicOnError("failed to get queued withdrawals", err) type TWithdrawalInfo struct { Staker string @@ -46,7 +47,7 @@ func ShowWithdrawalsCommand(args TShowWithdrawalArgs) error { } minDelay, err := dm.MinWithdrawalDelayBlocks(nil) - core.PanicOnError("failed to get minWithdrawalDelay", err) + utils.PanicOnError("failed to get minWithdrawalDelay", err) withdrawalInfo := []TWithdrawalInfo{} @@ -61,7 +62,7 @@ func ShowWithdrawalsCommand(args TShowWithdrawalArgs) error { targetBlock := new(big.Int).SetUint64(uint64(allWithdrawals.Withdrawals[i].StartBlock + minDelay)) withdrawalInfo = append(withdrawalInfo, TWithdrawalInfo{ - TotalAmountETH: core.GweiToEther(core.WeiToGwei(shares[0])), + TotalAmountETH: utils.GweiToEther(utils.WeiToGwei(shares[0])), Strategy: allWithdrawals.Withdrawals[i].Strategies[0], Staker: allWithdrawals.Withdrawals[i].Staker.Hex(), CurrentBlock: curBlock.NumberU64(), @@ -70,6 +71,6 @@ func ShowWithdrawalsCommand(args TShowWithdrawalArgs) error { }) } - printAsJSON(withdrawalInfo) + PrintAsJSON(withdrawalInfo) return nil } diff --git a/cli/commands/staleBalance.go b/cli/commands/staleBalance.go index e172bf46..958fec66 100644 --- a/cli/commands/staleBalance.go +++ b/cli/commands/staleBalance.go @@ -8,6 +8,7 @@ import ( "github.com/Layr-Labs/eigenlayer-contracts/pkg/bindings/EigenPod" eigenpodproofs "github.com/Layr-Labs/eigenpod-proofs-generation" "github.com/Layr-Labs/eigenpod-proofs-generation/cli/core" + "github.com/Layr-Labs/eigenpod-proofs-generation/cli/core/utils" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/fatih/color" @@ -43,36 +44,36 @@ func FixStaleBalance(args TFixStaleBalanceArgs) error { sentTxns := []TransactionDescription{} - eth, beacon, chainId, err := core.GetClients(ctx, args.EthNode, args.BeaconNode, args.Verbose) - core.PanicOnError("failed to get clients", err) + eth, beacon, chainId, err := utils.GetClients(ctx, args.EthNode, args.BeaconNode, args.Verbose) + utils.PanicOnError("failed to get clients", err) validator, err := beacon.GetValidator(ctx, args.SlashedValidatorIndex) - core.PanicOnError("failed to fetch validator state", err) + utils.PanicOnError("failed to fetch validator state", err) if !validator.Validator.Slashed { - core.Panic("Provided validator was not slashed.") + utils.Panic("Provided validator was not slashed.") return nil } - ownerAccount, err := core.PrepareAccount(&args.Sender, chainId, false /* noSend */) - core.PanicOnError("failed to parse sender PK", err) + ownerAccount, err := utils.PrepareAccount(&args.Sender, chainId, false /* noSend */) + utils.PanicOnError("failed to parse sender PK", err) eigenpod, err := EigenPod.NewEigenPod(common.HexToAddress(args.EigenpodAddress), eth) - core.PanicOnError("failed to reach eigenpod", err) + utils.PanicOnError("failed to reach eigenpod", err) currentCheckpointTimestamp, err := eigenpod.CurrentCheckpointTimestamp(nil) - core.PanicOnError("failed to fetch any existing checkpoint info", err) + utils.PanicOnError("failed to fetch any existing checkpoint info", err) if currentCheckpointTimestamp > 0 { if !args.NoPrompt { - core.PanicIfNoConsent(fmt.Sprintf("This eigenpod has an outstanding checkpoint (since %d). You must complete it before continuing. This will invoke `EigenPod.verifyCheckpointProofs()`, which will end the checkpoint. This may be expensive.", currentCheckpointTimestamp)) + utils.PanicIfNoConsent(fmt.Sprintf("This eigenpod has an outstanding checkpoint (since %d). You must complete it before continuing. This will invoke `EigenPod.verifyCheckpointProofs()`, which will end the checkpoint. This may be expensive.", currentCheckpointTimestamp)) } proofs, err := core.GenerateCheckpointProof(ctx, args.EigenpodAddress, eth, chainId, beacon, args.Verbose) - core.PanicOnError("failed to generate checkpoint proofs", err) + utils.PanicOnError("failed to generate checkpoint proofs", err) txns, err := core.SubmitCheckpointProof(ctx, args.Sender, args.EigenpodAddress, chainId, proofs, eth, args.CheckpointBatchSize, args.NoPrompt, false /* noSend */, args.Verbose) - core.PanicOnError("failed to submit checkpoint proofs", err) + utils.PanicOnError("failed to submit checkpoint proofs", err) for i, txn := range txns { if args.Verbose { @@ -84,10 +85,10 @@ func FixStaleBalance(args TFixStaleBalanceArgs) error { } 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) + utils.PanicOnError("failed to generate credential proof for slashed validator", err) if !args.NoPrompt { - core.PanicIfNoConsent("This will invoke `EigenPod.verifyStaleBalance()` on the given eigenpod, which will start a checkpoint. Once started, this checkpoint must be completed.") + utils.PanicIfNoConsent("This will invoke `EigenPod.verifyStaleBalance()` on the given eigenpod, which will start a checkpoint. Once started, this checkpoint must be completed.") } if args.Verbose { @@ -106,9 +107,9 @@ func FixStaleBalance(args TFixStaleBalanceArgs) error { Proof: proof.ValidatorFieldsProofs[0].ToByteSlice(), }, ) - core.PanicOnError("failed to call verifyStaleBalance()", err) + utils.PanicOnError("failed to call verifyStaleBalance()", err) sentTxns = append(sentTxns, TransactionDescription{Type: "verify_stale_balance", Hash: txn.Hash().Hex()}) - printAsJSON(sentTxns) + PrintAsJSON(sentTxns) return nil } diff --git a/cli/commands/status.go b/cli/commands/status.go index bb9b90a2..2e66ce0f 100644 --- a/cli/commands/status.go +++ b/cli/commands/status.go @@ -9,7 +9,8 @@ import ( "time" "github.com/Layr-Labs/eigenpod-proofs-generation/cli/core" - "github.com/Layr-Labs/eigenpod-proofs-generation/cli/utils" + "github.com/Layr-Labs/eigenpod-proofs-generation/cli/core/utils" + cliutils "github.com/Layr-Labs/eigenpod-proofs-generation/cli/utils" "github.com/fatih/color" ) @@ -30,14 +31,14 @@ func StatusCommand(args TStatusArgs) error { isVerbose := !args.UseJSON - eth, beaconClient, _, err := core.GetClients(ctx, args.Node, args.BeaconNode, isVerbose) - core.PanicOnError("failed to load ethereum clients", err) + eth, beaconClient, _, err := utils.GetClients(ctx, args.Node, args.BeaconNode, isVerbose) + utils.PanicOnError("failed to load ethereum clients", err) status := core.GetStatus(ctx, args.EigenpodAddress, eth, beaconClient) if args.UseJSON { bytes, err := json.MarshalIndent(status, "", " ") - core.PanicOnError("failed to get status", err) + utils.PanicOnError("failed to get status", err) statusStr := string(bytes) fmt.Println(statusStr) return nil @@ -55,7 +56,7 @@ func StatusCommand(args TStatusArgs) error { // sort validators by status awaitingActivationQueueValidators, inactiveValidators, activeValidators, withdrawnValidators := - core.SortByStatus(status.Validators) + utils.SortByStatus(status.Validators) var targetColor *color.Color bold.Printf("Eigenpod validators:\n============\n") @@ -74,7 +75,7 @@ func StatusCommand(args TStatusArgs) error { for _, validator := range awaitingActivationQueueValidators { publicKey := validator.PublicKey if !isVerbose { - publicKey = utils.ShortenHex(publicKey) + publicKey = cliutils.ShortenHex(publicKey) } targetColor = color.New(color.FgHiRed) @@ -97,7 +98,7 @@ func StatusCommand(args TStatusArgs) error { for _, validator := range inactiveValidators { publicKey := validator.PublicKey if !isVerbose { - publicKey = utils.ShortenHex(publicKey) + publicKey = cliutils.ShortenHex(publicKey) } if validator.Slashed { @@ -120,7 +121,7 @@ func StatusCommand(args TStatusArgs) error { for _, validator := range activeValidators { publicKey := validator.PublicKey if !isVerbose { - publicKey = utils.ShortenHex(publicKey) + publicKey = cliutils.ShortenHex(publicKey) } if validator.Slashed { @@ -143,7 +144,7 @@ func StatusCommand(args TStatusArgs) error { for _, validator := range withdrawnValidators { publicKey := validator.PublicKey if !isVerbose { - publicKey = utils.ShortenHex(publicKey) + publicKey = cliutils.ShortenHex(publicKey) } if validator.Slashed { @@ -175,8 +176,8 @@ func StatusCommand(args TStatusArgs) error { ylw.Printf("\tNote: pod does not have checkpointable native ETH. To checkpoint anyway, run `checkpoint` with the `--force` flag.\n") } - bold.Printf("Batching %d proofs per txn, this will require:\n\t", utils.DEFAULT_BATCH_CHECKPOINT) - ital.Printf("- 1x startCheckpoint() transaction, and \n\t- %dx EigenPod.verifyCheckpointProofs() transaction(s)\n\n", int(math.Ceil(float64(status.NumberValidatorsToCheckpoint)/float64(utils.DEFAULT_BATCH_CHECKPOINT)))) + bold.Printf("Batching %d proofs per txn, this will require:\n\t", cliutils.DEFAULT_BATCH_CHECKPOINT) + ital.Printf("- 1x startCheckpoint() transaction, and \n\t- %dx EigenPod.verifyCheckpointProofs() transaction(s)\n\n", int(math.Ceil(float64(status.NumberValidatorsToCheckpoint)/float64(cliutils.DEFAULT_BATCH_CHECKPOINT)))) } } return nil diff --git a/cli/commands/utils.go b/cli/commands/utils.go index 67165a85..7bcbdb41 100644 --- a/cli/commands/utils.go +++ b/cli/commands/utils.go @@ -4,7 +4,7 @@ import ( "encoding/json" "fmt" - "github.com/Layr-Labs/eigenpod-proofs-generation/cli/core" + "github.com/Layr-Labs/eigenpod-proofs-generation/cli/core/utils" ) type Transaction struct { @@ -20,28 +20,8 @@ type CredentialProofTransaction struct { ValidatorIndices []uint64 `json:"validator_indices"` } -func printAsJSON(txns any) { +func PrintAsJSON(txns any) { out, err := json.MarshalIndent(txns, " ", " ") - core.PanicOnError("failed to serialize", err) + utils.PanicOnError("failed to serialize", err) fmt.Println(string(out)) } - -func getKeys[A comparable, B any](data map[A]B) []A { - values := make([]A, len(data)) - i := 0 - for key, _ := range data { - values[i] = key - i++ - } - return values -} - -func getValues[A comparable, B any](data map[A]B) []B { - values := make([]B, len(data)) - i := 0 - for _, value := range data { - values[i] = value - i++ - } - return values -} diff --git a/cli/core/checkpoint.go b/cli/core/checkpoint.go index 5bd2db41..c9a34030 100644 --- a/cli/core/checkpoint.go +++ b/cli/core/checkpoint.go @@ -11,6 +11,7 @@ import ( "github.com/Layr-Labs/eigenlayer-contracts/pkg/bindings/EigenPod" eigenpodproofs "github.com/Layr-Labs/eigenpod-proofs-generation" + "github.com/Layr-Labs/eigenpod-proofs-generation/cli/core/utils" v1 "github.com/attestantio/go-eth2-client/api/v1" "github.com/attestantio/go-eth2-client/spec" "github.com/ethereum/go-ethereum/accounts/abi/bind" @@ -21,9 +22,9 @@ import ( ) func SubmitCheckpointProof(ctx context.Context, owner, eigenpodAddress string, chainId *big.Int, proof *eigenpodproofs.VerifyCheckpointProofsCallParams, eth *ethclient.Client, batchSize uint64, noPrompt bool, noSend bool, verbose bool) ([]*types.Transaction, error) { - tracing := GetContextTracingCallbacks(ctx) + tracing := utils.GetContextTracingCallbacks(ctx) - allProofChunks := chunk(proof.BalanceProofs, batchSize) + allProofChunks := utils.Chunk(proof.BalanceProofs, batchSize) transactions := []*types.Transaction{} if verbose { color.Green("calling EigenPod.VerifyCheckpointProofs() (using %d txn(s), max(%d) proofs per txn)", len(allProofChunks), batchSize) @@ -68,9 +69,9 @@ func SubmitCheckpointProof(ctx context.Context, owner, eigenpodAddress string, c } func SubmitCheckpointProofBatch(ctx context.Context, owner, eigenpodAddress string, chainId *big.Int, proof *eigenpodproofs.ValidatorBalancesRootProof, balanceProofs []*eigenpodproofs.BalanceProof, eth *ethclient.Client, noSend bool, verbose bool) (*types.Transaction, error) { - tracing := GetContextTracingCallbacks(ctx) + tracing := utils.GetContextTracingCallbacks(ctx) - ownerAccount, err := PrepareAccount(&owner, chainId, noSend) + ownerAccount, err := utils.PrepareAccount(&owner, chainId, noSend) if err != nil { return nil, err } @@ -93,7 +94,7 @@ func SubmitCheckpointProofBatch(ctx context.Context, owner, eigenpodAddress stri BalanceContainerRoot: proof.ValidatorBalancesRoot, Proof: proof.Proof.ToByteSlice(), }, - CastBalanceProofs(balanceProofs), + utils.CastBalanceProofs(balanceProofs), ) tracing.OnEndSection() if err != nil { @@ -124,18 +125,18 @@ func asJSON(obj interface{}) string { return string(bytes) } -func GenerateCheckpointProof(ctx context.Context, eigenpodAddress string, eth *ethclient.Client, chainId *big.Int, beaconClient BeaconClient, verbose bool) (*eigenpodproofs.VerifyCheckpointProofsCallParams, error) { - tracing := GetContextTracingCallbacks(ctx) +func GenerateCheckpointProof(ctx context.Context, eigenpodAddress string, eth *ethclient.Client, chainId *big.Int, beaconClient utils.BeaconClient, verbose bool) (*eigenpodproofs.VerifyCheckpointProofsCallParams, error) { + tracing := utils.GetContextTracingCallbacks(ctx) tracing.OnStartSection("GetCurrentCheckpoint", map[string]string{}) - currentCheckpoint, err := GetCurrentCheckpoint(eigenpodAddress, eth) + currentCheckpoint, err := utils.GetCurrentCheckpoint(eigenpodAddress, eth) if err != nil { return nil, err } tracing.OnEndSection() tracing.OnStartSection("GetCurrentCheckpointBlockRoot", map[string]string{}) - blockRoot, err := GetCurrentCheckpointBlockRoot(eigenpodAddress, eth) + blockRoot, err := utils.GetCurrentCheckpointBlockRoot(eigenpodAddress, eth) if err != nil { return nil, fmt.Errorf("failed to fetch last checkpoint: %w", err) } @@ -145,7 +146,7 @@ func GenerateCheckpointProof(ctx context.Context, eigenpodAddress string, eth *e tracing.OnEndSection() rootBytes := *blockRoot - if AllZero(rootBytes[:]) { + if utils.AllZero(rootBytes[:]) { return nil, fmt.Errorf("no checkpoint active. Are you sure you started a checkpoint?") } @@ -173,11 +174,11 @@ func GenerateCheckpointProof(ctx context.Context, eigenpodAddress string, eth *e } func GenerateCheckpointProofForState(ctx context.Context, eigenpodAddress string, beaconState *spec.VersionedBeaconState, header *v1.BeaconBlockHeader, eth *ethclient.Client, currentCheckpointTimestamp uint64, proofs *eigenpodproofs.EigenPodProofs, verbose bool) (*eigenpodproofs.VerifyCheckpointProofsCallParams, error) { - tracing := GetContextTracingCallbacks(ctx) + tracing := utils.GetContextTracingCallbacks(ctx) // filter through the beaconState's validators, and select only ones that have withdrawal address set to `eigenpod`. tracing.OnStartSection("FindAllValidatorsForEigenpod", map[string]string{}) - allValidators, err := FindAllValidatorsForEigenpod(eigenpodAddress, beaconState) + allValidators, err := utils.FindAllValidatorsForEigenpod(eigenpodAddress, beaconState) if err != nil { return nil, err } @@ -187,13 +188,13 @@ func GenerateCheckpointProofForState(ctx context.Context, eigenpodAddress string color.Yellow("You have a total of %d validators pointed to this pod.", len(allValidators)) } - allValidatorsWithInfo, err := FetchMultipleOnchainValidatorInfo(ctx, eth, eigenpodAddress, allValidators) + allValidatorsWithInfo, err := utils.FetchMultipleOnchainValidatorInfo(ctx, eth, eigenpodAddress, allValidators) if err != nil { return nil, err } tracing.OnStartSection("SelectCheckpointableValidators", map[string]string{}) - checkpointValidators, err := SelectCheckpointableValidators(eth, eigenpodAddress, allValidatorsWithInfo, currentCheckpointTimestamp) + checkpointValidators, err := utils.SelectCheckpointableValidators(eth, eigenpodAddress, allValidatorsWithInfo, currentCheckpointTimestamp) if err != nil { return nil, err } diff --git a/cli/core/findStalePods.go b/cli/core/findStalePods.go index f9b0b11d..1cc4053d 100644 --- a/cli/core/findStalePods.go +++ b/cli/core/findStalePods.go @@ -8,12 +8,14 @@ import ( "strings" "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/samber/lo" "github.com/Layr-Labs/eigenlayer-contracts/pkg/bindings/DelegationManager" "github.com/Layr-Labs/eigenlayer-contracts/pkg/bindings/EigenPod" "github.com/Layr-Labs/eigenlayer-contracts/pkg/bindings/EigenPodManager" "github.com/Layr-Labs/eigenlayer-contracts/pkg/bindings/IEigenPod" - "github.com/Layr-Labs/eigenpod-proofs-generation/cli/utils" + "github.com/Layr-Labs/eigenpod-proofs-generation/cli/core/utils" + cliutils "github.com/Layr-Labs/eigenpod-proofs-generation/cli/utils" "github.com/attestantio/go-eth2-client/spec" "github.com/attestantio/go-eth2-client/spec/phase0" "github.com/ethereum/go-ethereum/common" @@ -35,7 +37,9 @@ func FracMul(a *big.Int, x *big.Int, y *big.Int) *big.Int { } func executionWithdrawalAddress(withdrawalCredentials []byte) *string { - if withdrawalCredentials[0] != 1 { + // after the pectra upgrade, eigenpods may be found at: + // - `0x1` or `0x2` prefixed withdrawal addresses + if withdrawalCredentials[0] != 1 && withdrawalCredentials[0] != 2 { return nil } addr := common.Bytes2Hex(withdrawalCredentials[12:]) @@ -60,7 +64,7 @@ func validEigenpodsOnly(candidateAddresses []common.Address, mc *multicall.Multi ////// step 1: cast all addresses to EigenPod, and attempt to read the pod owner. var lastError error - calls := utils.Map(candidateAddresses, func(addr common.Address, i uint64) *multicall.MultiCallMetaData[common.Address] { + calls := lo.Map(candidateAddresses, func(addr common.Address, i int) *multicall.MultiCallMetaData[common.Address] { mc, err := multicall.Describe[common.Address]( addr, EigenPodAbi, @@ -89,17 +93,17 @@ func validEigenpodsOnly(candidateAddresses []common.Address, mc *multicall.Multi Response multicall.TypedMulticall3Result[*common.Address] } - podOwnerPairs := utils.Filter(utils.Map(*reportedPodOwners, func(res multicall.TypedMulticall3Result[*common.Address], i uint64) PodOwnerResult { + podOwnerPairs := lo.Filter(lo.Map(*reportedPodOwners, func(res multicall.TypedMulticall3Result[*common.Address], i int) PodOwnerResult { return PodOwnerResult{ Query: candidateAddresses[i], Response: res, } - }), func(m PodOwnerResult) bool { + }), func(m PodOwnerResult, _ int) bool { return m.Response.Success }) ////// step 2: using the pod manager, check `ownerToPod` and validate which ones point back at the same address. - authoritativeOwnerToPodCalls := utils.Map(podOwnerPairs, func(res PodOwnerResult, i uint64) *multicall.MultiCallMetaData[common.Address] { + authoritativeOwnerToPodCalls := lo.Map(podOwnerPairs, func(res PodOwnerResult, i int) *multicall.MultiCallMetaData[common.Address] { mc, err := multicall.Describe[common.Address]( common.HexToAddress(podManagerAddress), EigenPodManagerAbi, @@ -124,9 +128,9 @@ func validEigenpodsOnly(candidateAddresses []common.Address, mc *multicall.Multi nullAddress := common.BigToAddress(big.NewInt(0)) ////// step 3: the valid eigenrestpods are the ones where authoritativeOwnerToPod[i] == candidateAddresses[i]. - return utils.Map(utils.FilterI(podOwnerPairs, func(res PodOwnerResult, i uint64) bool { + return lo.Map(lo.Filter(podOwnerPairs, func(res PodOwnerResult, i int) bool { return (res.Query.Cmp(*(*authoritativeOwnerToPod)[i]) == 0) && (*authoritativeOwnerToPod)[i].Cmp(nullAddress) != 0 - }), func(v PodOwnerResult, i uint64) common.Address { + }), func(v PodOwnerResult, i int) common.Address { return v.Query }), nil } @@ -138,24 +142,24 @@ func ComputeBalanceDeviationSync(ctx context.Context, eth *ethclient.Client, sta } allValidators, err := state.Validators() - PanicOnError("failed to read validators", err) + utils.PanicOnError("failed to read validators", err) - allValidatorsWithIndexes := utils.Map(allValidators, func(v *phase0.Validator, i uint64) ValidatorWithIndex { - return ValidatorWithIndex{ + allValidatorsWithIndexes := lo.Map(allValidators, func(v *phase0.Validator, i int) utils.ValidatorWithIndex { + return utils.ValidatorWithIndex{ Validator: v, - Index: i, + Index: uint64(i), } }) - podValidators := utils.FilterI[ValidatorWithIndex](allValidatorsWithIndexes, func(v ValidatorWithIndex, u uint64) bool { + podValidators := lo.Filter(allValidatorsWithIndexes, func(v utils.ValidatorWithIndex, u int) bool { addr := executionWithdrawalAddress(v.Validator.WithdrawalCredentials) return addr != nil && eigenpod.Cmp(common.HexToAddress(*addr)) == 0 }) validatorBalances, err := state.ValidatorBalances() - PanicOnError("failed to read beacon state validator balances", err) + utils.PanicOnError("failed to read beacon state validator balances", err) - validatorInfo, err := FetchMultipleOnchainValidatorInfoWithFailures(ctx, eth, eigenpod.Hex(), podValidators) + validatorInfo, err := utils.FetchMultipleOnchainValidatorInfoWithFailures(ctx, eth, eigenpod.Hex(), podValidators) if err != nil { return nil, err } @@ -165,8 +169,8 @@ func ComputeBalanceDeviationSync(ctx context.Context, eth *ethclient.Client, sta return nil, err } - sumCurrentBeaconBalancesGwei := utils.BigSum( - utils.Map(podValidators, func(v ValidatorWithIndex, i uint64) *big.Int { + sumCurrentBeaconBalancesGwei := cliutils.BigSum( + lo.Map(podValidators, func(v utils.ValidatorWithIndex, i int) *big.Int { if validatorInfo[i].Info != nil && validatorInfo[i].Info.Status == 1 /* ACTIVE */ { return new(big.Int).SetUint64(uint64(validatorBalances[v.Index])) } @@ -175,28 +179,28 @@ func ComputeBalanceDeviationSync(ctx context.Context, eth *ethclient.Client, sta ) eigenPodManagerAddr, err := pod.EigenPodManager(nil) - PanicOnError("failed to load eigenpod manager", err) + utils.PanicOnError("failed to load eigenpod manager", err) eigenPodManager, err := EigenPodManager.NewEigenPodManager(eigenPodManagerAddr, eth) - PanicOnError("failed to load eigenpod manager", err) + utils.PanicOnError("failed to load eigenpod manager", err) delegationManagerAddress, err := eigenPodManager.DelegationManager(nil) - PanicOnError("failed to read delegationManager", err) + utils.PanicOnError("failed to read delegationManager", err) delegationManager, err := DelegationManager.NewDelegationManager(delegationManagerAddress, eth) - PanicOnError("failed to reach delegationManager", err) + utils.PanicOnError("failed to reach delegationManager", err) podOwner, err := pod.PodOwner(nil) - PanicOnError("failed to load pod owner", err) + utils.PanicOnError("failed to load pod owner", err) activeShares, err := delegationManager.GetWithdrawableShares(nil, podOwner, []common.Address{ BeaconStrategy(), }) - PanicOnError("failed to load owner shares", err) + utils.PanicOnError("failed to load owner shares", err) var sharesPendingWithdrawal *big.Int = new(big.Int).SetUint64(0) withdrawalInfo, err := delegationManager.GetQueuedWithdrawals(nil, podOwner) - PanicOnError("failed to load queued withdrawals", err) + utils.PanicOnError("failed to load queued withdrawals", err) for i, withdrawal := range withdrawalInfo.Withdrawals { for j, strategy := range withdrawal.Strategies { @@ -213,8 +217,8 @@ func ComputeBalanceDeviationSync(ctx context.Context, eth *ethclient.Client, sta // fmt.Printf("delta := 1 - ((podBalanceGwei + sumCurrentBeaconBalancesGwei) / (regGwei + sumPreviousBeaconBalancesGwei)\n") // fmt.Printf("delta := 1 - ((%s + %s) / (%d + %s)\n", WeiToGwei(podBalanceWei).String(), sumCurrentBeaconBalancesGwei.String(), regGwei, sumPreviousBeaconBalancesGwei.String()) - currentState := new(big.Float).Add(WeiToGwei(podBalanceWei), new(big.Float).SetInt(sumCurrentBeaconBalancesGwei)) - prevState := WeiToGwei(totalSharesInEigenLayer) + currentState := new(big.Float).Add(utils.WeiToGwei(podBalanceWei), new(big.Float).SetInt(sumCurrentBeaconBalancesGwei)) + prevState := utils.WeiToGwei(totalSharesInEigenLayer) var delta *big.Float @@ -236,7 +240,7 @@ func ComputeBalanceDeviationSync(ctx context.Context, eth *ethclient.Client, sta return delta, nil } -func FindStaleEigenpods(ctx context.Context, eth *ethclient.Client, nodeUrl string, beacon BeaconClient, chainId *big.Int, verbose bool, tolerance float64) (map[string][]ValidatorWithIndex, error) { +func FindStaleEigenpods(ctx context.Context, eth *ethclient.Client, nodeUrl string, beacon utils.BeaconClient, chainId *big.Int, verbose bool, tolerance float64) (map[string][]utils.ValidatorWithIndex, error) { beaconState, err := beacon.GetBeaconState(ctx, "head") if err != nil { return nil, fmt.Errorf("error downloading beacon state: %s", err.Error()) @@ -253,26 +257,26 @@ func FindStaleEigenpods(ctx context.Context, eth *ethclient.Client, nodeUrl stri return nil, err } - allValidatorsWithIndices := utils.Map(_allValidators, func(validator *phase0.Validator, index uint64) ValidatorWithIndex { - return ValidatorWithIndex{ + allValidatorsWithIndices := lo.Map(_allValidators, func(validator *phase0.Validator, index int) utils.ValidatorWithIndex { + return utils.ValidatorWithIndex{ Validator: validator, - Index: index, + Index: uint64(index), } }) // TODO(pectra): this logic changes after the pectra upgrade. - allSlashedValidators := utils.Filter(allValidatorsWithIndices, func(v ValidatorWithIndex) bool { + allSlashedValidators := lo.Filter(allValidatorsWithIndices, func(v utils.ValidatorWithIndex, _ int) bool { if !v.Validator.Slashed { return false // we only care about slashed validators. } - if v.Validator.WithdrawalCredentials[0] != 1 { + if v.Validator.WithdrawalCredentials[0] != 1 && v.Validator.WithdrawalCredentials[0] != 2 { return false // not an execution withdrawal address } return true }) - allSlashedWithdrawalAddresses := utils.Unique( - utils.Map(allSlashedValidators, func(v ValidatorWithIndex, i uint64) common.Address { + allSlashedWithdrawalAddresses := cliutils.FilterDuplicates( + lo.Map(allSlashedValidators, func(v utils.ValidatorWithIndex, i int) common.Address { return common.HexToAddress(*executionWithdrawalAddress(v.Validator.WithdrawalCredentials)) }), ) @@ -285,7 +289,7 @@ func FindStaleEigenpods(ctx context.Context, eth *ethclient.Client, nodeUrl stri if len(slashedEigenpods) == 0 { log.Println("No eigenpods were slashed.") - return map[string][]ValidatorWithIndex{}, nil + return map[string][]utils.ValidatorWithIndex{}, nil } // 2. given the set of slashed eigenpods, determine which are unhealthy. @@ -294,9 +298,9 @@ func FindStaleEigenpods(ctx context.Context, eth *ethclient.Client, nodeUrl stri log.Printf("%d EigenPods were slashed\n", len(slashedEigenpods)) } - unhealthyEigenpods := utils.Filter(slashedEigenpods, func(eigenpod common.Address) bool { + unhealthyEigenpods := lo.Filter(slashedEigenpods, func(eigenpod common.Address, i int) bool { deviation, err := ComputeBalanceDeviationSync(ctx, eth, beaconState, eigenpod) - PanicOnError("failed to compute balance deviation for eigenpod", err) + utils.PanicOnError("failed to compute balance deviation for eigenpod", err) return deviation.Cmp(big.NewFloat(tolerance)) > 0 }) @@ -305,16 +309,16 @@ func FindStaleEigenpods(ctx context.Context, eth *ethclient.Client, nodeUrl stri if verbose { log.Printf("All slashed eigenpods are within %f%% of their expected balance.\n", tolerance) } - return map[string][]ValidatorWithIndex{}, nil + return map[string][]utils.ValidatorWithIndex{}, nil } if verbose { log.Printf("%d EigenPods were unhealthy\n", len(unhealthyEigenpods)) } - var entries map[string][]ValidatorWithIndex = make(map[string][]ValidatorWithIndex) + var entries map[string][]utils.ValidatorWithIndex = make(map[string][]utils.ValidatorWithIndex) for _, val := range unhealthyEigenpods { - entries[val.Hex()] = utils.Filter(allValidatorsWithIndices, func(v ValidatorWithIndex) bool { + entries[val.Hex()] = lo.Filter(allValidatorsWithIndices, func(v utils.ValidatorWithIndex, _ int) bool { execAddr := executionWithdrawalAddress(v.Validator.WithdrawalCredentials) return execAddr != nil && common.HexToAddress(*execAddr).Cmp(val) == 0 }) diff --git a/cli/core/status.go b/cli/core/status.go index b6fe1b86..d2963f16 100644 --- a/cli/core/status.go +++ b/cli/core/status.go @@ -8,36 +8,21 @@ import ( "github.com/Layr-Labs/eigenlayer-contracts/pkg/bindings/DelegationManager" "github.com/Layr-Labs/eigenlayer-contracts/pkg/bindings/EigenPod" "github.com/Layr-Labs/eigenlayer-contracts/pkg/bindings/EigenPodManager" + "github.com/Layr-Labs/eigenpod-proofs-generation/cli/core/utils" "github.com/attestantio/go-eth2-client/spec" "github.com/attestantio/go-eth2-client/spec/phase0" gethCommon "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/ethclient" ) -type Checkpoint struct { - ProofsRemaining uint64 - StartedAt uint64 -} - -type Validator struct { - Slashed bool - Index uint64 - Status int - PublicKey string - IsAwaitingActivationQueue bool - IsAwaitingWithdrawalCredentialProof bool - EffectiveBalance uint64 - CurrentBalance uint64 -} - func BeaconStrategy() gethCommon.Address { return gethCommon.HexToAddress("0xbeaC0eeEeeeeEEeEeEEEEeeEEeEeeeEeeEEBEaC0") } type EigenpodStatus struct { - Validators map[string]Validator + Validators map[string]utils.Validator - ActiveCheckpoint *Checkpoint + ActiveCheckpoint *utils.Checkpoint NumberValidatorsToCheckpoint int @@ -64,12 +49,12 @@ type EigenpodStatus struct { func getRegularBalancesGwei(state *spec.VersionedBeaconState) []phase0.Gwei { validatorBalances, err := state.ValidatorBalances() - PanicOnError("failed to load validator balances", err) + utils.PanicOnError("failed to load validator balances", err) return validatorBalances } -func sumValidatorBeaconBalancesGwei(allValidators []ValidatorWithOnchainInfo, allBalances []phase0.Gwei) *big.Int { +func sumValidatorBeaconBalancesGwei(allValidators []utils.ValidatorWithOnchainInfo, allBalances []phase0.Gwei) *big.Int { sumGwei := big.NewInt(0) for i := 0; i < len(allValidators); i++ { @@ -80,7 +65,7 @@ func sumValidatorBeaconBalancesGwei(allValidators []ValidatorWithOnchainInfo, al return sumGwei } -func sumRestakedBalancesGwei(activeValidators []ValidatorWithOnchainInfo) *big.Int { +func sumRestakedBalancesGwei(activeValidators []utils.ValidatorWithOnchainInfo) *big.Int { sumGwei := big.NewInt(0) for i := 0; i < len(activeValidators); i++ { @@ -91,81 +76,81 @@ func sumRestakedBalancesGwei(activeValidators []ValidatorWithOnchainInfo) *big.I return sumGwei } -func GetStatus(ctx context.Context, eigenpodAddress string, eth *ethclient.Client, beaconClient BeaconClient) EigenpodStatus { - validators := map[string]Validator{} - var activeCheckpoint *Checkpoint = nil +func GetStatus(ctx context.Context, eigenpodAddress string, eth *ethclient.Client, beaconClient utils.BeaconClient) EigenpodStatus { + validators := map[string]utils.Validator{} + var activeCheckpoint *utils.Checkpoint = nil eigenPod, err := EigenPod.NewEigenPod(gethCommon.HexToAddress(eigenpodAddress), eth) - PanicOnError("failed to reach eigenpod", err) + utils.PanicOnError("failed to reach eigenpod", err) checkpoint, err := eigenPod.CurrentCheckpoint(nil) - PanicOnError("failed to fetch checkpoint information", err) + utils.PanicOnError("failed to fetch checkpoint information", err) // Fetch the beacon state associated with the checkpoint (or "head" if there is no checkpoint) - checkpointTimestamp, state, err := GetCheckpointTimestampAndBeaconState(ctx, eigenpodAddress, eth, beaconClient) - PanicOnError("failed to fetch checkpoint and beacon state", err) + checkpointTimestamp, state, err := utils.GetCheckpointTimestampAndBeaconState(ctx, eigenpodAddress, eth, beaconClient) + utils.PanicOnError("failed to fetch checkpoint and beacon state", err) - allValidatorsForEigenpod, err := FindAllValidatorsForEigenpod(eigenpodAddress, state) - PanicOnError("failed to find validators", err) + allValidatorsForEigenpod, err := utils.FindAllValidatorsForEigenpod(eigenpodAddress, state) + utils.PanicOnError("failed to find validators", err) - allValidatorsWithInfoForEigenpod, err := FetchMultipleOnchainValidatorInfo(ctx, eth, eigenpodAddress, allValidatorsForEigenpod) - PanicOnError("failed to fetch validator info", err) + allValidatorsWithInfoForEigenpod, err := utils.FetchMultipleOnchainValidatorInfo(ctx, eth, eigenpodAddress, allValidatorsForEigenpod) + utils.PanicOnError("failed to fetch validator info", err) allBeaconBalancesGwei := getRegularBalancesGwei(state) - activeValidators, err := SelectActiveValidators(eth, eigenpodAddress, allValidatorsWithInfoForEigenpod) - PanicOnError("failed to find active validators", err) + activeValidators, err := utils.SelectActiveValidators(eth, eigenpodAddress, allValidatorsWithInfoForEigenpod) + utils.PanicOnError("failed to find active validators", err) - checkpointableValidators, err := SelectCheckpointableValidators(eth, eigenpodAddress, allValidatorsWithInfoForEigenpod, checkpointTimestamp) - PanicOnError("failed to find checkpointable validators", err) + checkpointableValidators, err := utils.SelectCheckpointableValidators(eth, eigenpodAddress, allValidatorsWithInfoForEigenpod, checkpointTimestamp) + utils.PanicOnError("failed to find checkpointable validators", err) - sumBeaconBalancesWei := IGweiToWei(sumValidatorBeaconBalancesGwei(activeValidators, allBeaconBalancesGwei)) - sumRestakedBalancesWei := IGweiToWei(sumRestakedBalancesGwei(activeValidators)) + sumBeaconBalancesWei := utils.IGweiToWei(sumValidatorBeaconBalancesGwei(activeValidators, allBeaconBalancesGwei)) + sumRestakedBalancesWei := utils.IGweiToWei(sumRestakedBalancesGwei(activeValidators)) - PanicOnError("failed to calculate sum of onchain validator balances", err) + utils.PanicOnError("failed to calculate sum of onchain validator balances", err) for _, validator := range allValidatorsWithInfoForEigenpod { - validators[fmt.Sprintf("%d", validator.Index)] = Validator{ + validators[fmt.Sprintf("%d", validator.Index)] = utils.Validator{ Index: validator.Index, Status: int(validator.Info.Status), Slashed: validator.Validator.Slashed, PublicKey: validator.Validator.PublicKey.String(), - IsAwaitingActivationQueue: validator.Validator.ActivationEpoch == FAR_FUTURE_EPOCH, - IsAwaitingWithdrawalCredentialProof: IsAwaitingWithdrawalCredentialProof(validator.Info, validator.Validator), + IsAwaitingActivationQueue: validator.Validator.ActivationEpoch == utils.FAR_FUTURE_EPOCH, + IsAwaitingWithdrawalCredentialProof: utils.IsAwaitingWithdrawalCredentialProof(validator.Info, validator.Validator), EffectiveBalance: uint64(validator.Validator.EffectiveBalance), CurrentBalance: uint64(allBeaconBalancesGwei[validator.Index]), } } eigenpodManagerContractAddress, err := eigenPod.EigenPodManager(nil) - PanicOnError("failed to get manager address", err) + utils.PanicOnError("failed to get manager address", err) eigenPodManager, err := EigenPodManager.NewEigenPodManager(eigenpodManagerContractAddress, eth) - PanicOnError("failed to get manager instance", err) + utils.PanicOnError("failed to get manager instance", err) eigenPodOwner, err := eigenPod.PodOwner(nil) - PanicOnError("failed to get eigenpod owner", err) + utils.PanicOnError("failed to get eigenpod owner", err) proofSubmitter, err := eigenPod.ProofSubmitter(nil) - PanicOnError("failed to get eigenpod proof submitter", err) + utils.PanicOnError("failed to get eigenpod proof submitter", err) delegationManagerAddress, err := eigenPodManager.DelegationManager(nil) - PanicOnError("failed to read delegationManager", err) + utils.PanicOnError("failed to read delegationManager", err) delegationManager, err := DelegationManager.NewDelegationManager(delegationManagerAddress, eth) - PanicOnError("failed to reach delegationManager", err) + utils.PanicOnError("failed to reach delegationManager", err) shares, err := delegationManager.GetWithdrawableShares(nil, eigenPodOwner, []gethCommon.Address{ BeaconStrategy(), }) - PanicOnError("failed to load owner shares", err) + utils.PanicOnError("failed to load owner shares", err) - currentOwnerSharesETH := IweiToEther(shares.WithdrawableShares[0]) + currentOwnerSharesETH := utils.IweiToEther(shares.WithdrawableShares[0]) currentOwnerSharesWei := shares.WithdrawableShares[0] withdrawableRestakedExecutionLayerGwei, err := eigenPod.WithdrawableRestakedExecutionLayerGwei(nil) - PanicOnError("failed to fetch withdrawableRestakedExecutionLayerGwei", err) + utils.PanicOnError("failed to fetch withdrawableRestakedExecutionLayerGwei", err) // Estimate the total shares we'll have if we complete an existing checkpoint // (or start a new one and complete that). @@ -177,28 +162,28 @@ func GetStatus(ctx context.Context, eigenpodAddress string, eth *ethclient.Clien if checkpointTimestamp != 0 { // Change in the pod's native ETH balance (already calculated for us when the checkpoint was started) fmt.Printf("pod had a checkpoint\n") - nativeETHDeltaWei = IGweiToWei(new(big.Int).SetUint64(checkpoint.PodBalanceGwei)) + nativeETHDeltaWei = utils.IGweiToWei(new(big.Int).SetUint64(checkpoint.PodBalanceGwei)) // Remove already-computed delta from an in-progress checkpoint sumRestakedBalancesWei = new(big.Int).Sub( sumRestakedBalancesWei, - IGweiToWei(big.NewInt(checkpoint.BalanceDeltasGwei)), + utils.IGweiToWei(big.NewInt(checkpoint.BalanceDeltasGwei)), ) - activeCheckpoint = &Checkpoint{ + activeCheckpoint = &utils.Checkpoint{ ProofsRemaining: checkpoint.ProofsRemaining.Uint64(), StartedAt: checkpointTimestamp, } } else { fmt.Printf("pod did not have a checkpoint\n") latestPodBalanceWei, err := eth.BalanceAt(ctx, gethCommon.HexToAddress(eigenpodAddress), nil) - PanicOnError("failed to fetch pod balance", err) + utils.PanicOnError("failed to fetch pod balance", err) // We don't have a checkpoint currently, so we need to calculate what // checkpoint.PodBalanceGwei would be if we started one now: nativeETHDeltaWei = new(big.Int).Sub( latestPodBalanceWei, - IGweiToWei(new(big.Int).SetUint64(withdrawableRestakedExecutionLayerGwei)), + utils.IGweiToWei(new(big.Int).SetUint64(withdrawableRestakedExecutionLayerGwei)), ) // Determine whether the checkpoint needs to be started with `--force` @@ -228,13 +213,13 @@ func GetStatus(ctx context.Context, eigenpodAddress string, eth *ethclient.Clien totalShareDeltaWei, ) - pendingEth := GweiToEther(WeiToGwei(pendingSharesWei)) + pendingEth := utils.GweiToEther(utils.WeiToGwei(pendingSharesWei)) return EigenpodStatus{ Validators: validators, ActiveCheckpoint: activeCheckpoint, CurrentTotalSharesETH: currentOwnerSharesETH, - TotalSharesAfterCheckpointGwei: WeiToGwei(pendingSharesWei), + TotalSharesAfterCheckpointGwei: utils.WeiToGwei(pendingSharesWei), TotalSharesAfterCheckpointETH: pendingEth, NumberValidatorsToCheckpoint: len(checkpointableValidators), PodOwner: eigenPodOwner, diff --git a/cli/core/beaconClient.go b/cli/core/utils/beaconClient.go similarity index 99% rename from cli/core/beaconClient.go rename to cli/core/utils/beaconClient.go index 195c3a1b..9b3cbeeb 100644 --- a/cli/core/beaconClient.go +++ b/cli/core/utils/beaconClient.go @@ -1,4 +1,4 @@ -package core +package utils import ( "context" diff --git a/cli/core/messages.go b/cli/core/utils/messages.go similarity index 98% rename from cli/core/messages.go rename to cli/core/utils/messages.go index 0ca8e0d3..50d0deac 100644 --- a/cli/core/messages.go +++ b/cli/core/utils/messages.go @@ -1,4 +1,4 @@ -package core +package utils import ( "fmt" diff --git a/cli/core/tracing.go b/cli/core/utils/tracing.go similarity index 97% rename from cli/core/tracing.go rename to cli/core/utils/tracing.go index 7807b3c8..9dab6f71 100644 --- a/cli/core/tracing.go +++ b/cli/core/utils/tracing.go @@ -1,4 +1,4 @@ -package core +package utils import ( "context" diff --git a/cli/core/utils.go b/cli/core/utils/utils.go similarity index 93% rename from cli/core/utils.go rename to cli/core/utils/utils.go index 34a55930..99c00b9d 100644 --- a/cli/core/utils.go +++ b/cli/core/utils/utils.go @@ -1,4 +1,4 @@ -package core +package utils import ( "context" @@ -15,9 +15,10 @@ import ( "strconv" "strings" + lo "github.com/samber/lo" + "github.com/Layr-Labs/eigenlayer-contracts/pkg/bindings/EigenPod" eigenpodproofs "github.com/Layr-Labs/eigenpod-proofs-generation" - "github.com/Layr-Labs/eigenpod-proofs-generation/cli/utils" "github.com/attestantio/go-eth2-client/spec" "github.com/attestantio/go-eth2-client/spec/phase0" "github.com/ethereum/go-ethereum/accounts/abi" @@ -37,6 +38,22 @@ const ( ValidatorStatusWithdrawn = 2 ) +type Checkpoint struct { + ProofsRemaining uint64 + StartedAt uint64 +} + +type Validator struct { + Slashed bool + Index uint64 + Status int + PublicKey string + IsAwaitingActivationQueue bool + IsAwaitingWithdrawalCredentialProof bool + EffectiveBalance uint64 + CurrentBalance uint64 +} + func Panic(message string) { color.Red(fmt.Sprintf("error: %s\n\n", message)) @@ -77,7 +94,7 @@ func PanicOnError(message string, err error) { } } -func chunk[T any](arr []T, chunkSize uint64) [][]T { +func Chunk[T any](arr []T, chunkSize uint64) [][]T { // Validate the chunkSize to ensure it's positive if chunkSize <= 0 { panic("chunkSize must be greater than 0") @@ -274,7 +291,7 @@ func FindAllValidatorsForEigenpod(eigenpodAddress string, beaconState *spec.Vers maxValidators := uint64(len(allValidators)) for i = 0; i < maxValidators; i++ { validator := allValidators[i] - if validator == nil || validator.WithdrawalCredentials[0] != 1 { // withdrawalCredentials _need_ their first byte set to 1 to withdraw to execution layer. + if validator == nil || (validator.WithdrawalCredentials[0] != 1 && validator.WithdrawalCredentials[0] != 2) { // withdrawalCredentials _need_ their first byte set to 1 or 2 to withdraw to an eigenpod on the execution layer. continue } // we check that the last 20 bytes of expectedCredentials matches validatorCredentials. @@ -304,7 +321,7 @@ func FetchMultipleOnchainValidatorInfoMulticalls(eigenpodAddress string, allVali Error error } - requests := utils.Map(allValidators, func(validator *phase0.Validator, index uint64) MulticallAndError { + requests := lo.Map(allValidators, func(validator *phase0.Validator, index int) MulticallAndError { pubKeyHash := sha256.Sum256( append( validator.PublicKey[:], @@ -335,14 +352,14 @@ func FetchMultipleOnchainValidatorInfoMulticalls(eigenpodAddress string, allVali return nil, fmt.Errorf("failed to form request for validator info: %s", errors.Join(errs...)) } - allMulticalls := utils.Map(requests, func(mc MulticallAndError, _ uint64) *multicall.MultiCallMetaData[EigenPod.IEigenPodTypesValidatorInfo] { + allMulticalls := lo.Map(requests, func(mc MulticallAndError, _ int) *multicall.MultiCallMetaData[EigenPod.IEigenPodTypesValidatorInfo] { return mc.Multicall }) return allMulticalls, nil } func FetchMultipleOnchainValidatorInfo(ctx context.Context, client *ethclient.Client, eigenpodAddress string, allValidators []ValidatorWithIndex) ([]ValidatorWithOnchainInfo, error) { - allMulticalls, err := FetchMultipleOnchainValidatorInfoMulticalls(eigenpodAddress, utils.Map(allValidators, func(validator ValidatorWithIndex, i uint64) *phase0.Validator { return validator.Validator })) + allMulticalls, err := FetchMultipleOnchainValidatorInfoMulticalls(eigenpodAddress, lo.Map(allValidators, func(validator ValidatorWithIndex, i int) *phase0.Validator { return validator.Validator })) if err != nil { return nil, fmt.Errorf("failed to form multicalls: %s", err.Error()) } @@ -363,7 +380,7 @@ func FetchMultipleOnchainValidatorInfo(ctx context.Context, client *ethclient.Cl return nil, errors.New("no results returned fetching validator info") } - return utils.Map(*results, func(info *EigenPod.IEigenPodTypesValidatorInfo, i uint64) ValidatorWithOnchainInfo { + return lo.Map(*results, func(info *EigenPod.IEigenPodTypesValidatorInfo, i int) ValidatorWithOnchainInfo { return ValidatorWithOnchainInfo{ Info: *info, Validator: allValidators[i].Validator, @@ -373,7 +390,7 @@ func FetchMultipleOnchainValidatorInfo(ctx context.Context, client *ethclient.Cl } func FetchMultipleOnchainValidatorInfoWithFailures(ctx context.Context, client *ethclient.Client, eigenpodAddress string, allValidators []ValidatorWithIndex) ([]ValidatorWithMaybeOnchainInfo, error) { - allMulticalls, err := FetchMultipleOnchainValidatorInfoMulticalls(eigenpodAddress, utils.Map(allValidators, func(validator ValidatorWithIndex, i uint64) *phase0.Validator { return validator.Validator })) + allMulticalls, err := FetchMultipleOnchainValidatorInfoMulticalls(eigenpodAddress, lo.Map(allValidators, func(validator ValidatorWithIndex, i int) *phase0.Validator { return validator.Validator })) if err != nil { return nil, fmt.Errorf("failed to form multicalls: %s", err.Error()) } @@ -394,7 +411,7 @@ func FetchMultipleOnchainValidatorInfoWithFailures(ctx context.Context, client * return nil, errors.New("no results returned fetching validator info") } - return utils.Map(*results, func(info multicall.TypedMulticall3Result[*EigenPod.IEigenPodTypesValidatorInfo], i uint64) ValidatorWithMaybeOnchainInfo { + return lo.Map(*results, func(info multicall.TypedMulticall3Result[*EigenPod.IEigenPodTypesValidatorInfo], i int) ValidatorWithMaybeOnchainInfo { return ValidatorWithMaybeOnchainInfo{ Info: info.Value, Validator: allValidators[i].Validator, diff --git a/cli/core/validator.go b/cli/core/validator.go index 0de9abd8..a7a5390f 100644 --- a/cli/core/validator.go +++ b/cli/core/validator.go @@ -8,9 +8,11 @@ import ( "os" "strconv" + lo "github.com/samber/lo" + "github.com/Layr-Labs/eigenlayer-contracts/pkg/bindings/EigenPod" eigenpodproofs "github.com/Layr-Labs/eigenpod-proofs-generation" - "github.com/Layr-Labs/eigenpod-proofs-generation/cli/utils" + "github.com/Layr-Labs/eigenpod-proofs-generation/cli/core/utils" v1 "github.com/attestantio/go-eth2-client/api/v1" "github.com/attestantio/go-eth2-client/spec" "github.com/ethereum/go-ethereum/common" @@ -40,23 +42,23 @@ func LoadValidatorProofFromFile(path string) (*SerializableCredentialProof, erro } func SubmitValidatorProof(ctx context.Context, owner, eigenpodAddress string, chainId *big.Int, eth *ethclient.Client, batchSize uint64, proofs *eigenpodproofs.VerifyValidatorFieldsCallParams, oracleBeaconTimesetamp uint64, noPrompt bool, noSend bool, verbose bool) ([]*types.Transaction, [][]*big.Int, error) { - ownerAccount, err := PrepareAccount(&owner, chainId, noSend) + ownerAccount, err := utils.PrepareAccount(&owner, chainId, noSend) if err != nil { return nil, [][]*big.Int{}, err } - PanicOnError("failed to parse private key", err) + utils.PanicOnError("failed to parse private key", err) eigenPod, err := EigenPod.NewEigenPod(common.HexToAddress(eigenpodAddress), eth) if err != nil { return nil, [][]*big.Int{}, err } - indices := Uint64ArrayToBigIntArray(proofs.ValidatorIndices) - validatorIndicesChunks := chunk(indices, batchSize) - validatorProofsChunks := chunk(proofs.ValidatorFieldsProofs, batchSize) - validatorFieldsChunks := chunk(proofs.ValidatorFields, batchSize) + indices := utils.Uint64ArrayToBigIntArray(proofs.ValidatorIndices) + validatorIndicesChunks := utils.Chunk(indices, batchSize) + validatorProofsChunks := utils.Chunk(proofs.ValidatorFieldsProofs, batchSize) + validatorFieldsChunks := utils.Chunk(proofs.ValidatorFields, batchSize) if !noPrompt && !noSend { - PanicIfNoConsent(SubmitCredentialsProofConsent(len(validatorFieldsChunks))) + utils.PanicIfNoConsent(utils.SubmitCredentialsProofConsent(len(validatorFieldsChunks))) } transactions := []*types.Transaction{} @@ -82,7 +84,7 @@ func SubmitValidatorProof(ctx context.Context, owner, eigenpodAddress string, ch pr := curValidatorProofs[i].ToByteSlice() validatorFieldsProofs = append(validatorFieldsProofs, pr) } - var curValidatorFields [][][32]byte = CastValidatorFields(validatorFieldsChunks[i]) + var curValidatorFields [][][32]byte = utils.CastValidatorFields(validatorFieldsChunks[i]) if verbose { fmt.Printf("Submitted chunk %d/%d -- waiting for transaction...: ", i+1, numChunks) @@ -98,7 +100,7 @@ func SubmitValidatorProof(ctx context.Context, owner, eigenpodAddress string, ch return transactions, validatorIndicesChunks, err } -func SubmitValidatorProofChunk(ctx context.Context, ownerAccount *Owner, eigenPod *EigenPod.EigenPod, chainId *big.Int, eth *ethclient.Client, indices []*big.Int, validatorFields [][][32]byte, stateRootProofs *eigenpodproofs.StateRootProof, validatorFieldsProofs [][]byte, oracleBeaconTimesetamp uint64, verbose bool) (*types.Transaction, error) { +func SubmitValidatorProofChunk(ctx context.Context, ownerAccount *utils.Owner, eigenPod *EigenPod.EigenPod, chainId *big.Int, eth *ethclient.Client, indices []*big.Int, validatorFields [][][32]byte, stateRootProofs *eigenpodproofs.StateRootProof, validatorFieldsProofs [][]byte, oracleBeaconTimesetamp uint64, verbose bool) (*types.Transaction, error) { if verbose { color.Green("submitting...") } @@ -121,7 +123,7 @@ func SubmitValidatorProofChunk(ctx context.Context, ownerAccount *Owner, eigenPo * Generates a .ProveValidatorContainers() proof for all eligible validators on the pod. If `validatorIndex` is set, it will only generate a proof * against that validator, regardless of the validator's state. */ -func GenerateValidatorProof(ctx context.Context, eigenpodAddress string, eth *ethclient.Client, chainId *big.Int, beaconClient BeaconClient, validatorIndex *big.Int, verbose bool) (*eigenpodproofs.VerifyValidatorFieldsCallParams, uint64, error) { +func GenerateValidatorProof(ctx context.Context, eigenpodAddress string, eth *ethclient.Client, chainId *big.Int, beaconClient utils.BeaconClient, validatorIndex *big.Int, verbose bool) (*eigenpodproofs.VerifyValidatorFieldsCallParams, uint64, error) { latestBlock, err := eth.BlockByNumber(ctx, nil) if err != nil { return nil, 0, fmt.Errorf("failed to load latest block: %w", err) @@ -157,18 +159,18 @@ func GenerateValidatorProof(ctx context.Context, eigenpodAddress string, eth *et } func GenerateValidatorProofAtState(ctx context.Context, proofs *eigenpodproofs.EigenPodProofs, eigenpodAddress string, beaconState *spec.VersionedBeaconState, eth *ethclient.Client, chainId *big.Int, header *v1.BeaconBlockHeader, blockTimestamp uint64, forSpecificValidatorIndex *big.Int, verbose bool) (*eigenpodproofs.VerifyValidatorFieldsCallParams, error) { - allValidators, err := FindAllValidatorsForEigenpod(eigenpodAddress, beaconState) + allValidators, err := utils.FindAllValidatorsForEigenpod(eigenpodAddress, beaconState) if err != nil { return nil, fmt.Errorf("failed to find validators: %w", err) } - var awaitingCredentialValidators []ValidatorWithIndex + var awaitingCredentialValidators []utils.ValidatorWithIndex if forSpecificValidatorIndex != nil { // prove a specific validator for _, v := range allValidators { if v.Index == forSpecificValidatorIndex.Uint64() { - awaitingCredentialValidators = []ValidatorWithIndex{v} + awaitingCredentialValidators = []utils.ValidatorWithIndex{v} break } } @@ -177,18 +179,18 @@ func GenerateValidatorProofAtState(ctx context.Context, proofs *eigenpodproofs.E } } else { // default behavior -- load any validators that are inactive / need a credential proof - allValidatorsWithInfo, err := FetchMultipleOnchainValidatorInfo(ctx, eth, eigenpodAddress, allValidators) + allValidatorsWithInfo, err := utils.FetchMultipleOnchainValidatorInfo(ctx, eth, eigenpodAddress, allValidators) if err != nil { return nil, fmt.Errorf("failed to load validator information: %s", err.Error()) } - _awaitingCredentialValidators, err := SelectAwaitingCredentialValidators(eth, eigenpodAddress, allValidatorsWithInfo) + _awaitingCredentialValidators, err := utils.SelectAwaitingCredentialValidators(eth, eigenpodAddress, allValidatorsWithInfo) if err != nil { return nil, fmt.Errorf("failed to select awaiting credential validators: %s", err.Error()) } - awaitingCredentialValidators = utils.Map(_awaitingCredentialValidators, func(validator ValidatorWithOnchainInfo, index uint64) ValidatorWithIndex { - return ValidatorWithIndex{Index: validator.Index, Validator: validator.Validator} + awaitingCredentialValidators = lo.Map(_awaitingCredentialValidators, func(validator utils.ValidatorWithOnchainInfo, index int) utils.ValidatorWithIndex { + return utils.ValidatorWithIndex{Index: validator.Index, Validator: validator.Validator} }) } diff --git a/cli/utils/utils.go b/cli/utils/utils.go index ecbc4539..eeea3b99 100644 --- a/cli/utils/utils.go +++ b/cli/utils/utils.go @@ -1,86 +1,30 @@ package utils -import "math/big" +import ( + "math/big" + + lo "github.com/samber/lo" +) // 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 -} - -type Addable interface { - ~int | ~float64 | ~int64 | ~float32 | ~uint64 -} - -// A generic Sum function that sums up all elements in a list. -func Sum[T Addable](list []T) T { - var sum T - for _, item := range list { - sum += item - } - return sum -} - func BigSum(list []*big.Int) *big.Int { - return Reduce(list, func(sum *big.Int, cur *big.Int) *big.Int { + return lo.Reduce(list, func(sum *big.Int, cur *big.Int, index int) *big.Int { return sum.Add(sum, cur) }, big.NewInt(0)) } -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 FilterI[A any](coll []A, criteria func(i A, index uint64) bool) []A { - out := []A{} - i := uint64(0) - for _, item := range coll { - if criteria(item, i) { - out = append(out, item) - } - i++ - } - 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 Unique[A comparable](coll []A) []A { +func FilterDuplicates[A comparable](coll []A) []A { values := map[A]bool{} - return Filter(coll, func(item A) bool { + return lo.Filter(coll, func(item A, index int) bool { isSet := values[item] values[item] = true return !isSet }) } -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:] } diff --git a/go.mod b/go.mod index 066f9c20..ab8323a1 100644 --- a/go.mod +++ b/go.mod @@ -5,11 +5,11 @@ go 1.22.0 toolchain go1.22.4 require ( - github.com/Layr-Labs/eigenlayer-contracts v0.4.3-mainnet-rewards-foundation-incentives.0.20241218180135-1856b33e74ac - github.com/attestantio/go-eth2-client v0.23.1-0.20250129191805-4ee14baa752e + github.com/Layr-Labs/eigenlayer-contracts v1.1.0-testnet.0.20250219143349-7a05fa397d3d + github.com/attestantio/go-eth2-client v0.24.0 github.com/ethereum/go-ethereum v1.14.9 - github.com/fatih/color v1.16.0 - github.com/ferranbt/fastssz v0.1.3 + github.com/fatih/color v1.18.0 + github.com/ferranbt/fastssz v0.1.4 github.com/hashicorp/golang-lru/v2 v2.0.7 github.com/jbrower95/multicall-go v0.0.0-20241012224745-7e9c19976cb5 github.com/joho/godotenv v1.5.1 @@ -35,19 +35,20 @@ require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/deckarep/golang-set/v2 v2.6.0 // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 // indirect + github.com/emicklei/dot v1.6.4 // indirect github.com/ethereum/c-kzg-4844 v1.0.3 // indirect github.com/ethereum/go-verkle v0.1.1-0.20240829091221-dffa7562dbe9 // indirect github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/go-logr/logr v1.2.4 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-ole/go-ole v1.3.0 // indirect - github.com/goccy/go-yaml v1.9.2 // indirect + github.com/goccy/go-yaml v1.15.23 // indirect github.com/google/uuid v1.6.0 // indirect github.com/gorilla/websocket v1.5.3 // indirect - github.com/holiman/uint256 v1.3.1 // indirect + github.com/holiman/uint256 v1.3.2 // indirect github.com/huandu/go-clone v1.6.0 // indirect - github.com/klauspost/cpuid/v2 v2.2.7 // indirect - github.com/mattn/go-colorable v0.1.13 // indirect + github.com/klauspost/cpuid/v2 v2.2.9 // indirect + github.com/mattn/go-colorable v0.1.14 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/mmcloughlin/addchain v0.4.0 // indirect @@ -57,7 +58,7 @@ require ( github.com/prometheus/client_model v0.5.0 // indirect github.com/prometheus/common v0.48.0 // indirect github.com/prometheus/procfs v0.12.0 // indirect - github.com/prysmaticlabs/go-bitfield v0.0.0-20240328144219-a1caa50c3a1e // indirect + github.com/prysmaticlabs/go-bitfield v0.0.0-20240618144021-706c95b2dd15 // indirect github.com/r3labs/sse/v2 v2.10.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/shirou/gopsutil v3.21.11+incompatible // indirect @@ -69,13 +70,13 @@ require ( go.opentelemetry.io/otel v1.16.0 // indirect go.opentelemetry.io/otel/metric v1.16.0 // indirect go.opentelemetry.io/otel/trace v1.16.0 // indirect - golang.org/x/crypto v0.27.0 // indirect + golang.org/x/crypto v0.33.0 // indirect golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 // indirect golang.org/x/net v0.29.0 // indirect - golang.org/x/sync v0.8.0 // indirect - golang.org/x/sys v0.25.0 // indirect - golang.org/x/text v0.18.0 // indirect - golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect + golang.org/x/sync v0.11.0 // indirect + golang.org/x/sys v0.30.0 // indirect + golang.org/x/text v0.22.0 // indirect + golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da // indirect google.golang.org/protobuf v1.34.2 // indirect gopkg.in/Knetic/govaluate.v3 v3.0.0 // indirect gopkg.in/cenkalti/backoff.v1 v1.1.0 // indirect diff --git a/go.sum b/go.sum index a5c50832..dcdeb5cb 100644 --- a/go.sum +++ b/go.sum @@ -2,12 +2,16 @@ github.com/DataDog/zstd v1.4.5 h1:EndNeuB0l9syBZhut0wns3gV1hL8zX8LIu6ZiVHWLIQ= github.com/DataDog/zstd v1.4.5/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= github.com/Layr-Labs/eigenlayer-contracts v0.4.3-mainnet-rewards-foundation-incentives.0.20241218180135-1856b33e74ac h1:YKNXU2HFHxdR7XyrUxeXyVWf2u5tMCwKA3/2YKT54Oo= github.com/Layr-Labs/eigenlayer-contracts v0.4.3-mainnet-rewards-foundation-incentives.0.20241218180135-1856b33e74ac/go.mod h1:Ie8YE3EQkTHqG6/tnUS0He7/UPMkXPo/3OFXwSy0iRo= +github.com/Layr-Labs/eigenlayer-contracts v1.1.0-testnet.0.20250219143349-7a05fa397d3d h1:sbhosXD2jiCrRl/EVI1FJ5mnOT8xBerNPY8S+C/oyCA= +github.com/Layr-Labs/eigenlayer-contracts v1.1.0-testnet.0.20250219143349-7a05fa397d3d/go.mod h1:Ie8YE3EQkTHqG6/tnUS0He7/UPMkXPo/3OFXwSy0iRo= github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= github.com/VictoriaMetrics/fastcache v1.12.2 h1:N0y9ASrJ0F6h0QaC3o6uJb3NIZ9VKLjCM7NQbSmF7WI= github.com/VictoriaMetrics/fastcache v1.12.2/go.mod h1:AmC+Nzz1+3G2eCPapF6UcsnkThDcMsQicp4xDukwJYI= github.com/attestantio/go-eth2-client v0.23.1-0.20250129191805-4ee14baa752e h1:3G/ZObqxMYsePLSPkiogDNjjJem4Ab02yFrQgoDFYsw= github.com/attestantio/go-eth2-client v0.23.1-0.20250129191805-4ee14baa752e/go.mod h1:vy5jU/uDZ2+RcVzq5BfnG+bQ3/6uu9DGwCrGsPtjJ1A= +github.com/attestantio/go-eth2-client v0.24.0 h1:lGVbcnhlBwRglt1Zs56JOCgXVyLWKFZOmZN8jKhE7Ws= +github.com/attestantio/go-eth2-client v0.24.0/go.mod h1:/KTLN3WuH1xrJL7ZZrpBoWM1xCCihnFbzequD5L+83o= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bits-and-blooms/bitset v1.14.3 h1:Gd2c8lSNf9pKXom5JtD7AaKO8o7fGQ2LtFj1436qilA= @@ -52,6 +56,8 @@ github.com/decred/dcrd/crypto/blake256 v1.0.1 h1:7PltbUIQB7u/FfZ39+DGa/ShuMyJ5il github.com/decred/dcrd/crypto/blake256 v1.0.1/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 h1:rpfIENRNNilwHwZeG5+P150SMrnNEcHYvcCuK6dPZSg= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0= +github.com/emicklei/dot v1.6.4 h1:cG9ycT67d9Yw22G+mAb4XiuUz6E6H1S0zePp/5Cwe/c= +github.com/emicklei/dot v1.6.4/go.mod h1:DeV7GvQtIw4h2u73RKBkkFdvVAz0D9fzeJrgPW6gy/s= github.com/ethereum/c-kzg-4844 v1.0.3 h1:IEnbOHwjixW2cTvKRUlAAUOeleV7nNM/umJR+qy4WDs= github.com/ethereum/c-kzg-4844 v1.0.3/go.mod h1:VewdlzQmpT5QSrVhbBuGoCdFJkpaJlO1aQputP83wc0= github.com/ethereum/go-ethereum v1.14.9 h1:J7iwXDrtUyE9FUjUYbd4c9tyzwMh6dTJsKzo9i6SrwA= @@ -61,8 +67,12 @@ github.com/ethereum/go-verkle v0.1.1-0.20240829091221-dffa7562dbe9/go.mod h1:M3b github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM= github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE= +github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= +github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU= github.com/ferranbt/fastssz v0.1.3 h1:ZI+z3JH05h4kgmFXdHuR1aWYsgrg7o+Fw7/NCzM16Mo= github.com/ferranbt/fastssz v0.1.3/go.mod h1:0Y9TEd/9XuFlh7mskMPfXiI2Dkw4Ddg9EyXt1W7MRvE= +github.com/ferranbt/fastssz v0.1.4 h1:OCDB+dYDEQDvAgtAGnTSidK1Pe2tW3nFV40XyMkTeDY= +github.com/ferranbt/fastssz v0.1.4/go.mod h1:Ea3+oeoRGGLGm5shYAeDgu6PGUlcvQhE2fILyD9+tGg= github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff h1:tY80oXqGNY4FhTFhk+o9oFHGINQ/+vhlm8HFzi6znCI= @@ -86,6 +96,8 @@ github.com/go-playground/validator/v10 v10.4.1 h1:pH2c5ADXtd66mxoE0Zm9SUhxE20r7a github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4= github.com/goccy/go-yaml v1.9.2 h1:2Njwzw+0+pjU2gb805ZC1B/uBuAs2VcZ3K+ZgHwDs7w= github.com/goccy/go-yaml v1.9.2/go.mod h1:U/jl18uSupI5rdI2jmuCswEA2htH9eXfferR3KfscvA= +github.com/goccy/go-yaml v1.15.23 h1:WS0GAX1uNPDLUvLkNU2vXq6oTnsmfVFocjQ/4qA48qo= +github.com/goccy/go-yaml v1.15.23/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw= github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= @@ -114,6 +126,8 @@ github.com/holiman/bloomfilter/v2 v2.0.3 h1:73e0e/V0tCydx14a0SCYS/EWCxgwLZ18CZcZ github.com/holiman/bloomfilter/v2 v2.0.3/go.mod h1:zpoh+gs7qcpqrHr3dB55AMiJwo0iURXE7ZOP9L9hSkA= github.com/holiman/uint256 v1.3.1 h1:JfTzmih28bittyHM8z360dCjIA9dbPIBlcTI6lmctQs= github.com/holiman/uint256 v1.3.1/go.mod h1:EOMSn4q6Nyt9P6efbI3bueV4e1b3dGlUCXeiRV4ng7E= +github.com/holiman/uint256 v1.3.2 h1:a9EgMPSC1AAaj1SZL5zIQD3WbwTuHrMGOerLjGmM/TA= +github.com/holiman/uint256 v1.3.2/go.mod h1:EOMSn4q6Nyt9P6efbI3bueV4e1b3dGlUCXeiRV4ng7E= github.com/huandu/go-assert v1.1.5 h1:fjemmA7sSfYHJD7CUqs9qTwwfdNAx7/j2/ZlHXzNB3c= github.com/huandu/go-assert v1.1.5/go.mod h1:yOLvuqZwmcHIC5rIzrBhT7D3Q9c3GFnd0JrPVhn/06U= github.com/huandu/go-clone v1.6.0 h1:HMo5uvg4wgfiy5FoGOqlFLQED/VGRm2D9Pi8g1FXPGc= @@ -132,6 +146,8 @@ github.com/klauspost/compress v1.16.0 h1:iULayQNOReoYUe+1qtKOqw9CwJv3aNQu8ivo7lw github.com/klauspost/compress v1.16.0/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM= github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= +github.com/klauspost/cpuid/v2 v2.2.9 h1:66ze0taIn2H33fBvCkXuv9BmCwDfafmiIVpKV9kKGuY= +github.com/klauspost/cpuid/v2 v2.2.9/go.mod h1:rqkxqrZ1EhYM9G+hXH7YdowN5R5RGN6NK4QwQ3WMXF8= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= @@ -145,6 +161,8 @@ github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgx github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE= +github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= @@ -179,6 +197,8 @@ github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= github.com/prysmaticlabs/go-bitfield v0.0.0-20240328144219-a1caa50c3a1e h1:ATgOe+abbzfx9kCPeXIW4fiWyDdxlwHw07j8UGhdTd4= github.com/prysmaticlabs/go-bitfield v0.0.0-20240328144219-a1caa50c3a1e/go.mod h1:wmuf/mdK4VMD+jA9ThwcUKjg3a2XWM9cVfFYjDyY4j4= +github.com/prysmaticlabs/go-bitfield v0.0.0-20240618144021-706c95b2dd15 h1:lC8kiphgdOBTcbTvo8MwkvpKjO0SlAgjv4xIK5FGJ94= +github.com/prysmaticlabs/go-bitfield v0.0.0-20240618144021-706c95b2dd15/go.mod h1:8svFBIKKu31YriBG/pNizo9N0Jr9i5PQ+dFkxWg3x5k= github.com/r3labs/sse/v2 v2.10.0 h1:hFEkLLFY4LDifoHdiCN/LlGBAdVJYsANaLqNYa1l/v0= github.com/r3labs/sse/v2 v2.10.0/go.mod h1:Igau6Whc+F17QUgML1fYe1VPZzTV6EMCnYktEmkNJ7I= github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= @@ -231,6 +251,8 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A= golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70= +golang.org/x/crypto v0.33.0 h1:IOBPskki6Lysi0lo9qQvbxiQ+FvsCC/YWOecCHAixus= +golang.org/x/crypto v0.33.0/go.mod h1:bVdXmD7IV/4GdElGPozy6U7lWdRXA4qyRVGJV57uQ5M= golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 h1:e66Fs6Z+fZTbFBAxKfP3PALWBtpfqks2bwGcexMxgtk= golang.org/x/exp v0.0.0-20240909161429-701f63a606c0/go.mod h1:2TbTHSBQa924w8M6Xs1QcRcFwyucIwBGpK1p2f1YFFY= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= @@ -239,6 +261,8 @@ golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo= golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0= golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w= +golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -251,16 +275,22 @@ golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34= golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc= +golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224= golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= +golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM= +golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY= golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 h1:+cNy6SZtPcJQH3LJVLOSmiC7MMxXNOb3PU/VUEz+EhU= golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90= +golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da h1:noIWHXmPHxILtqtCOPIhSt0ABwskkZKjD3bXGnZGpNY= +golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90= google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= gopkg.in/Knetic/govaluate.v3 v3.0.0 h1:18mUyIt4ZlRlFZAAfVetz4/rzlJs9yhN+U02F4u1AOc=