diff --git a/CHANGELOG.md b/CHANGELOG.md index 304b02a3..4b92cf31 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,16 +7,25 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Fixed +- Remove arguments for Lighthouse `--eth1` flag. + ### Added - Add support for MEV-boost on Holesky. +- New flag `--lido` to `generate` command for Lido CSM setup. +- New Sedge setup flow with `sedge cli` command for Lido CSM setup. +- Support for `sedge keys` to generate 0x01 withdrawal credentials. +- Support for installing Docker in Ubuntu 24.04 LTS. ### Changed - Update client images to Dencun-ready versions. -- +- Renamed `--eth1-withdrawal-address` flag from `sedge keys` to `--eth-withdrawal-address`. +- Update client images to latest versions. ### Removed + - Removed support for Goerli. ## [v1.3.1] - 2024-02-14 diff --git a/cli/actions/testdata/getContainers_tests/case_consensusNF/docker-compose.yml b/cli/actions/testdata/getContainers_tests/case_consensusNF/docker-compose.yml index 6336b13d..51df7398 100644 --- a/cli/actions/testdata/getContainers_tests/case_consensusNF/docker-compose.yml +++ b/cli/actions/testdata/getContainers_tests/case_consensusNF/docker-compose.yml @@ -85,7 +85,7 @@ services: - --target-peers=${CC_PEER_COUNT} - --execution-endpoints=${EC_AUTH_URL} - --execution-jwt=/tmp/jwt/jwtsecret - - --eth1=${EC_API_URL} + - --eth1 - --debug-level=${CC_LOG_LEVEL} - --suggested-fee-recipient=${FEE_RECIPIENT} - --validator-monitor-auto diff --git a/cli/actions/testdata/getContainers_tests/case_consensusOnly/docker-compose.yml b/cli/actions/testdata/getContainers_tests/case_consensusOnly/docker-compose.yml index 3d08ea5d..99e618c7 100644 --- a/cli/actions/testdata/getContainers_tests/case_consensusOnly/docker-compose.yml +++ b/cli/actions/testdata/getContainers_tests/case_consensusOnly/docker-compose.yml @@ -32,7 +32,7 @@ services: - --target-peers=${CC_PEER_COUNT} - --execution-endpoints=${EC_AUTH_URL} - --execution-jwt=/tmp/jwt/jwtsecret - - --eth1=${EC_API_URL} + - --eth1 - --debug-level=${CC_LOG_LEVEL} - --suggested-fee-recipient=${FEE_RECIPIENT} - --validator-monitor-auto diff --git a/cli/actions/testdata/getContainers_tests/case_executionNF/docker-compose.yml b/cli/actions/testdata/getContainers_tests/case_executionNF/docker-compose.yml index 6178e968..6f699fe2 100644 --- a/cli/actions/testdata/getContainers_tests/case_executionNF/docker-compose.yml +++ b/cli/actions/testdata/getContainers_tests/case_executionNF/docker-compose.yml @@ -85,7 +85,7 @@ services: - --target-peers=${CC_PEER_COUNT} - --execution-endpoints=${EC_AUTH_URL} - --execution-jwt=/tmp/jwt/jwtsecret - - --eth1=${EC_API_URL} + - --eth1 - --debug-level=${CC_LOG_LEVEL} - --suggested-fee-recipient=${FEE_RECIPIENT} - --validator-monitor-auto diff --git a/cli/actions/testdata/getContainers_tests/case_fullNode/docker-compose.yml b/cli/actions/testdata/getContainers_tests/case_fullNode/docker-compose.yml index fa176df8..9d9c127b 100644 --- a/cli/actions/testdata/getContainers_tests/case_fullNode/docker-compose.yml +++ b/cli/actions/testdata/getContainers_tests/case_fullNode/docker-compose.yml @@ -85,7 +85,7 @@ services: - --target-peers=${CC_PEER_COUNT} - --execution-endpoints=${EC_AUTH_URL} - --execution-jwt=/tmp/jwt/jwtsecret - - --eth1=${EC_API_URL} + - --eth1 - --debug-level=${CC_LOG_LEVEL} - --suggested-fee-recipient=${FEE_RECIPIENT} - --validator-monitor-auto diff --git a/cli/actions/testdata/getContainers_tests/case_fullNodeTag/docker-compose.yml b/cli/actions/testdata/getContainers_tests/case_fullNodeTag/docker-compose.yml index 0154f1d6..8632b4b5 100644 --- a/cli/actions/testdata/getContainers_tests/case_fullNodeTag/docker-compose.yml +++ b/cli/actions/testdata/getContainers_tests/case_fullNodeTag/docker-compose.yml @@ -86,7 +86,7 @@ services: - --target-peers=${CC_PEER_COUNT} - --execution-endpoints=${EC_AUTH_URL} - --execution-jwt=/tmp/jwt/jwtsecret - - --eth1=${EC_API_URL} + - --eth1 - --debug-level=${CC_LOG_LEVEL} - --suggested-fee-recipient=${FEE_RECIPIENT} - --validator-monitor-auto diff --git a/cli/actions/testdata/getContainers_tests/case_noExecution/docker-compose.yml b/cli/actions/testdata/getContainers_tests/case_noExecution/docker-compose.yml index 06840f3c..a33b9a9b 100644 --- a/cli/actions/testdata/getContainers_tests/case_noExecution/docker-compose.yml +++ b/cli/actions/testdata/getContainers_tests/case_noExecution/docker-compose.yml @@ -47,7 +47,7 @@ services: - --target-peers=${CC_PEER_COUNT} - --execution-endpoints=${EC_AUTH_URL} - --execution-jwt=/tmp/jwt/jwtsecret - - --eth1=${EC_API_URL} + - --eth1 - --debug-level=${CC_LOG_LEVEL} - --suggested-fee-recipient=${FEE_RECIPIENT} - --validator-monitor-auto diff --git a/cli/actions/testdata/getContainers_tests/case_noMev/docker-compose.yml b/cli/actions/testdata/getContainers_tests/case_noMev/docker-compose.yml index 9a5026ea..98debf6e 100644 --- a/cli/actions/testdata/getContainers_tests/case_noMev/docker-compose.yml +++ b/cli/actions/testdata/getContainers_tests/case_noMev/docker-compose.yml @@ -71,7 +71,7 @@ services: - --target-peers=${CC_PEER_COUNT} - --execution-endpoints=${EC_AUTH_URL} - --execution-jwt=/tmp/jwt/jwtsecret - - --eth1=${EC_API_URL} + - --eth1 - --debug-level=${CC_LOG_LEVEL} - --suggested-fee-recipient=${FEE_RECIPIENT} - --validator-monitor-auto diff --git a/cli/actions/testdata/getContainers_tests/case_noValidator/docker-compose.yml b/cli/actions/testdata/getContainers_tests/case_noValidator/docker-compose.yml index c9b95990..f06ba0ab 100644 --- a/cli/actions/testdata/getContainers_tests/case_noValidator/docker-compose.yml +++ b/cli/actions/testdata/getContainers_tests/case_noValidator/docker-compose.yml @@ -85,7 +85,7 @@ services: - --target-peers=${CC_PEER_COUNT} - --execution-endpoints=${EC_AUTH_URL} - --execution-jwt=/tmp/jwt/jwtsecret - - --eth1=${EC_API_URL} + - --eth1 - --debug-level=${CC_LOG_LEVEL} - --suggested-fee-recipient=${FEE_RECIPIENT} - --validator-monitor-auto diff --git a/cli/actions/testdata/getContainers_tests/case_validatorNF/docker-compose.yml b/cli/actions/testdata/getContainers_tests/case_validatorNF/docker-compose.yml index cd1a806c..72761b19 100644 --- a/cli/actions/testdata/getContainers_tests/case_validatorNF/docker-compose.yml +++ b/cli/actions/testdata/getContainers_tests/case_validatorNF/docker-compose.yml @@ -85,7 +85,7 @@ services: - --target-peers=${CC_PEER_COUNT} - --execution-endpoints=${EC_AUTH_URL} - --execution-jwt=/tmp/jwt/jwtsecret - - --eth1=${EC_API_URL} + - --eth1 - --debug-level=${CC_LOG_LEVEL} - --suggested-fee-recipient=${FEE_RECIPIENT} - --validator-monitor-auto diff --git a/cli/cli.go b/cli/cli.go index 42a20101..e7dd21d1 100644 --- a/cli/cli.go +++ b/cli/cli.go @@ -28,6 +28,7 @@ import ( "github.com/NethermindEth/sedge/internal/pkg/clients" "github.com/NethermindEth/sedge/internal/pkg/dependencies" "github.com/NethermindEth/sedge/internal/pkg/generate" + sedgeOpts "github.com/NethermindEth/sedge/internal/pkg/options" "github.com/NethermindEth/sedge/internal/ui" "github.com/NethermindEth/sedge/cli/actions" @@ -79,6 +80,7 @@ type CliCmdOptions struct { keystorePassphrasePath string keystorePassphrase string withdrawalAddress string + nodeSetup string numberOfValidators int64 existingValidators int64 installDependencies bool @@ -96,6 +98,7 @@ func CliCmd(p ui.Prompter, actions actions.SedgeActions, depsMgr dependencies.De - Execution Node - Consensus Node - Validator Node +- Lido CSM Node Follow the prompts to select the options you want for your node. At the end of the process, you will be asked to run the generated setup or not. If you chose to run the setup, it will be executed for you @@ -103,6 +106,7 @@ using docker compose command behind the scenes. `, RunE: func(cmd *cobra.Command, args []string) error { if err := runPromptActions(p, o, + selectNodeSetup, selectNetwork, selectNodeType, inputGenerationPath, @@ -614,8 +618,20 @@ func runPromptActions(p ui.Prompter, o *CliCmdOptions, actions ...promptAction) return nil } +func selectNodeSetup(p ui.Prompter, o *CliCmdOptions) (err error) { + options := []string{sedgeOpts.EthereumNode, sedgeOpts.LidoNode} + index, err := p.Select("Select node setup", "", options) + if err != nil { + return err + } + o.nodeSetup = options[index] + return +} + func selectNetwork(p ui.Prompter, o *CliCmdOptions) error { - options := []string{NetworkMainnet, NetworkSepolia, NetworkGnosis, NetworkChiado, NetworkHolesky} + opts := sedgeOpts.CreateSedgeOptions(o.nodeSetup) + options := opts.SupportedNetworks() + index, err := p.Select("Select network", "", options) if err != nil { return err @@ -792,6 +808,12 @@ func confirmInstallDependencies(p ui.Prompter, o *CliCmdOptions) (err error) { } func confirmEnableMEVBoost(p ui.Prompter, o *CliCmdOptions) (err error) { + opts := sedgeOpts.CreateSedgeOptions(o.nodeSetup) + enableMev := opts.MEVBoostEnabled(o.genData.Network) + if opts.OverwriteSettings().MevBoost { + o.withMevBoost = enableMev + return + } o.withMevBoost, err = p.Confirm("Enable MEV Boost?", true) return } @@ -847,8 +869,16 @@ func inputMevBoostEndpoint(p ui.Prompter, o *CliCmdOptions) (err error) { } func inputRelayURL(p ui.Prompter, o *CliCmdOptions) (err error) { - var defaultValue []string = configs.NetworksConfigs()[o.genData.Network].RelayURLs - relayURLs, err := p.InputList("Insert relay URLs if you don't want to use the default values listed below", defaultValue, func(list []string) error { + opts := sedgeOpts.CreateSedgeOptions(o.nodeSetup) + relayURLs, err := opts.RelayURLs(o.genData.Network) + if err != nil { + return err + } + if relayURLs != nil && opts.OverwriteSettings().RelayURLs { + o.genData.RelayURLs = relayURLs + return + } + relayURLs, err = p.InputList("Insert relay URLs if you don't want to use the default values listed below", relayURLs, func(list []string) error { badUri, ok := utils.UriValidator(list) if !ok { return fmt.Errorf(configs.InvalidUrlFlagError, "relay", badUri) @@ -870,11 +900,23 @@ func inputCheckpointSyncURL(p ui.Prompter, o *CliCmdOptions) (err error) { } func inputFeeRecipient(p ui.Prompter, o *CliCmdOptions) (err error) { + opts := sedgeOpts.CreateSedgeOptions(o.nodeSetup) + feeRecipient := opts.FeeRecipient(o.genData.Network) + if opts.OverwriteSettings().FeeRecipient { + o.genData.FeeRecipient = feeRecipient + return + } o.genData.FeeRecipient, err = p.EthAddress("Please enter the Fee Recipient address", "", true) return } func inputFeeRecipientNoValidator(p ui.Prompter, o *CliCmdOptions) (err error) { + opts := sedgeOpts.CreateSedgeOptions(o.nodeSetup) + feeRecipient := opts.FeeRecipient(o.genData.Network) + if opts.OverwriteSettings().FeeRecipient { + o.genData.FeeRecipient = feeRecipient + return + } o.genData.FeeRecipient, err = p.EthAddress("Please enter the Fee Recipient address (press enter to skip it)", "", false) return } @@ -929,6 +971,12 @@ func inputKeystorePassphrase(p ui.Prompter, o *CliCmdOptions) (err error) { } func inputWithdrawalAddress(p ui.Prompter, o *CliCmdOptions) (err error) { + opts := sedgeOpts.CreateSedgeOptions(o.nodeSetup) + withdrawalAddress := opts.WithdrawalAddress(o.genData.Network) + if opts.OverwriteSettings().WithdrawalAddress { + o.withdrawalAddress = withdrawalAddress + return + } o.withdrawalAddress, err = p.Input("Withdrawal address", "", false, func(s string) error { return ui.EthAddressValidator(s, true) }) return } diff --git a/cli/cli_test.go b/cli/cli_test.go index a65f1168..5c6f6838 100644 --- a/cli/cli_test.go +++ b/cli/cli_test.go @@ -22,9 +22,11 @@ import ( "github.com/NethermindEth/sedge/cli/actions" "github.com/NethermindEth/sedge/configs" + "github.com/NethermindEth/sedge/internal/lido/contracts/mevboostrelaylist" "github.com/NethermindEth/sedge/internal/pkg/clients" "github.com/NethermindEth/sedge/internal/pkg/dependencies" "github.com/NethermindEth/sedge/internal/pkg/generate" + sedgeOpts "github.com/NethermindEth/sedge/internal/pkg/options" "github.com/NethermindEth/sedge/internal/ui" "github.com/NethermindEth/sedge/internal/utils" sedge_mocks "github.com/NethermindEth/sedge/mocks" @@ -37,6 +39,9 @@ func TestCli(t *testing.T) { // Silence logger log.SetOutput(io.Discard) + mevboostRelayListUris, _ := mevboostrelaylist.RelaysURI("mainnet") + holeskyMevboostRelayListUris, _ := mevboostrelaylist.RelaysURI("holesky") + ETHClients := map[string][]string{ "execution": clients.AllClients["execution"], "consensus": clients.AllClients["consensus"], @@ -94,7 +99,8 @@ func TestCli(t *testing.T) { } sedgeActions.EXPECT().GetCommandRunner().Return(&test.SimpleCMDRunner{}) gomock.InOrder( - prompter.EXPECT().Select("Select network", "", []string{NetworkMainnet, NetworkSepolia, NetworkGnosis, NetworkChiado, NetworkHolesky}).Return(0, nil), + prompter.EXPECT().Select("Select node setup", "", []string{sedgeOpts.EthereumNode, sedgeOpts.LidoNode}).Return(0, nil), + prompter.EXPECT().Select("Select network", "", []string{NetworkMainnet, NetworkHolesky, NetworkSepolia, NetworkGnosis, NetworkChiado}).Return(0, nil), prompter.EXPECT().Select("Select node type", "", []string{NodeTypeFullNode, NodeTypeExecution, NodeTypeConsensus, NodeTypeValidator}).Return(0, nil), prompter.EXPECT().Input("Generation path", configs.DefaultAbsSedgeDataPath, false, nil).Return(generationPath, nil), prompter.EXPECT().Input("Container tag, sedge will add to each container and the network, a suffix with the tag", "", false, nil).Return("tag", nil), @@ -164,7 +170,8 @@ func TestCli(t *testing.T) { JWTSecretPath: filepath.Join(generationPath, "jwtsecret"), } gomock.InOrder( - prompter.EXPECT().Select("Select network", "", []string{NetworkMainnet, NetworkSepolia, NetworkGnosis, NetworkChiado, NetworkHolesky}).Return(0, nil), + prompter.EXPECT().Select("Select node setup", "", []string{sedgeOpts.EthereumNode, sedgeOpts.LidoNode}).Return(0, nil), + prompter.EXPECT().Select("Select network", "", []string{NetworkMainnet, NetworkHolesky, NetworkSepolia, NetworkGnosis, NetworkChiado}).Return(0, nil), prompter.EXPECT().Select("Select node type", "", []string{NodeTypeFullNode, NodeTypeExecution, NodeTypeConsensus, NodeTypeValidator}).Return(0, nil), prompter.EXPECT().Input("Generation path", configs.DefaultAbsSedgeDataPath, false, nil).Return(generationPath, nil), prompter.EXPECT().Input("Container tag, sedge will add to each container and the network, a suffix with the tag", "", false, nil).Return("tag", nil), @@ -207,7 +214,8 @@ func TestCli(t *testing.T) { JWTSecretPath: filepath.Join(generationPath, "jwtsecret"), } gomock.InOrder( - prompter.EXPECT().Select("Select network", "", []string{NetworkMainnet, NetworkSepolia, NetworkGnosis, NetworkChiado, NetworkHolesky}).Return(4, nil), + prompter.EXPECT().Select("Select node setup", "", []string{sedgeOpts.EthereumNode, sedgeOpts.LidoNode}).Return(0, nil), + prompter.EXPECT().Select("Select network", "", []string{NetworkMainnet, NetworkHolesky, NetworkSepolia, NetworkGnosis, NetworkChiado}).Return(1, nil), prompter.EXPECT().Select("Select node type", "", []string{NodeTypeFullNode, NodeTypeExecution, NodeTypeConsensus, NodeTypeValidator}).Return(0, nil), prompter.EXPECT().Input("Generation path", configs.DefaultAbsSedgeDataPath, false, nil).Return(generationPath, nil), prompter.EXPECT().Input("Container tag, sedge will add to each container and the network, a suffix with the tag", "", false, nil).Return("tag", nil), @@ -243,7 +251,8 @@ func TestCli(t *testing.T) { } gomock.InOrder( - prompter.EXPECT().Select("Select network", "", []string{NetworkMainnet, NetworkSepolia, NetworkGnosis, NetworkChiado, NetworkHolesky}).Return(0, nil), + prompter.EXPECT().Select("Select node setup", "", []string{sedgeOpts.EthereumNode, sedgeOpts.LidoNode}).Return(0, nil), + prompter.EXPECT().Select("Select network", "", []string{NetworkMainnet, NetworkHolesky, NetworkSepolia, NetworkGnosis, NetworkChiado}).Return(0, nil), prompter.EXPECT().Select("Select node type", "", []string{NodeTypeFullNode, NodeTypeExecution, NodeTypeConsensus, NodeTypeValidator}).Return(1, nil), prompter.EXPECT().Input("Generation path", configs.DefaultAbsSedgeDataPath, false, nil).Return(generationPath, nil), prompter.EXPECT().Input("Container tag, sedge will add to each container and the network, a suffix with the tag", "", false, nil).Return("tag", nil), @@ -286,7 +295,8 @@ func TestCli(t *testing.T) { } gomock.InOrder( - prompter.EXPECT().Select("Select network", "", []string{NetworkMainnet, NetworkSepolia, NetworkGnosis, NetworkChiado, NetworkHolesky}).Return(4, nil), + prompter.EXPECT().Select("Select node setup", "", []string{sedgeOpts.EthereumNode, sedgeOpts.LidoNode}).Return(0, nil), + prompter.EXPECT().Select("Select network", "", []string{NetworkMainnet, NetworkHolesky, NetworkSepolia, NetworkGnosis, NetworkChiado}).Return(1, nil), prompter.EXPECT().Select("Select node type", "", []string{NodeTypeFullNode, NodeTypeExecution, NodeTypeConsensus, NodeTypeValidator}).Return(1, nil), prompter.EXPECT().Input("Generation path", configs.DefaultAbsSedgeDataPath, false, nil).Return(generationPath, nil), prompter.EXPECT().Input("Container tag, sedge will add to each container and the network, a suffix with the tag", "", false, nil).Return("tag", nil), @@ -335,7 +345,8 @@ func TestCli(t *testing.T) { } gomock.InOrder( - prompter.EXPECT().Select("Select network", "", []string{NetworkMainnet, NetworkSepolia, NetworkGnosis, NetworkChiado, NetworkHolesky}).Return(0, nil), + prompter.EXPECT().Select("Select node setup", "", []string{sedgeOpts.EthereumNode, sedgeOpts.LidoNode}).Return(0, nil), + prompter.EXPECT().Select("Select network", "", []string{NetworkMainnet, NetworkHolesky, NetworkSepolia, NetworkGnosis, NetworkChiado}).Return(0, nil), prompter.EXPECT().Select("Select node type", "", []string{NodeTypeFullNode, NodeTypeExecution, NodeTypeConsensus, NodeTypeValidator}).Return(2, nil), prompter.EXPECT().Input("Generation path", configs.DefaultAbsSedgeDataPath, false, nil).Return(generationPath, nil), prompter.EXPECT().Input("Container tag, sedge will add to each container and the network, a suffix with the tag", "", false, nil).Return("tag", nil), @@ -378,7 +389,8 @@ func TestCli(t *testing.T) { } gomock.InOrder( - prompter.EXPECT().Select("Select network", "", []string{NetworkMainnet, NetworkSepolia, NetworkGnosis, NetworkChiado, NetworkHolesky}).Return(4, nil), + prompter.EXPECT().Select("Select node setup", "", []string{sedgeOpts.EthereumNode, sedgeOpts.LidoNode}).Return(0, nil), + prompter.EXPECT().Select("Select network", "", []string{NetworkMainnet, NetworkHolesky, NetworkSepolia, NetworkGnosis, NetworkChiado}).Return(1, nil), prompter.EXPECT().Select("Select node type", "", []string{NodeTypeFullNode, NodeTypeExecution, NodeTypeConsensus, NodeTypeValidator}).Return(2, nil), prompter.EXPECT().Input("Generation path", configs.DefaultAbsSedgeDataPath, false, nil).Return(generationPath, nil), prompter.EXPECT().Input("Container tag, sedge will add to each container and the network, a suffix with the tag", "", false, nil).Return("tag", nil), @@ -421,7 +433,8 @@ func TestCli(t *testing.T) { } gomock.InOrder( - prompter.EXPECT().Select("Select network", "", []string{NetworkMainnet, NetworkSepolia, NetworkGnosis, NetworkChiado, NetworkHolesky}).Return(0, nil), + prompter.EXPECT().Select("Select node setup", "", []string{sedgeOpts.EthereumNode, sedgeOpts.LidoNode}).Return(0, nil), + prompter.EXPECT().Select("Select network", "", []string{NetworkMainnet, NetworkHolesky, NetworkSepolia, NetworkGnosis, NetworkChiado}).Return(0, nil), prompter.EXPECT().Select("Select node type", "", []string{NodeTypeFullNode, NodeTypeExecution, NodeTypeConsensus, NodeTypeValidator}).Return(3, nil), prompter.EXPECT().Input("Generation path", configs.DefaultAbsSedgeDataPath, false, nil).Return(generationPath, nil), prompter.EXPECT().Input("Container tag, sedge will add to each container and the network, a suffix with the tag", "", false, nil).Return("tag", nil), @@ -460,6 +473,206 @@ func TestCli(t *testing.T) { ) }, }, + { + name: "consensus node", + setup: func(t *testing.T, sedgeActions *sedge_mocks.MockSedgeActions, prompter *sedge_mocks.MockPrompter, depsMgr *sedge_mocks.MockDependenciesManager) { + generationPath := t.TempDir() + genData := generate.GenData{ + Services: []string{"consensus"}, + ConsensusClient: &clients.Client{ + Name: "lodestar", + Type: "consensus", + Image: configs.ClientImages.Consensus.Lodestar.String(), + }, + Network: NetworkMainnet, + CheckpointSyncUrl: "http://checkpoint.sync", + FeeRecipient: "0x2d07a21ebadde0c13e8b91022a7e5732eb6bf5d5", + MapAllPorts: true, + ExecutionApiUrl: "http://execution:5051", + ExecutionAuthUrl: "http://execution:5051", + MevBoostEndpoint: "http://mev-boost:3030", + ContainerTag: "tag", + JWTSecretPath: filepath.Join(generationPath, "jwtsecret"), + } + + gomock.InOrder( + prompter.EXPECT().Select("Select node setup", "", []string{sedgeOpts.EthereumNode, sedgeOpts.LidoNode}).Return(0, nil), + prompter.EXPECT().Select("Select network", "", []string{NetworkMainnet, NetworkHolesky, NetworkSepolia, NetworkGnosis, NetworkChiado}).Return(0, nil), + prompter.EXPECT().Select("Select node type", "", []string{NodeTypeFullNode, NodeTypeExecution, NodeTypeConsensus, NodeTypeValidator}).Return(2, nil), + prompter.EXPECT().Input("Generation path", configs.DefaultAbsSedgeDataPath, false, nil).Return(generationPath, nil), + prompter.EXPECT().Input("Container tag, sedge will add to each container and the network, a suffix with the tag", "", false, nil).Return("tag", nil), + prompter.EXPECT().Select("Select consensus client", "", ETHClients["consensus"]).Return(3, nil), + prompter.EXPECT().InputURL("Checkpoint sync URL", configs.NetworksConfigs()[genData.Network].CheckpointSyncURL, false).Return("http://checkpoint.sync", nil), + prompter.EXPECT().InputURL("Mev-Boost endpoint", "", false).Return("http://mev-boost:3030", nil), + prompter.EXPECT().InputURL("Execution API URL", "", true).Return("http://execution:5051", nil), + prompter.EXPECT().InputURL("Execution Auth API URL", "", true).Return("http://execution:5051", nil), + prompter.EXPECT().EthAddress("Please enter the Fee Recipient address (press enter to skip it)", "", false).Return("0x2d07a21ebadde0c13e8b91022a7e5732eb6bf5d5", nil), + prompter.EXPECT().Confirm("Do you want to expose all ports?", false).Return(true, nil), + prompter.EXPECT().Select("Select JWT source", "", []string{SourceTypeCreate, SourceTypeExisting, SourceTypeSkip}).Return(0, nil), + sedgeActions.EXPECT().Generate(gomock.Eq(actions.GenerateOptions{ + GenerationPath: generationPath, + GenerationData: genData, + })).Return(genData, nil), + prompter.EXPECT().Confirm("Run services now?", false).Return(false, nil), + ) + }, + }, + { + name: "full node with Lido", + setup: func(t *testing.T, sedgeActions *sedge_mocks.MockSedgeActions, prompter *sedge_mocks.MockPrompter, depsMgr *sedge_mocks.MockDependenciesManager) { + generationPath := t.TempDir() + genData := generate.GenData{ + Services: []string{"execution", "consensus", "validator", "mev-boost"}, + ExecutionClient: &clients.Client{ + Name: "nethermind", + Type: "execution", + Image: configs.ClientImages.Execution.Nethermind.String(), + }, + ConsensusClient: &clients.Client{ + Name: "prysm", + Type: "consensus", + Image: configs.ClientImages.Consensus.Prysm.String(), + }, + ValidatorClient: &clients.Client{ + Name: "prysm", + Type: "validator", + Image: configs.ClientImages.Validator.Prysm.String(), + }, + Network: "mainnet", + CheckpointSyncUrl: "http://checkpoint.sync", + FeeRecipient: "0x388C818CA8B9251b393131C08a736A67ccB19297", + MapAllPorts: true, + Graffiti: "test graffiti", + VLStartGracePeriod: 840, + Mev: true, + MevImage: "flashbots/mev-boost:latest", + RelayURLs: mevboostRelayListUris, + ContainerTag: "tag", + JWTSecretPath: filepath.Join(generationPath, "jwtsecret"), + } + sedgeActions.EXPECT().GetCommandRunner().Return(&test.SimpleCMDRunner{}) + gomock.InOrder( + prompter.EXPECT().Select("Select node setup", "", []string{sedgeOpts.EthereumNode, sedgeOpts.LidoNode}).Return(1, nil), + prompter.EXPECT().Select("Select network", "", []string{NetworkMainnet, NetworkHolesky, NetworkSepolia}).Return(0, nil), + prompter.EXPECT().Select("Select node type", "", []string{NodeTypeFullNode, NodeTypeExecution, NodeTypeConsensus, NodeTypeValidator}).Return(0, nil), + prompter.EXPECT().Input("Generation path", configs.DefaultAbsSedgeDataPath, false, nil).Return(generationPath, nil), + prompter.EXPECT().Input("Container tag, sedge will add to each container and the network, a suffix with the tag", "", false, nil).Return("tag", nil), + prompter.EXPECT().Confirm("Do you want to set up a validator?", true).Return(true, nil), + prompter.EXPECT().Input("Mev-Boost image", "flashbots/mev-boost:latest", false, nil).Return("flashbots/mev-boost:latest", nil), + prompter.EXPECT().Select("Select execution client", "", ETHClients["execution"]).Return(0, nil), + prompter.EXPECT().Select("Select consensus client", "", ETHClients["consensus"]).Return(1, nil), + prompter.EXPECT().Select("Select validator client", "", ETHClients["validator"]).Return(1, nil), + prompter.EXPECT().InputInt64("Validator grace period. This is the number of epochs the validator will wait for security reasons before starting", int64(1)).Return(int64(2), nil), + prompter.EXPECT().Input("Graffiti to be used by the validator (press enter to skip it)", "", false, gomock.AssignableToTypeOf(ui.GraffitiValidator)).Return("test graffiti", nil), + prompter.EXPECT().InputURL("Checkpoint sync URL", configs.NetworksConfigs()[genData.Network].CheckpointSyncURL, false).Return("http://checkpoint.sync", nil), + prompter.EXPECT().Confirm("Do you want to expose all ports?", false).Return(true, nil), + prompter.EXPECT().Select("Select JWT source", "", []string{SourceTypeCreate, SourceTypeExisting}).Return(0, nil), + sedgeActions.EXPECT().Generate(gomock.Eq(actions.GenerateOptions{ + GenerationPath: generationPath, + GenerationData: genData, + })).Return(genData, nil), + prompter.EXPECT().Select("Select keystore source", "", []string{SourceTypeCreate, SourceTypeExisting, SourceTypeSkip}).Return(0, nil), + prompter.EXPECT().Select("Select mnemonic source", "", []string{SourceTypeCreate, SourceTypeExisting}).Return(0, nil), + prompter.EXPECT().Select("Select passphrase source", "", []string{SourceTypeRandom, SourceTypeExisting, SourceTypeCreate}).Return(0, nil), + prompter.EXPECT().InputInt64("Number of validators", int64(1)).Return(int64(1), nil), + prompter.EXPECT().InputInt64("Existing validators. This number will be used as the initial index for the generated keystores.", int64(0)).Return(int64(0), nil), + depsMgr.EXPECT().Check([]string{dependencies.Docker}).Return([]string{dependencies.Docker}, nil), + depsMgr.EXPECT().DockerEngineIsOn().Return(nil), + depsMgr.EXPECT().DockerComposeIsInstalled().Return(nil), + sedgeActions.EXPECT().SetupContainers(actions.SetupContainersOptions{ + GenerationPath: generationPath, + Services: []string{"validator"}, + }), + sedgeActions.EXPECT().ImportValidatorKeys(actions.ImportValidatorKeysOptions{ + ValidatorClient: "prysm", + Network: NetworkMainnet, + GenerationPath: generationPath, + From: filepath.Join(generationPath, "keystore"), + ContainerTag: "tag", + }).Return(nil), + prompter.EXPECT().Confirm("Do you want to import slashing protection data?", false).Return(false, nil), + prompter.EXPECT().Confirm("Run services now?", false).Return(false, nil), + ) + }, + }, + { + name: "full node with Lido, holesky", + setup: func(t *testing.T, sedgeActions *sedge_mocks.MockSedgeActions, prompter *sedge_mocks.MockPrompter, depsMgr *sedge_mocks.MockDependenciesManager) { + generationPath := t.TempDir() + genData := generate.GenData{ + Services: []string{"execution", "consensus", "validator", "mev-boost"}, + ExecutionClient: &clients.Client{ + Name: "nethermind", + Type: "execution", + Image: configs.ClientImages.Execution.Nethermind.String(), + }, + ConsensusClient: &clients.Client{ + Name: "prysm", + Type: "consensus", + Image: configs.ClientImages.Consensus.Prysm.String(), + }, + ValidatorClient: &clients.Client{ + Name: "prysm", + Type: "validator", + Image: configs.ClientImages.Validator.Prysm.String(), + }, + Network: "holesky", + CheckpointSyncUrl: "http://checkpoint.sync", + FeeRecipient: "0xE73a3602b99f1f913e72F8bdcBC235e206794Ac8", + MapAllPorts: true, + Graffiti: "test graffiti", + VLStartGracePeriod: 840, + Mev: true, + MevImage: "flashbots/mev-boost:latest", + RelayURLs: holeskyMevboostRelayListUris, + ContainerTag: "tag", + JWTSecretPath: filepath.Join(generationPath, "jwtsecret"), + } + sedgeActions.EXPECT().GetCommandRunner().Return(&test.SimpleCMDRunner{}) + gomock.InOrder( + prompter.EXPECT().Select("Select node setup", "", []string{sedgeOpts.EthereumNode, sedgeOpts.LidoNode}).Return(1, nil), + prompter.EXPECT().Select("Select network", "", []string{NetworkMainnet, NetworkHolesky, NetworkSepolia}).Return(1, nil), + prompter.EXPECT().Select("Select node type", "", []string{NodeTypeFullNode, NodeTypeExecution, NodeTypeConsensus, NodeTypeValidator}).Return(0, nil), + prompter.EXPECT().Input("Generation path", configs.DefaultAbsSedgeDataPath, false, nil).Return(generationPath, nil), + prompter.EXPECT().Input("Container tag, sedge will add to each container and the network, a suffix with the tag", "", false, nil).Return("tag", nil), + prompter.EXPECT().Confirm("Do you want to set up a validator?", true).Return(true, nil), + prompter.EXPECT().Input("Mev-Boost image", "flashbots/mev-boost:latest", false, nil).Return("flashbots/mev-boost:latest", nil), + prompter.EXPECT().Select("Select execution client", "", ETHClients["execution"]).Return(0, nil), + prompter.EXPECT().Select("Select consensus client", "", ETHClients["consensus"]).Return(1, nil), + prompter.EXPECT().Select("Select validator client", "", ETHClients["validator"]).Return(1, nil), + prompter.EXPECT().InputInt64("Validator grace period. This is the number of epochs the validator will wait for security reasons before starting", int64(1)).Return(int64(2), nil), + prompter.EXPECT().Input("Graffiti to be used by the validator (press enter to skip it)", "", false, gomock.AssignableToTypeOf(ui.GraffitiValidator)).Return("test graffiti", nil), + prompter.EXPECT().InputURL("Checkpoint sync URL", configs.NetworksConfigs()[genData.Network].CheckpointSyncURL, false).Return("http://checkpoint.sync", nil), + prompter.EXPECT().Confirm("Do you want to expose all ports?", false).Return(true, nil), + prompter.EXPECT().Select("Select JWT source", "", []string{SourceTypeCreate, SourceTypeExisting}).Return(0, nil), + sedgeActions.EXPECT().Generate(gomock.Eq(actions.GenerateOptions{ + GenerationPath: generationPath, + GenerationData: genData, + })).Return(genData, nil), + prompter.EXPECT().Select("Select keystore source", "", []string{SourceTypeCreate, SourceTypeExisting, SourceTypeSkip}).Return(0, nil), + prompter.EXPECT().Select("Select mnemonic source", "", []string{SourceTypeCreate, SourceTypeExisting}).Return(0, nil), + prompter.EXPECT().Select("Select passphrase source", "", []string{SourceTypeRandom, SourceTypeExisting, SourceTypeCreate}).Return(0, nil), + prompter.EXPECT().InputInt64("Number of validators", int64(1)).Return(int64(1), nil), + prompter.EXPECT().InputInt64("Existing validators. This number will be used as the initial index for the generated keystores.", int64(0)).Return(int64(0), nil), + depsMgr.EXPECT().Check([]string{dependencies.Docker}).Return([]string{dependencies.Docker}, nil), + depsMgr.EXPECT().DockerEngineIsOn().Return(nil), + depsMgr.EXPECT().DockerComposeIsInstalled().Return(nil), + sedgeActions.EXPECT().SetupContainers(actions.SetupContainersOptions{ + GenerationPath: generationPath, + Services: []string{"validator"}, + }), + sedgeActions.EXPECT().ImportValidatorKeys(actions.ImportValidatorKeysOptions{ + ValidatorClient: "prysm", + Network: NetworkHolesky, + GenerationPath: generationPath, + From: filepath.Join(generationPath, "keystore"), + ContainerTag: "tag", + }).Return(nil), + prompter.EXPECT().Confirm("Do you want to import slashing protection data?", false).Return(false, nil), + prompter.EXPECT().Confirm("Run services now?", false).Return(false, nil), + ) + }, + }, } for _, tt := range tests { diff --git a/cli/generate.go b/cli/generate.go index 7637cc2b..96afe4e5 100644 --- a/cli/generate.go +++ b/cli/generate.go @@ -30,6 +30,7 @@ import ( "github.com/NethermindEth/sedge/configs" "github.com/NethermindEth/sedge/internal/pkg/clients" "github.com/NethermindEth/sedge/internal/pkg/generate" + sedgeOpts "github.com/NethermindEth/sedge/internal/pkg/options" "github.com/NethermindEth/sedge/internal/ui" "github.com/NethermindEth/sedge/internal/utils" log "github.com/sirupsen/logrus" @@ -42,6 +43,7 @@ var ( network string logging string containerTag string + lidoNode bool ) const ( @@ -101,6 +103,7 @@ You can generate: - Consensus Node - Validator Node - Mev-Boost Instance +- Lido CSM node `, Args: cobra.NoArgs, } @@ -111,6 +114,7 @@ You can generate: cmd.AddCommand(ValidatorSubCmd(sedgeAction)) cmd.AddCommand(MevBoostSubCmd(sedgeAction)) + cmd.PersistentFlags().BoolVar(&lidoNode, "lido", false, "generate Lido CSM node") cmd.PersistentFlags().StringVarP(&generationPath, "path", "p", configs.DefaultAbsSedgeDataPath, "generation path for sedge data. Default is sedge-data") cmd.PersistentFlags().StringVarP(&network, "network", "n", "mainnet", "Target network. e.g. mainnet,sepolia, holesky, gnosis, chiado, etc.") cmd.PersistentFlags().StringVar(&logging, "logging", "json", fmt.Sprintf("Docker logging driver used by all the services. Set 'none' to use the default docker logging driver. Possible values: %v", configs.ValidLoggingFlags())) @@ -258,6 +262,13 @@ func runGenCmd(out io.Writer, flags *GenCmdFlags, sedgeAction actions.SedgeActio } } + // Overwrite feeRecipient and relayURLs for Lido Node + if lidoNode { + opts := sedgeOpts.CreateSedgeOptions(sedgeOpts.LidoNode) + flags.feeRecipient = opts.FeeRecipient(network) + flags.relayURLs, _ = opts.RelayURLs(network) + } + // Warning if no fee recipient is set if flags.feeRecipient == "" { log.Warn(configs.EmptyFeeRecipientError) @@ -493,3 +504,13 @@ func loadJWTSecret(from string) (absFrom string, err error) { } return } + +func nodeType() string { + var nodeType string + if lidoNode { + nodeType = sedgeOpts.LidoNode + } else { + nodeType = sedgeOpts.EthereumNode + } + return nodeType +} diff --git a/cli/generate_test.go b/cli/generate_test.go index 7b45f043..24a65512 100644 --- a/cli/generate_test.go +++ b/cli/generate_test.go @@ -26,6 +26,8 @@ import ( "github.com/NethermindEth/sedge/cli/actions" "github.com/NethermindEth/sedge/configs" + "github.com/NethermindEth/sedge/internal/lido/contracts" + "github.com/NethermindEth/sedge/internal/lido/contracts/mevboostrelaylist" "github.com/NethermindEth/sedge/test" log "github.com/sirupsen/logrus" "github.com/stretchr/testify/assert" @@ -48,6 +50,7 @@ type globalFlags struct { generationPath string network string logging string + lidoNode bool } type generateCmdTestCase struct { @@ -72,6 +75,9 @@ func (flags *globalFlags) argsList() []string { if flags.logging != "" { s = append(s, "--logging", flags.logging) } + if flags.lidoNode { + s = append(s, "--lido") + } return s } @@ -1320,10 +1326,64 @@ func TestGenerateCmd(t *testing.T) { distributed: true, }, globalFlags{ - network: "goerli", + network: "holesky", + }, + nil, + }, + { + "Lido Full-node - Holesky without MEV", + subCmd{ + name: "full-node", + }, + GenCmdFlags{ + noMev: true, + }, + globalFlags{ + network: NetworkHolesky, + lidoNode: true, }, nil, }, + { + "Lido Full-node - Sepolia", + subCmd{ + name: "full-node", + }, + GenCmdFlags{}, + globalFlags{ + network: NetworkSepolia, + lidoNode: true, + }, + fmt.Errorf(configs.InvalidNetworkForLidoMevBoost, mevboostrelaylist.LidoSupportedNetworksMevBoost()), + }, + { + "Lido Full-node - Holesky no validator", + subCmd{ + name: "full-node", + }, + GenCmdFlags{ + noValidator: true, + }, + globalFlags{ + network: NetworkHolesky, + lidoNode: true, + }, + nil, + }, + { + "Lido Full-node - unsupported Gnosis", + subCmd{ + name: "full-node", + }, + GenCmdFlags{ + noMev: true, + }, + globalFlags{ + network: NetworkGnosis, + lidoNode: true, + }, + fmt.Errorf(configs.InvalidNetworkForLido, contracts.LidoSupportedNetworks()), + }, } // TODO: Add test cases for Execution fallback urls diff --git a/cli/keys.go b/cli/keys.go index 3b9d4ea9..f7bef209 100644 --- a/cli/keys.go +++ b/cli/keys.go @@ -21,6 +21,7 @@ import ( "path/filepath" "github.com/NethermindEth/sedge/configs" + "github.com/NethermindEth/sedge/internal/lido/contracts" "github.com/NethermindEth/sedge/internal/pkg/commands" "github.com/NethermindEth/sedge/internal/pkg/keystores" "github.com/NethermindEth/sedge/internal/ui" @@ -31,15 +32,16 @@ import ( ) type KeysCmdFlags struct { - network string - path string - eth1WithdrawalAddress string - mnemonicPath string - passphrasePath string - existingVal int64 - numberVal int64 - randomPassphrase bool - install bool + network string + path string + ethWithdrawalAddress string + mnemonicPath string + passphrasePath string + existingVal int64 + numberVal int64 + randomPassphrase bool + install bool + lidoNode bool } func KeysCmd(cmdRunner commands.CommandRunner, p ui.Prompter) *cobra.Command { @@ -85,7 +87,7 @@ func KeysCmd(cmdRunner commands.CommandRunner, p ui.Prompter) *cobra.Command { log.Fatal(err.Error()) } // Validate fee recipient - if flags.eth1WithdrawalAddress != "" && !utils.IsAddress(flags.eth1WithdrawalAddress) { + if flags.ethWithdrawalAddress != "" && !utils.IsAddress(flags.ethWithdrawalAddress) { log.Fatal(configs.ErrInvalidWithdrawalAddr) } // Ensure that path is absolute @@ -98,8 +100,19 @@ func KeysCmd(cmdRunner commands.CommandRunner, p ui.Prompter) *cobra.Command { return nil }, Run: func(cmd *cobra.Command, args []string) { + // Incompatible --lido and --eth-withdrawal-address together + if flags.lidoNode && flags.ethWithdrawalAddress != "" { + log.Fatalf(configs.IncompatibleLidoAndEth1Withdrawal) + } + // validate network for Lido + if flags.lidoNode { + supported := contracts.NetworkSupportedByLidoWithdrawal(flags.network) + if !supported { + log.Fatalf(configs.InvalidNetworkForLidoKeys, contracts.LidoWithdrawalSupportedNetworks()) + } + } // Warn about withdrawal address - if flags.eth1WithdrawalAddress != "" { + if flags.ethWithdrawalAddress != "" { log.Warn(configs.WithdrawalAddressDefinedWarning) } // Get keystore passphrase @@ -164,8 +177,11 @@ func KeysCmd(cmdRunner commands.CommandRunner, p ui.Prompter) *cobra.Command { keystorePath := filepath.Join(flags.path, "keystore") var withdrawalAddress string - if flags.eth1WithdrawalAddress != "" { - withdrawalAddress = flags.eth1WithdrawalAddress[2:] + if flags.lidoNode { + withdrawalAddress, _ = contracts.WithdrawalAddress(flags.network) + withdrawalAddress = withdrawalAddress[2:] + } else if flags.ethWithdrawalAddress != "" { + withdrawalAddress = flags.ethWithdrawalAddress[2:] } data := keystores.ValidatorKeysGenData{ @@ -194,12 +210,14 @@ func KeysCmd(cmdRunner commands.CommandRunner, p ui.Prompter) *cobra.Command { log.Fatal(err) } log.Info(configs.DepositDataGenerated) + log.Infof(configs.KeystorePath, keystorePath) }, } // Flag binds + cmd.PersistentFlags().BoolVar(&flags.lidoNode, "lido", false, "Enable Lido CSM compatible keys. Similar to using --eth-withdrawal-address with the Lido Withdrawal Vault address.") cmd.Flags().StringVarP(&flags.network, "network", "n", "mainnet", "Target network. e.g. mainnet,sepolia, holesky, gnosis, chiado etc.") cmd.Flags().StringVarP(&flags.path, "path", "p", configs.DefaultAbsSedgeDataPath, "Absolute path to keystore folder. e.g. /home/user/keystore") - cmd.Flags().StringVar(&flags.eth1WithdrawalAddress, "eth1-withdrawal-address", "", "If this field is set and valid, the given Eth1 address will be used to create the withdrawal credentials. Otherwise, it will generate withdrawal credentials with the mnemonic-derived withdrawal public key in EIP-2334 format.") + cmd.Flags().StringVar(&flags.ethWithdrawalAddress, "eth-withdrawal-address", "", "If this field is set and valid, the given Eth address will be used to create the withdrawal credentials. Otherwise, it will generate withdrawal credentials with the mnemonic-derived withdrawal public key in EIP-2334 format.") cmd.Flags().StringVar(&flags.mnemonicPath, "mnemonic-path", "", "Path to file with a existing mnemonic to use.") cmd.Flags().StringVar(&flags.passphrasePath, "passphrase-path", "", "Path to file with a keystores passphrase to use.") cmd.Flags().Int64Var(&flags.existingVal, "existing", -1, `Number of validators generated with the provided mnemonic. Will be ignored if "--mnemonic-path" its not set. This number will be used as the initial index for the generated keystores.`) diff --git a/cli/sub_gen.go b/cli/sub_gen.go index ffd59db5..1606e9aa 100644 --- a/cli/sub_gen.go +++ b/cli/sub_gen.go @@ -19,6 +19,7 @@ import ( "errors" "github.com/NethermindEth/sedge/cli/actions" + sedgeOpts "github.com/NethermindEth/sedge/internal/pkg/options" "github.com/spf13/cobra" ) @@ -55,7 +56,15 @@ Additionally, you can use this syntax ':' to override the if err := validateCustomNetwork(&flags.CustomFlags, network); err != nil { return err } - return preValidationGenerateCmd(network, logging, &flags) + if err := preValidationGenerateCmd(network, logging, &flags); err != nil { + return err + } + opts := sedgeOpts.CreateSedgeOptions(nodeType()) + settings := sedgeOpts.OptionSettings{ + Network: network, + MEVBoostEnabled: !flags.noMev && !flags.noValidator, + } + return opts.ValidateSettings(settings) }, RunE: func(cmd *cobra.Command, args []string) error { services := []string{execution, consensus} @@ -83,10 +92,12 @@ Additionally, you can use this syntax ':' to override the cmd.Flags().BoolVar(&flags.distributed, "distributed", false, "Deploy a node configured to run as part of a Distributed Validator Cluster.") cmd.Flags().BoolVar(&flags.latestVersion, "latest", false, "Use the latest version of clients. This sets the \"latest\" tag on the client's docker images. Latest version might not work.") cmd.Flags().StringVar(&flags.checkpointSyncUrl, "checkpoint-sync-url", "", "Initial state endpoint (trusted synced consensus endpoint) for the consensus client to sync from a finalized checkpoint. Provide faster sync process for the consensus client and protect it from long-range attacks affored by Weak Subjetivity. Each network has a default checkpoint sync url.") - cmd.Flags().StringVar(&flags.feeRecipient, "fee-recipient", "", "Suggested fee recipient. Is a 20-byte Ethereum address which the execution layer might choose to set as the coinbase and the recipient of other fees or rewards. There is no guarantee that an execution node will use the suggested fee recipient to collect fees, it may use any address it chooses. It is assumed that an honest execution node will use the suggested fee recipient, but users should note this trust assumption") + cmd.Flags().StringVar(&flags.feeRecipient, "fee-recipient", "", "Suggested fee recipient. Is a 20-byte Ethereum address which the execution layer might choose to set as the coinbase and the recipient of other fees or rewards. There is no guarantee that an execution node will use the suggested fee recipient to collect fees, it may use any address it chooses. It is assumed that an honest execution node will use the suggested fee recipient, but users should note this trust assumption.\n"+ + "Note: When setting up a Lido node, fee recipient address will be automatically set by the system.") cmd.Flags().BoolVar(&flags.noMev, "no-mev-boost", false, "Not use mev-boost if supported") cmd.Flags().StringVarP(&flags.mevImage, "mev-boost-image", "m", "", "Custom docker image to use for Mev Boost. Example: 'sedge generate full-node --mev-boost-image flashbots/mev-boost:latest-portable'") - cmd.Flags().StringSliceVar(&flags.relayURLs, "relay-urls", []string{}, "List of comma separated relay URLs used to connect to mev relay. Example: 'sedge generate full-node --relay-urls=https://0xac6e77dfe25ecd6110b8e780608cce0dab71fdd5ebea22a16c0205200f2f8e2e3ad3b71d3499c54ad14d6c21b41a37ae@boost-relay.flashbots.net,https://0xa1559ace749633b997cb3fdacffb890aeebdb0f5a3b6aaa7eeeaf1a38af0a8fe88b9e4b1f61f236d2e64d95733327a62@relay.ultrasound.money'") + cmd.Flags().StringSliceVar(&flags.relayURLs, "relay-urls", []string{}, "List of comma separated relay URLs used to connect to mev relay. Example: 'sedge generate full-node --relay-urls=https://0xac6e77dfe25ecd6110b8e780608cce0dab71fdd5ebea22a16c0205200f2f8e2e3ad3b71d3499c54ad14d6c21b41a37ae@boost-relay.flashbots.net,https://0xa1559ace749633b997cb3fdacffb890aeebdb0f5a3b6aaa7eeeaf1a38af0a8fe88b9e4b1f61f236d2e64d95733327a62@relay.ultrasound.money'\n"+ + "Note: When setting up a Lido node, the provided relay URLs will be automatically set by the system.") cmd.Flags().BoolVar(&flags.noValidator, "no-validator", false, "Exclude the validator from the full node setup. Designed for execution and consensus nodes setup without a validator node. Exclude also the validator from other flags. If set, mev-boost will not be used.") cmd.Flags().StringVar(&flags.jwtPath, "jwt-secret-path", "", "Path to the JWT secret file") cmd.Flags().StringVar(&flags.graffiti, "graffiti", "", "Graffiti to be used by the validator") @@ -129,7 +140,15 @@ func ExecutionSubCmd(sedgeAction actions.SedgeActions) *cobra.Command { if err := validateCustomNetwork(&flags.CustomFlags, network); err != nil { return err } - return preValidationGenerateCmd(network, logging, &flags) + if err := preValidationGenerateCmd(network, logging, &flags); err != nil { + return err + } + opts := sedgeOpts.CreateSedgeOptions(nodeType()) + settings := sedgeOpts.OptionSettings{ + Network: network, + MEVBoostEnabled: false, // MEV Boost is not supported for execution nodes only + } + return opts.ValidateSettings(settings) }, RunE: func(cmd *cobra.Command, args []string) error { return runGenCmd(cmd.OutOrStdout(), &flags, sedgeAction, []string{execution}) @@ -174,7 +193,15 @@ func ConsensusSubCmd(sedgeAction actions.SedgeActions) *cobra.Command { if err := validateCustomNetwork(&flags.CustomFlags, network); err != nil { return err } - return preValidationGenerateCmd(network, logging, &flags) + if err := preValidationGenerateCmd(network, logging, &flags); err != nil { + return err + } + opts := sedgeOpts.CreateSedgeOptions(nodeType()) + settings := sedgeOpts.OptionSettings{ + Network: network, + MEVBoostEnabled: false, // MEV Boost is not supported for consensus nodes only + } + return opts.ValidateSettings(settings) }, RunE: func(cmd *cobra.Command, args []string) error { return runGenCmd(cmd.OutOrStdout(), &flags, sedgeAction, []string{consensus}) @@ -185,7 +212,8 @@ func ConsensusSubCmd(sedgeAction actions.SedgeActions) *cobra.Command { cmd.Flags().StringVar(&flags.executionApiUrl, "execution-api-url", "", "Execution API endpoint for the consensus client. Example: 'sedge generate consensus -r --execution-api-url=https://api.url.endpoint'") cmd.Flags().StringVar(&flags.executionAuthUrl, "execution-auth-url", "", "Execution AUTH endpoint for the consensus client. Example: 'sedge generate consensus -r --execution-auth-url=https://auth.url.endpoint'") cmd.Flags().StringVar(&flags.checkpointSyncUrl, "checkpoint-sync-url", "", "Initial state endpoint (trusted synced consensus endpoint) for the consensus client to sync from a finalized checkpoint. Provide faster sync process for the consensus client and protect it from long-range attacks affored by Weak Subjetivity. Each network has a default checkpoint sync url.") - cmd.Flags().StringVar(&flags.feeRecipient, "fee-recipient", "", "Suggested fee recipient. Is a 20-byte Ethereum address which the execution layer might choose to set as the coinbase and the recipient of other fees or rewards. There is no guarantee that an execution node will use the suggested fee recipient to collect fees, it may use any address it chooses. It is assumed that an honest execution node will use the suggested fee recipient, but users should note this trust assumption") + cmd.Flags().StringVar(&flags.feeRecipient, "fee-recipient", "", "Suggested fee recipient. Is a 20-byte Ethereum address which the execution layer might choose to set as the coinbase and the recipient of other fees or rewards. There is no guarantee that an execution node will use the suggested fee recipient to collect fees, it may use any address it chooses. It is assumed that an honest execution node will use the suggested fee recipient, but users should note this trust assumption.\n"+ + "Note: When setting up a Lido node, fee recipient address will be automatically set by the system.") cmd.Flags().StringVar(&flags.jwtPath, "jwt-secret-path", "", "Path to the JWT secret file") cmd.Flags().StringVar(&flags.mevBoostUrl, "mev-boost-url", "", "If you are running a mev boost node, and you want to connect to it, you need to set mev-boost-url, if not set, node will not load any mev boost related config.") cmd.Flags().BoolVar(&flags.mapAllPorts, "map-all", false, "Map all clients ports to host. Use with care. Useful to allow remote access to the clients") @@ -233,7 +261,15 @@ func ValidatorSubCmd(sedgeAction actions.SedgeActions) *cobra.Command { if err := validateCustomNetwork(&flags.CustomFlags, network); err != nil { return err } - return preValidationGenerateCmd(network, logging, &flags) + if err := preValidationGenerateCmd(network, logging, &flags); err != nil { + return err + } + opts := sedgeOpts.CreateSedgeOptions(nodeType()) + settings := sedgeOpts.OptionSettings{ + Network: network, + MEVBoostEnabled: !flags.noMev && !flags.noValidator, + } + return opts.ValidateSettings(settings) }, RunE: func(cmd *cobra.Command, args []string) error { flags.noMev = true @@ -243,7 +279,8 @@ func ValidatorSubCmd(sedgeAction actions.SedgeActions) *cobra.Command { // Bind flags cmd.Flags().BoolVar(&flags.latestVersion, "latest", false, "Use the latest version of clients. This sets the \"latest\" tag on the client's docker images. Latest version might not work.") cmd.Flags().StringVar(&flags.consensusApiUrl, "consensus-url", "", "Consensus endpoint for the validator client to connect to. Example: 'sedge generate validator --consensus-url http://localhost:4000'") - cmd.Flags().StringVar(&flags.feeRecipient, "fee-recipient", "", "Suggested fee recipient. Is a 20-byte Ethereum address which the execution layer might choose to set as the coinbase and the recipient of other fees or rewards. There is no guarantee that an execution node will use the suggested fee recipient to collect fees, it may use any address it chooses. It is assumed that an honest execution node will use the suggested fee recipient, but users should note this trust assumption") + cmd.Flags().StringVar(&flags.feeRecipient, "fee-recipient", "", "Suggested fee recipient. Is a 20-byte Ethereum address which the execution layer might choose to set as the coinbase and the recipient of other fees or rewards. There is no guarantee that an execution node will use the suggested fee recipient to collect fees, it may use any address it chooses. It is assumed that an honest execution node will use the suggested fee recipient, but users should note this trust assumption.\n"+ + "Note: When setting up a Lido node, fee recipient address will be automatically set by the system.") cmd.Flags().StringVar(&flags.graffiti, "graffiti", "", "Graffiti to be used by the validator") cmd.Flags().BoolVar(&flags.mevBoostOnVal, "mev-boost", false, "Use mev-boost while turning on validator node") cmd.Flags().StringVar(&flags.customNetworkConfig, "custom-config", "", "File path or url to use as custom network config file for consensus client.") @@ -275,7 +312,8 @@ func MevBoostSubCmd(sedgeAction actions.SedgeActions) *cobra.Command { }, } // Bind flags - cmd.Flags().StringSliceVar(&flags.relayURLs, "relay-urls", []string{}, "List of comma separated relay URLs used to connect to mev relay. Example: 'sedge generate mev-boost --relay-urls=https://0xac6e77dfe25ecd6110b8e780608cce0dab71fdd5ebea22a16c0205200f2f8e2e3ad3b71d3499c54ad14d6c21b41a37ae@boost-relay.flashbots.net,https://0xa1559ace749633b997cb3fdacffb890aeebdb0f5a3b6aaa7eeeaf1a38af0a8fe88b9e4b1f61f236d2e64d95733327a62@relay.ultrasound.money'") + cmd.Flags().StringSliceVar(&flags.relayURLs, "relay-urls", []string{}, "List of comma separated relay URLs used to connect to mev relay. Example: 'sedge generate full-node --relay-urls=https://0xac6e77dfe25ecd6110b8e780608cce0dab71fdd5ebea22a16c0205200f2f8e2e3ad3b71d3499c54ad14d6c21b41a37ae@boost-relay.flashbots.net,https://0xa1559ace749633b997cb3fdacffb890aeebdb0f5a3b6aaa7eeeaf1a38af0a8fe88b9e4b1f61f236d2e64d95733327a62@relay.ultrasound.money'\n"+ + "Note: When setting up a Lido node, the provided relay URLs will be automatically set by the system.") cmd.Flags().StringVarP(&flags.mevImage, "mev-boost-image", "m", "", "Custom docker image to use for Mev Boost. Example: 'sedge generate mev-boost --mev-boost-image flashbots/mev-boost:latest-portable'") cmd.Flags().StringVarP(&network, "network", "n", "mainnet", "Target network. e.g. mainnet, sepolia etc.") cmd.Flags().SortFlags = false diff --git a/cli/testdata/run_tests/no_env/docker-compose.yml b/cli/testdata/run_tests/no_env/docker-compose.yml index dd476997..41a203c6 100644 --- a/cli/testdata/run_tests/no_env/docker-compose.yml +++ b/cli/testdata/run_tests/no_env/docker-compose.yml @@ -88,7 +88,7 @@ services: - --target-peers=${CC_PEER_COUNT} - --execution-endpoints=${EC_AUTH_URL} - --execution-jwt=/tmp/jwt/jwtsecret - - --eth1=${EC_API_URL} + - --eth1 - --debug-level=${CC_LOG_LEVEL} - --validator-monitor-auto - --subscribe-all-subnets diff --git a/cli/testdata/run_tests/no_version/docker-compose.yml b/cli/testdata/run_tests/no_version/docker-compose.yml index 63ea362c..a23d4e0d 100644 --- a/cli/testdata/run_tests/no_version/docker-compose.yml +++ b/cli/testdata/run_tests/no_version/docker-compose.yml @@ -87,7 +87,7 @@ services: - --target-peers=${CC_PEER_COUNT} - --execution-endpoints=${EC_AUTH_URL} - --execution-jwt=/tmp/jwt/jwtsecret - - --eth1=${EC_API_URL} + - --eth1 - --debug-level=${CC_LOG_LEVEL} - --validator-monitor-auto - --subscribe-all-subnets diff --git a/cli/testdata/run_tests/valid/docker-compose.yml b/cli/testdata/run_tests/valid/docker-compose.yml index 63ea362c..a23d4e0d 100644 --- a/cli/testdata/run_tests/valid/docker-compose.yml +++ b/cli/testdata/run_tests/valid/docker-compose.yml @@ -87,7 +87,7 @@ services: - --target-peers=${CC_PEER_COUNT} - --execution-endpoints=${EC_AUTH_URL} - --execution-jwt=/tmp/jwt/jwtsecret - - --eth1=${EC_API_URL} + - --eth1 - --debug-level=${CC_LOG_LEVEL} - --validator-monitor-auto - --subscribe-all-subnets diff --git a/configs/client_images.yaml b/configs/client_images.yaml index f8605e66..d95dd03f 100644 --- a/configs/client_images.yaml +++ b/configs/client_images.yaml @@ -1,43 +1,43 @@ execution: geth: name: ethereum/client-go - version: v1.13.14 + version: v1.14.6 besu: name: hyperledger/besu - version: 24.3.0 + version: 24.6.0 nethermind: name: nethermind/nethermind - version: 1.25.4 + version: 1.27.0 erigon: name: thorax/erigon - version: v2.58.1 + version: v2.60.2 consensus: lighthouse: name: sigp/lighthouse - version: v5.0.0 + version: v5.2.1 lodestar: name: chainsafe/lodestar - version: v1.16.0 + version: v1.19.0 teku: name: consensys/teku - version: 24.3.0 + version: 24.6.1 prysm: name: gcr.io/prysmaticlabs/prysm/beacon-chain - version: v5.0.0 + version: v5.0.4 validator: lighthouse: name: sigp/lighthouse - version: v5.0.0 + version: v5.2.1 lodestar: name: chainsafe/lodestar - version: v1.16.0 + version: v1.19.0 teku: name: consensys/teku - version: 24.3.0 + version: 24.6.1 prysm: name: gcr.io/prysmaticlabs/prysm/validator - version: v5.0.0 + version: v5.0.4 distributed: charon: name: ghcr.io/obolnetwork/charon - version: v0.19.2 \ No newline at end of file + version: v0.19.2 diff --git a/configs/errors.go b/configs/errors.go index ca1de8c1..8b82002f 100644 --- a/configs/errors.go +++ b/configs/errors.go @@ -87,4 +87,8 @@ const ( ErrWithdrawalEth1SecretKeyCreation = "failed to create withdrawal private key for address 0x%s: %v" ErrWithdrawalBLSSecretKeyCreation = "failed to create withdrawal private key for path %q: %v" ErrInvalidWithdrawalAddr = "provided withdrawal address is not a valid Ethereum address" + IncompatibleLidoAndEth1Withdrawal = "incompatible flags --lido, and --eth-withdrawal-address can't be used together" + InvalidNetworkForLido = "invalid network: Choose valid network for Lido: %v" + InvalidNetworkForLidoMevBoost = "invalid network: Choose valid network for Lido with MEV-Boost: %v" + InvalidNetworkForLidoKeys = "invalid network: Choose valid network for Lido Withdrawal Address: %v" ) diff --git a/configs/init.go b/configs/init.go index db5dd533..77e953d1 100644 --- a/configs/init.go +++ b/configs/init.go @@ -32,6 +32,7 @@ var networksConfigs map[string]NetworkConfig = map[string]NetworkConfig{ "https://0xac6e77dfe25ecd6110b8e780608cce0dab71fdd5ebea22a16c0205200f2f8e2e3ad3b71d3499c54ad14d6c21b41a37ae@boost-relay.flashbots.net", "https://0xa1559ace749633b997cb3fdacffb890aeebdb0f5a3b6aaa7eeeaf1a38af0a8fe88b9e4b1f61f236d2e64d95733327a62@relay.ultrasound.money", }, + Weight: 1, }, NetworkSepolia: { Name: NetworkSepolia, @@ -42,23 +43,26 @@ var networksConfigs map[string]NetworkConfig = map[string]NetworkConfig{ RelayURLs: []string{ "https://0x845bd072b7cd566f02faeb0a4033ce9399e42839ced64e8b2adcfc859ed1e8e1a5a293336a49feac6d9a5edb779be53a@builder-relay-sepolia.flashbots.net", }, + Weight: 3, }, NetworkChiado: { Name: NetworkChiado, NetworkService: "merge", GenesisForkVersion: "0x0000006f", CheckpointSyncURL: "https://checkpoint.chiadochain.net", + Weight: 5, }, NetworkGnosis: { Name: NetworkGnosis, NetworkService: "merge", GenesisForkVersion: "0x00000064", CheckpointSyncURL: "https://checkpoint.gnosischain.com", + Weight: 4, }, NetworkHolesky: { Name: NetworkHolesky, NetworkService: "merge", - GenesisForkVersion: "0x00017000", + GenesisForkVersion: "0x01017000", SupportsMEVBoost: true, CheckpointSyncURL: "https://checkpoint-sync.holesky.ethpandaops.io/", RelayURLs: []string{ @@ -67,11 +71,13 @@ var networksConfigs map[string]NetworkConfig = map[string]NetworkConfig{ "https://0xab78bf8c781c58078c3beb5710c57940874dd96aef2835e7742c866b4c7c0406754376c2c8285a36c630346aa5c5f833@holesky.aestus.live", "https://0xaa58208899c6105603b74396734a6263cc7d947f444f396a90f7b7d3e65d102aec7e5e5291b27e08d02c50a050825c2f@holesky.titanrelay.xyz", }, + Weight: 2, }, NetworkCustom: { Name: NetworkCustom, NetworkService: "merge", GenesisForkVersion: "0x00000000", // TODO: only affects keystores generation, ensure the deposit method does not conflict over this. + Weight: 6, }, } diff --git a/configs/messages.go b/configs/messages.go index f57f2177..d4b9be4f 100644 --- a/configs/messages.go +++ b/configs/messages.go @@ -57,6 +57,7 @@ const ( KeystoresGenerated = "Keystores generated successfully" GeneratingDepositData = "Generating deposit data..." DepositDataGenerated = "Deposit data generated successfully" + KeystorePath = "Keystore path: %s" KeysFoundAt = "If everything went well, your keys can be found at: %s" ImageNotFoundBuilding = "Image %s not found, building it" ImageNotFoundPulling = "Image %s not found, pulling it" diff --git a/configs/public_rpcs.go b/configs/public_rpcs.go index f014eb92..e40ece86 100644 --- a/configs/public_rpcs.go +++ b/configs/public_rpcs.go @@ -19,7 +19,6 @@ var networkRPCs = map[string]RPC{ NetworkHolesky: { NetworkName: NetworkHolesky, PublicRPCs: []string{ - "https://1rpc.io/holesky", "https://holesky.drpc.org", "https://ethereum-holesky-rpc.publicnode.com", "https://endpoints.omniatech.io/v1/eth/holesky/public", diff --git a/configs/types.go b/configs/types.go index cb3af28b..599b3288 100644 --- a/configs/types.go +++ b/configs/types.go @@ -34,4 +34,5 @@ type NetworkConfig struct { SupportsMEVBoost bool CheckpointSyncURL string RelayURLs []string + Weight int // Weight of the network for sorting purposes } diff --git a/docs/docs/commands/cli.mdx b/docs/docs/commands/cli.mdx index ed73be9f..e947b3b7 100644 --- a/docs/docs/commands/cli.mdx +++ b/docs/docs/commands/cli.mdx @@ -18,6 +18,7 @@ This command will guide you through the process of setting up one of these node - Execution Node - Consensus Node - Validator Node +- Lido CSM Node Follow the prompts to select the options you want for your node. At the end of the process, you will be asked to run the generated setup or not. If you chose to run the setup, it will be executed for you diff --git a/docs/docs/commands/generate.mdx b/docs/docs/commands/generate.mdx index 4bd2cb7e..7f07ec99 100644 --- a/docs/docs/commands/generate.mdx +++ b/docs/docs/commands/generate.mdx @@ -22,6 +22,7 @@ You can generate: - Consensus Node - Validator Node - Mev-Boost Instance +- Lido CSM node Usage: sedge generate [command] @@ -36,6 +37,7 @@ Available Commands: Flags: --container-tag string Container tag to use. If defined, sedge will add to each container and the network, a suffix with the tag. e.g. sedge-validator-client -> sedge-validator-client-. -h, --help help for generate + --lido generate Lido CSM node --logging string Docker logging driver used by all the services. Set 'none' to use the default docker logging driver. Possible values: [none json] (default "json") -n, --network string Target network. e.g. mainnet, sepolia, holesky, gnosis, chiado, etc. (default "mainnet") -p, --path string generation path for sedge data. Default is sedge-data (default "/path/to/sedge-data") @@ -46,6 +48,15 @@ Global Flags: Use "sedge generate [command] --help" for more information about a command. ``` +### Lido Flow + +With the `--lido` flag, you can generate a Lido CSM node. This will generate a full node, a execution, a consensus, a validator o a mev-boost node with the Lido CSM configuration. + +It will include in the configuration of the selected node: +- Lido Withdrawal Credentials +- Lido Fee Recipient Address +- Designated MEV-Boost Relay URL + ### Sub Commands #### Full-Node @@ -77,10 +88,12 @@ Flags: -v, --validator string Validator engine client, e.g. teku, lodestar, prysm, lighthouse, Nimbus. Additionally, you can use this syntax ':' to override the docker image used for the client. If you want to use the default docker image, just use the client name --latest Use the latest version of clients. This sets the "latest" tag on the client's docker images. Latest version might not work. --checkpoint-sync-url string Initial state endpoint (trusted synced consensus endpoint) for the consensus client to sync from a finalized checkpoint. Provide faster sync process for the consensus client and protect it from long-range attacks affored by Weak Subjetivity. Each network has a default checkpoint sync url. - --fee-recipient string Suggested fee recipient. Is a 20-byte Ethereum address which the execution layer might choose to set as the coinbase and the recipient of other fees or rewards. There is no guarantee that an execution node will use the suggested fee recipient to collect fees, it may use any address it chooses. It is assumed that an honest execution node will use the suggested fee recipient, but users should note this trust assumption + --fee-recipient string Suggested fee recipient. Is a 20-byte Ethereum address which the execution layer might choose to set as the coinbase and the recipient of other fees or rewards. There is no guarantee that an execution node will use the suggested fee recipient to collect fees, it may use any address it chooses. It is assumed that an honest execution node will use the suggested fee recipient, but users should note this trust assumption. + Note: When setting up a Lido node, fee recipient address will be automatically set by the system. --no-mev-boost Not use mev-boost if supported -m, --mev-boost-image string Custom docker image to use for Mev Boost. Example: 'sedge generate full-node --mev-boost-image flashbots/mev-boost:latest-portable' - --relay-urls strings List of comma separated relay URLs used to connect to mev relay. Example: 'sedge generate full-node --relay-url=https://0xac6e77dfe25ecd6110b8e780608cce0dab71fdd5ebea22a16c0205200f2f8e2e3ad3b71d3499c54ad14d6c21b41a37ae@boost-relay.flashbots.net,https://0xa1559ace749633b997cb3fdacffb890aeebdb0f5a3b6aaa7eeeaf1a38af0a8fe88b9e4b1f61f236d2e64d95733327a62@relay.ultrasound.money + --relay-urls strings List of comma separated relay URLs used to connect to mev relay. Example: 'sedge generate full-node --relay-urls=https://0xac6e77dfe25ecd6110b8e780608cce0dab71fdd5ebea22a16c0205200f2f8e2e3ad3b71d3499c54ad14d6c21b41a37ae@boost-relay.flashbots.net,https://0xa1559ace749633b997cb3fdacffb890aeebdb0f5a3b6aaa7eeeaf1a38af0a8fe88b9e4b1f61f236d2e64d95733327a62@relay.ultrasound.money' + Note: When setting up a Lido node, the provided relay URLs will be automatically set by the system. --no-validator Exclude the validator from the full node setup. Designed for execution and consensus nodes setup without a validator node. Exclude also the validator from other flags. If set, mev-boost will not be used. --jwt-secret-path string Path to the JWT secret file --graffiti string Graffiti to be used by the validator @@ -100,9 +113,10 @@ Flags: Global Flags: --container-tag string Container tag to use. If defined, sedge will add to each container and the network, a suffix with the tag. e.g. sedge-validator-client -> sedge-validator-client-. + --lido generate Lido CSM node --log-level string Set Log Level, e.g panic, fatal, error, warn, warning, info, debug, trace (default "info") - --logging string Docker logging driver used by all the services. Set 'none' to use the default docker logging driver. Possible values: [none json] (default "json") - -n, --network string Target network. e.g. mainnet, sepolia, holesky, gnosis, chiado, etc. (default "mainnet") + --logging string Docker logging driver used by all the services. Set 'none' to use the default docker logging driver. Possible values: [json none] (default "json") + -n, --network string Target network. e.g. mainnet,sepolia, holesky, gnosis, chiado, etc. (default "mainnet") -p, --path string generation path for sedge data. Default is sedge-data (default "/path/to/sedge/sedge-data") ``` @@ -128,7 +142,8 @@ Flags: --execution-api-url string Execution API endpoint for the consensus client. Example: 'sedge generate consensus -r --execution-api-url=https://api.url.endpoint' --execution-auth-url string Execution AUTH endpoint for the consensus client. Example: 'sedge generate consensus -r --execution-auth-url=https://auth.url.endpoint' --checkpoint-sync-url string Initial state endpoint (trusted synced consensus endpoint) for the consensus client to sync from a finalized checkpoint. Provide faster sync process for the consensus client and protect it from long-range attacks affored by Weak Subjetivity. Each network has a default checkpoint sync url. - --fee-recipient string Suggested fee recipient. Is a 20-byte Ethereum address which the execution layer might choose to set as the coinbase and the recipient of other fees or rewards. There is no guarantee that an execution node will use the suggested fee recipient to collect fees, it may use any address it chooses. It is assumed that an honest execution node will use the suggested fee recipient, but users should note this trust assumption + --fee-recipient string Suggested fee recipient. Is a 20-byte Ethereum address which the execution layer might choose to set as the coinbase and the recipient of other fees or rewards. There is no guarantee that an execution node will use the suggested fee recipient to collect fees, it may use any address it chooses. It is assumed that an honest execution node will use the suggested fee recipient, but users should note this trust assumption. + Note: When setting up a Lido node, fee recipient address will be automatically set by the system. --jwt-secret-path string Path to the JWT secret file --mev-boost-url string If you are running a mev boost node, and you want to connect to it, you need to set mev-boost-url, if not set, node will not load any mev boost related config. --map-all Map all clients ports to host. Use with care. Useful to allow remote access to the clients @@ -142,9 +157,10 @@ Flags: Global Flags: --container-tag string Container tag to use. If defined, sedge will add to each container and the network, a suffix with the tag. e.g. sedge-validator-client -> sedge-validator-client-. + --lido generate Lido CSM node --log-level string Set Log Level, e.g panic, fatal, error, warn, warning, info, debug, trace (default "info") --logging string Docker logging driver used by all the services. Set 'none' to use the default docker logging driver. Possible values: [none json] (default "json") - -n, --network string Target network. e.g. mainnet, sepolia, etc. (default "mainnet") + -n, --network string Target network. e.g. mainnet,sepolia, holesky, gnosis, chiado, etc. (default "mainnet") -p, --path string generation path for sedge data. Default is sedge-data (default "/path/to/sedge/sedge-data") ``` @@ -162,7 +178,7 @@ Usage: sedge generate execution [flags] [args] Flags: - --latest Use the latest version of clients. This sets the "latest" tag on the client's docker images. Latest version might not work. + --latest Use the latest version of clients. This sets the "latest" tag on the client's docker images. Latest version might not work. --jwt-secret-path string Path to the JWT secret file --map-all Map all clients ports to host. Use with care. Useful to allow remote access to the clients --custom-chainSpec string File path or url to use as custom network chainSpec for execution client. @@ -172,9 +188,10 @@ Flags: Global Flags: --container-tag string Container tag to use. If defined, sedge will add to each container and the network, a suffix with the tag. e.g. sedge-validator-client -> sedge-validator-client-. + --lido generate Lido CSM node --log-level string Set Log Level, e.g panic, fatal, error, warn, warning, info, debug, trace (default "info") --logging string Docker logging driver used by all the services. Set 'none' to use the default docker logging driver. Possible values: [none json] (default "json") - -n, --network string Target network. e.g. mainnet, sepolia, holesky, gnosis, chiado, etc. (default "mainnet") + -n, --network string Target network. e.g. mainnet,sepolia, holesky, gnosis, chiado, etc. (default "mainnet") -p, --path string generation path for sedge data. Default is sedge-data (default "/path/to/sedge/sedge-data") ``` @@ -187,6 +204,7 @@ You should use `--fee-recipient` flag to set the fee recipient address. If you d ::: ``` +$ sedge generate validator -h Generate a docker-compose and an environment file with a validator node configuration Valid args: name of execution clients according to network @@ -202,7 +220,8 @@ Usage: Flags: --latest Use the latest version of clients. This sets the "latest" tag on the client's docker images. Latest version might not work. --consensus-url string Consensus endpoint for the validator client to connect to. Example: 'sedge generate validator --consensus-url http://localhost:4000' - --fee-recipient string Suggested fee recipient. Is a 20-byte Ethereum address which the execution layer might choose to set as the coinbase and the recipient of other fees or rewards. There is no guarantee that an execution node will use the suggested fee recipient to collect fees, it may use any address it chooses. It is assumed that an honest execution node will use the suggested fee recipient, but users should note this trust assumption + --fee-recipient string Suggested fee recipient. Is a 20-byte Ethereum address which the execution layer might choose to set as the coinbase and the recipient of other fees or rewards. There is no guarantee that an execution node will use the suggested fee recipient to collect fees, it may use any address it chooses. It is assumed that an honest execution node will use the suggested fee recipient, but users should note this trust assumption. + Note: When setting up a Lido node, fee recipient address will be automatically set by the system. --graffiti string Graffiti to be used by the validator --mev-boost Use mev-boost while turning on validator node --custom-config string File path or url to use as custom network config file for consensus client. @@ -214,9 +233,10 @@ Flags: Global Flags: --container-tag string Container tag to use. If defined, sedge will add to each container and the network, a suffix with the tag. e.g. sedge-validator-client -> sedge-validator-client-. + --lido generate Lido CSM node --log-level string Set Log Level, e.g panic, fatal, error, warn, warning, info, debug, trace (default "info") --logging string Docker logging driver used by all the services. Set 'none' to use the default docker logging driver. Possible values: [none json] (default "json") - -n, --network string Target network. e.g. mainnet, sepolia, holesky, gnosis, chiado, etc. (default "mainnet") + -n, --network string Target network. e.g. mainnet,sepolia, holesky, gnosis, chiado, etc. (default "mainnet") -p, --path string generation path for sedge data. Default is sedge-data (default "/path/to/sedge/sedge-data") ``` @@ -230,14 +250,16 @@ Usage: sedge generate mev-boost [flags] Flags: - --relay-urls strings List of comma separated relay URLs used to connect to mev relay. Example: 'sedge generate mev-boost --relay-url=https://0xac6e77dfe25ecd6110b8e780608cce0dab71fdd5ebea22a16c0205200f2f8e2e3ad3b71d3499c54ad14d6c21b41a37ae@boost-relay.flashbots.net,https://0xa1559ace749633b997cb3fdacffb890aeebdb0f5a3b6aaa7eeeaf1a38af0a8fe88b9e4b1f61f236d2e64d95733327a62@relay.ultrasound.money + --relay-urls strings List of comma separated relay URLs used to connect to mev relay. Example: 'sedge generate full-node --relay-urls=https://0xac6e77dfe25ecd6110b8e780608cce0dab71fdd5ebea22a16c0205200f2f8e2e3ad3b71d3499c54ad14d6c21b41a37ae@boost-relay.flashbots.net,https://0xa1559ace749633b997cb3fdacffb890aeebdb0f5a3b6aaa7eeeaf1a38af0a8fe88b9e4b1f61f236d2e64d95733327a62@relay.ultrasound.money' + Note: When setting up a Lido node, the provided relay URLs will be automatically set by the system. -m, --mev-boost-image string Custom docker image to use for Mev Boost. Example: 'sedge generate mev-boost --mev-boost-image flashbots/mev-boost:latest-portable' + -n, --network string Target network. e.g. mainnet, sepolia etc. (default "mainnet") -h, --help help for mev-boost Global Flags: --container-tag string Container tag to use. If defined, sedge will add to each container and the network, a suffix with the tag. e.g. sedge-validator-client -> sedge-validator-client-. + --lido generate Lido CSM node --log-level string Set Log Level, e.g panic, fatal, error, warn, warning, info, debug, trace (default "info") --logging string Docker logging driver used by all the services. Set 'none' to use the default docker logging driver. Possible values: [none json] (default "json") - -n, --network string Target network. e.g. mainnet, sepolia, etc. (default "mainnet") -p, --path string generation path for sedge data. Default is sedge-data (default "/path/to/sedge/sedge-data") ``` \ No newline at end of file diff --git a/docs/docs/commands/importKey.mdx b/docs/docs/commands/importKey.mdx index 87dc3671..c6fb4adf 100644 --- a/docs/docs/commands/importKey.mdx +++ b/docs/docs/commands/importKey.mdx @@ -14,7 +14,7 @@ initialized sedge setup containing a validator client. To know more about the command options, run `sedge import-key --help`: ``` -$ sedge import-key --help +$ sedge import-key --help Import validator client keys, use the 'from' flag to specify the keys location, and make sure that follows the EIP-2335: BLS12-381 Keystore standard. This command @@ -36,18 +36,19 @@ Usage: sedge import-key [flags] [validator] Flags: + --container-tag string Container tag to use. If defined, sedge will add to each container and the network, a suffix with the tag. e.g. sedge-validator-client -> sedge-validator-client-. --custom-config string file path or url to use as custom network config. --custom-deploy-block string custom network deploy block. --custom-genesis string file path or url to use as custom network genesis. --from string path to the validator keys, must follow the EIP-2335: BLS12-381 Keystore standard (default "[WORK_DIR]/sedge-data/keystore") -h, --help help for import-key - -n, --network string network + -n, --network string network (default "mainnet") -p, --path string path to the generation directory (default "[WORK_DIR]/sedge-data") --start-validator starts the validator client after import, regardless of the state the validator was in before --stop-validator stops the validator client after import, regardless of the state the validator was in before Global Flags: - --logLevel string Set Log Level, e.g panic, fatal, error, warn, warning, info, debug, trace (default "info") + --log-level string Set Log Level, e.g panic, fatal, error, warn, warning, info, debug, trace (default "info") ``` ## Execution examples diff --git a/docs/docs/commands/keys.mdx b/docs/docs/commands/keys.mdx index 82913221..848b1386 100644 --- a/docs/docs/commands/keys.mdx +++ b/docs/docs/commands/keys.mdx @@ -17,26 +17,26 @@ Users acknowledge that generating the keystore for any network is an unaudited f ``` $ sedge keys -h -Initializing configuration Generate keystore folder using the eth2.0-deposit-cli tool Usage: sedge keys [flags] Flags: - --eth1-withdrawal-address string If this field is set and valid, the given Eth1 address will be used to create the withdrawal credentials. Otherwise, it will generate withdrawal credentials with the mnemonic-derived withdrawal public key in EIP-2334 format. - --existing int Number of validators generated with the provided mnemonic. Will be ignored if "--mnemonic-path" its not set. This number will be used as the initial index for the generated keystores. (default -1) - -h, --help help for keys - -i, --install Install dependencies if not installed without asking - --mnemonic-path string Path to file with a existing mnemonic to use. - -n, --network string Target network. e.g. mainnet, sepolia, holesky, gnosis, chiado etc. (default "mainnet") - --num-validators int Number of validators to generate. This number will be used in addition to the existing flag as the end index for the generated keystores. (default -1) - --passphrase-path string Path to file with a keystores passphrase to use. - -p, --path string Absolute path to keystore folder. e.g. /home/user/keystore (default "./docker-compose-scripts") - --random-passphrase Usa a randomly generated passphrase to encrypt keystores. + --eth-withdrawal-address string If this field is set and valid, the given Eth address will be used to create the withdrawal credentials. Otherwise, it will generate withdrawal credentials with the mnemonic-derived withdrawal public key in EIP-2334 format. + --existing int Number of validators generated with the provided mnemonic. Will be ignored if "--mnemonic-path" its not set. This number will be used as the initial index for the generated keystores. (default -1) + -h, --help help for keys + -i, --install Install dependencies if not installed without asking + --lido Enable Lido CSM compatible keys. Similar to using --eth-withdrawal-address with the Lido Withdrawal Vault address. + --mnemonic-path string Path to file with a existing mnemonic to use. + -n, --network string Target network. e.g. mainnet,sepolia, holesky, gnosis, chiado etc. (default "mainnet") + --num-validators int Number of validators to generate. This number will be used in addition to the existing flag as the end index for the generated keystores. (default -1) + --passphrase-path string Path to file with a keystores passphrase to use. + -p, --path string Absolute path to keystore folder. e.g. /home/user/keystore (default "/path/to/sedge-data") + --random-passphrase Usa a randomly generated passphrase to encrypt keystores. Global Flags: - --logLevel string Set Log Level (default "info") + --log-level string Set Log Level, e.g panic, fatal, error, warn, warning, info, debug, trace (default "info") ``` ## Execution Example diff --git a/docs/docs/commands/logs.mdx b/docs/docs/commands/logs.mdx index 967668d3..66cb2536 100644 --- a/docs/docs/commands/logs.mdx +++ b/docs/docs/commands/logs.mdx @@ -11,7 +11,6 @@ Running `sedge logs` will get running container logs using docker compose CLI. ``` $ sedge logs -h -Initializing configuration Get running container logs using docker-compose CLI. If no services are provided, the logs of all running services will be displayed. By default will run 'docker compose -f