diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 000000000..ab9c306fc --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,45 @@ +// For format details, see https://aka.ms/devcontainer.json. For config options, see the +// README at: https://github.com/devcontainers/templates/tree/main/src/go +{ + "name": "Go", + // Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile + "image": "mcr.microsoft.com/devcontainers/go:1-1.22-bookworm", + "features": { + "ghcr.io/devcontainers/features/docker-in-docker:2": {}, + "ghcr.io/devcontainers-contrib/features/curl-apt-get:1": {} + }, + "customizations": { + "vscode": { + "extensions": [ + "GitHub.copilot", + "streetsidesoftware.code-spell-checker", + "ms-azuretools.vscode-docker", + "dbaeumer.vscode-eslint", + "donjayamanne.githistory", + "GitHub.copilot-chat", + "GitHub.vscode-pull-request-github", + "golang.go", + "yzhang.markdown-all-in-one", + "DavidAnson.vscode-markdownlint", + "unifiedjs.vscode-mdx", + "redhat.vscode-yaml", + "eamodio.gitlens" + ] + } + } + + // Features to add to the dev container. More info: https://containers.dev/features. + // "features": {}, + + // Use 'forwardPorts' to make a list of ports inside the container available locally. + // "forwardPorts": [], + + // Use 'postCreateCommand' to run commands after the container is created. + // "postCreateCommand": "go version", + + // Configure tool-specific properties. + // "customizations": {}, + + // Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root. + // "remoteUser": "root" +} diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index a34327c3a..1b4aaa202 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -13,9 +13,9 @@ jobs: matrix: include: - os: ubuntu-latest - go: '1.19' + go: '1.21' - os: macos-latest - go: '1.19' + go: '1.21' - os: windows-latest go: '1.21' runs-on: ${{ matrix.os }} @@ -27,10 +27,10 @@ jobs: git config --global core.eol lf - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Setup Go - uses: actions/setup-go@v3 + uses: actions/setup-go@v5 with: go-version: ${{ matrix.go }} diff --git a/.github/workflows/check-version.yml b/.github/workflows/check-version.yml index f87ae37fd..9f128e0d1 100644 --- a/.github/workflows/check-version.yml +++ b/.github/workflows/check-version.yml @@ -21,11 +21,11 @@ jobs: PAT: ${{ secrets.REPOSITORY_DISPATCH_TOKEN }} - name: Create Pull Request - uses: peter-evans/create-pull-request@v4 + uses: peter-evans/create-pull-request@v6 with: token: ${{ secrets.REPOSITORY_DISPATCH_TOKEN }} commit-message: Update image versions to latest version. title: "[Update] Update image versions" - reviewers: falcoxyz, AntiD2ta, cbermudez97 + reviewers: AntiD2ta, adriantpaez, stdevMac, cbermudez97 branch: feature/update-container-images draft: false diff --git a/.github/workflows/docs-test.yml b/.github/workflows/docs-test.yml index b1786320c..23cc4c695 100644 --- a/.github/workflows/docs-test.yml +++ b/.github/workflows/docs-test.yml @@ -11,8 +11,8 @@ jobs: name: Test deployment runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 - - uses: actions/setup-node@v3 + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 with: node-version: 18 cache: npm diff --git a/.github/workflows/e2e_tests.yml b/.github/workflows/e2e_tests.yml new file mode 100644 index 000000000..0517c51f8 --- /dev/null +++ b/.github/workflows/e2e_tests.yml @@ -0,0 +1,34 @@ +name: sedge e2e tests +on: + push: + branches: [main, develop] + pull_request: + branches: [main, develop] + workflow_dispatch: + +jobs: + unit_tests: + name: Run e2e tests + strategy: + matrix: + include: + - os: ubuntu-latest + go: '1.21' + - os: windows-latest + go: '1.21' + runs-on: ${{ matrix.os }} + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Go + uses: actions/setup-go@v5 + with: + go-version: ${{ matrix.go }} + + - name: Install deps + run: make install-deps + + - name: Run e2e tests + run: make e2e-test diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 9e19884d6..53e439e22 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -20,21 +20,21 @@ jobs: VERSION: ${{ github.event.inputs.tag }} steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - - uses: actions/setup-go@v3 + - uses: actions/setup-go@v5 with: - go-version: "1.19.0" + go-version: "1.21.0" - run: chmod +x ./scripts/build-go-darwin-binaries.sh && ./scripts/build-go-darwin-binaries.sh - - uses: actions/upload-artifact@master + - uses: actions/upload-artifact@v4 name: Uploading sedge darwin amd64 package with: name: sedge-${{env.VERSION}}-darwin-amd64 path: build/sedge-${{env.VERSION}}-darwin-amd64 - - uses: actions/upload-artifact@master + - uses: actions/upload-artifact@v4 name: Uploading sedge darwin arm64 package with: name: sedge-${{env.VERSION}}-darwin-arm64 @@ -48,15 +48,15 @@ jobs: needs: sedge-darwin steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - - uses: actions/setup-go@v3 + - uses: actions/setup-go@v5 with: go-version: "1.21.0" - run: scripts\build-go-windows-binaries.ps1 - - uses: actions/upload-artifact@master + - uses: actions/upload-artifact@v4 name: Uploading sedge windows amd64 package with: name: sedge-${{env.VERSION}}-windows-amd64.exe @@ -70,28 +70,28 @@ jobs: needs: sedge-windows steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - - uses: actions/setup-go@v3 + - uses: actions/setup-go@v5 with: - go-version: "1.19.0" + go-version: "1.21.0" - name: Set up QEMU - uses: docker/setup-qemu-action@v2 + uses: docker/setup-qemu-action@v3 - name: Set up Docker Buildx id: buildx - uses: docker/setup-buildx-action@v2 + uses: docker/setup-buildx-action@v3 - run: chmod +x ./scripts/build-go-linux-binaries.sh && ./scripts/build-go-linux-binaries.sh - - uses: actions/upload-artifact@master + - uses: actions/upload-artifact@v4 name: Uploading sedge linux amd64 package with: name: sedge-${{env.VERSION}}-linux-amd64 path: build/sedge-${{env.VERSION}}-linux-amd64 - - uses: actions/upload-artifact@master + - uses: actions/upload-artifact@v4 name: Uploading sedge linux arm64 package with: name: sedge-${{env.VERSION}}-linux-arm64 @@ -105,12 +105,12 @@ jobs: needs: sedge-linux steps: - name: Download packages - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: path: /tmp/binaries - name: Checkout repository - uses: actions/checkout@master + uses: actions/checkout@v4 with: repository: NethermindEth/homebrew-sedge path: homebrew-sedge @@ -121,12 +121,12 @@ jobs: bash /home/runner/work/sedge/sedge/homebrew-sedge/scripts/update-homebrew.sh - name: Create Pull Request - uses: peter-evans/create-pull-request@v4 + uses: peter-evans/create-pull-request@v6 with: token: ${{ secrets.REPOSITORY_DISPATCH_TOKEN }} commit-message: Update Homebrew to latest release title: "[Release] Update Homebrew" - reviewers: falcoxyz, AntiD2ta, cbermudez97, stdevMac + reviewers: AntiD2ta, cbermudez97, stdevMac, adriantpaez draft: false path: homebrew-sedge add-paths: | @@ -140,10 +140,10 @@ jobs: needs: update-homebrew steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Download packages - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: path: /tmp/binaries - name: Generate Changelog @@ -184,12 +184,12 @@ jobs: run: | sudo apt update && sudo apt install golang-go debhelper libdebhelper-perl build-essential devscripts rsync -y - name: Checking out Sedge repository - uses: actions/checkout@master + uses: actions/checkout@v4 with: path: sedge - - uses: actions/setup-go@v3 + - uses: actions/setup-go@v5 with: - go-version: "1.19.0" + go-version: "1.21.0" - name: Run publish PPA script env: GOPATH: /home/runner/go @@ -200,7 +200,7 @@ jobs: - name: Sleep for 1 hour run: sleep 3600s shell: bash - - uses: actions/setup-python@v4 + - uses: actions/setup-python@v5 - run: pip install launchpadlib --upgrade - name: Run copy binaries PPA script env: diff --git a/.github/workflows/unit_tests.yml b/.github/workflows/unit_tests.yml index 3650eccef..83ecf32a7 100644 --- a/.github/workflows/unit_tests.yml +++ b/.github/workflows/unit_tests.yml @@ -13,17 +13,17 @@ jobs: matrix: include: - os: ubuntu-latest - go: '1.19' + go: '1.21' - os: windows-latest go: '1.21' runs-on: ${{ matrix.os }} steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Setup Go - uses: actions/setup-go@v3 + uses: actions/setup-go@v5 with: go-version: ${{ matrix.go }} @@ -39,7 +39,7 @@ jobs: run: make generate && go test ./... - name: Upload coverage to Codecov - uses: codecov/codecov-action@v2 + uses: codecov/codecov-action@v4 if: matrix.os == 'ubuntu-latest' with: fail_ci_if_error: true diff --git a/CHANGELOG.md b/CHANGELOG.md index 3433c9be9..2864f2a72 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,50 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Fixed +- Teku and Lighthouse import keys container error on Windows. + +## [v1.4.0] - 2024-07-10 + +### 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.2] - 2024-03-08 + +### Changed + +- Update client images to Dencun-ready versions. + +## [v1.3.1] - 2024-02-14 + +### Fixed + +- Remove the Lodestar `--eth1.providerUrls` flag +- Replace the Lighthouse `--eth1-endpoints` flag with `--eth1`. + +### Changed + +- Update client images. + ## [v1.3.0] - 2023-12-11 ### Added diff --git a/Makefile b/Makefile index 516e32062..358850d72 100644 --- a/Makefile +++ b/Makefile @@ -30,6 +30,9 @@ test: generate ## run tests @mkdir -p coverage @go test -coverprofile=coverage/coverage.out -covermode=count ./... +e2e-test: generate ## Run e2e tests + @go test -timeout 20m -count=1 ./e2e/... + codecov-test: generate ## unit tests with coverage using the courtney tool @mkdir -p coverage @courtney/courtney -v -o coverage/coverage.out ./... @@ -42,7 +45,7 @@ install-mockgen: ## install mockgen go install github.com/golang/mock/mockgen@v1.6.0 install-courtney: ## Install courtney for code coverage - @git clone https://github.com/stdevMac/courtney + @git clone https://github.com/dave/courtney @(cd courtney && go get ./... && go build courtney.go) @go get ./... diff --git a/README.md b/README.md index 062054293..6585dd5a3 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,6 @@ Sedge is a one-click node setup tool for PoS network/chain validators and nodes - [Supported networks and clients](#supported-networks-and-clients) - [Mainnet](#mainnet) - [Sepolia](#sepolia) - - [Goerli](#goerli) - [Holesky](#holesky) - [Gnosis](#gnosis) - [Chiado (Gnosis testnet)](#chiado-gnosis-testnet) @@ -128,6 +127,15 @@ While Sedge assists in installing the validator, it is not designed to register Users acknowledge that no warranty is being made of a successful installation. Sedge is a tool and it ultimately depends on you to use it correctly and follow all the best practice guidance, as found in this README and documentation. +## Lido integration + +Sedge is integrated with [Lido CSM](https://operatorportal.lido.fi/modules/community-staking-module), with +permissionless entry, allowing any node operator — and especially community stakers, from solo stakers, to groups of +friends, to amateur operators — to operate validators by providing an ETH-based bond (security collateral). + +Sedge supports the Lido CSM, allowing users to generate validator keys and set up their full nodes with ease. You can +read more about it in [our documentation](https://docs.sedge.nethermind.io/docs/quickstart/staking-with-lido)! + ## Supported networks and clients ### Mainnet @@ -148,15 +156,6 @@ Users acknowledge that no warranty is being made of a successful installation. S | Erigon | Prysm | Prysm | | Besu | Teku | Teku | -### Goerli - -| Execution | Consensus | Validator | -| ---------- | ---------- | ---------- | -| Geth | Lighthouse | Lighthouse | -| Nethermind | Lodestar | Lodestar | -| Erigon | Prysm | Prysm | -| Besu | Teku | Teku | - ### Holesky | Execution | Consensus | Validator | @@ -184,12 +183,12 @@ Users acknowledge that no warranty is being made of a successful installation. S ### CL clients with Mev-Boost -| Client | Mev-Boost | Networks | -| ---------- | --------- |--------------------------| -| Lighthouse | yes | Mainnet, Goerli, Sepolia | -| Lodestar | yes | Mainnet, Goerli, Sepolia | -| Prysm | yes | Mainnet, Goerli, Sepolia | -| Teku | yes | Mainnet, Goerli, Sepolia | +| Client | Mev-Boost | Networks | +| ---------- | --------- |---------------------------| +| Lighthouse | yes | Mainnet, Sepolia, Holesky | +| Lodestar | yes | Mainnet, Sepolia, Holesky | +| Prysm | yes | Mainnet, Sepolia, Holesky | +| Teku | yes | Mainnet, Sepolia, Holesky | ## Supported Linux flavours for dependency installation @@ -256,6 +255,7 @@ The following roadmap covers the main features and ideas we want to implement bu ### Version 1.X (Current) - [x] Support Erigon on Gnosis +- [x] Support for Lido CSM - [ ] Include monitoring tool for alerting, tracking validator balance, and tracking sync progress and status of nodes - [ ] More tests!!! - [ ] Support for Nimbus client diff --git a/cli/actions/importKeys.go b/cli/actions/importKeys.go index d12cfb290..15a915d91 100644 --- a/cli/actions/importKeys.go +++ b/cli/actions/importKeys.go @@ -229,7 +229,7 @@ func setupLodestarValidatorImport(dockerClient client.APIClient, serviceManager // CMD var preset string switch options.Network { - case "mainnet", "goerli", "sepolia", "holesky": + case "mainnet", "sepolia", "holesky": preset = "mainnet" case "gnosis", "chiado": preset = "gnosis" diff --git a/cli/actions/importKeys_test.go b/cli/actions/importKeys_test.go index 30ef18c5e..daa096c4d 100644 --- a/cli/actions/importKeys_test.go +++ b/cli/actions/importKeys_test.go @@ -174,7 +174,7 @@ func TestImportKeys_CustomOptions(t *testing.T) { customImage bool }{} for _, validatorClient := range []string{"prysm", "lodestar"} { - for _, network := range []string{"sepolia", "goerli", "mainnet"} { + for _, network := range []string{"sepolia", "mainnet"} { tests = append(tests, struct { client string network string @@ -183,7 +183,7 @@ func TestImportKeys_CustomOptions(t *testing.T) { } } for _, validatorClient := range []string{"lighthouse", "teku"} { - for _, network := range []string{"sepolia", "goerli", "mainnet"} { + for _, network := range []string{"sepolia", "mainnet"} { tests = append(tests, struct { client string network string 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 d331e071c..51df73989 100644 --- a/cli/actions/testdata/getContainers_tests/case_consensusNF/docker-compose.yml +++ b/cli/actions/testdata/getContainers_tests/case_consensusNF/docker-compose.yml @@ -1,4 +1,3 @@ -version: "3.9" services: execution: stop_grace_period: 30s @@ -86,7 +85,7 @@ services: - --target-peers=${CC_PEER_COUNT} - --execution-endpoints=${EC_AUTH_URL} - --execution-jwt=/tmp/jwt/jwtsecret - - --eth1-endpoints=${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 67a12c624..99e618c7c 100644 --- a/cli/actions/testdata/getContainers_tests/case_consensusOnly/docker-compose.yml +++ b/cli/actions/testdata/getContainers_tests/case_consensusOnly/docker-compose.yml @@ -1,4 +1,3 @@ -version: "3.9" services: consensus: stop_grace_period: 30s @@ -33,7 +32,7 @@ services: - --target-peers=${CC_PEER_COUNT} - --execution-endpoints=${EC_AUTH_URL} - --execution-jwt=/tmp/jwt/jwtsecret - - --eth1-endpoints=${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 7ad96dadc..6f699fe25 100644 --- a/cli/actions/testdata/getContainers_tests/case_executionNF/docker-compose.yml +++ b/cli/actions/testdata/getContainers_tests/case_executionNF/docker-compose.yml @@ -1,4 +1,3 @@ -version: "3.9" services: execution: stop_grace_period: 30s @@ -86,7 +85,7 @@ services: - --target-peers=${CC_PEER_COUNT} - --execution-endpoints=${EC_AUTH_URL} - --execution-jwt=/tmp/jwt/jwtsecret - - --eth1-endpoints=${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_executionOnly/docker-compose.yml b/cli/actions/testdata/getContainers_tests/case_executionOnly/docker-compose.yml index 44881f3d9..21bad610b 100644 --- a/cli/actions/testdata/getContainers_tests/case_executionOnly/docker-compose.yml +++ b/cli/actions/testdata/getContainers_tests/case_executionOnly/docker-compose.yml @@ -1,4 +1,3 @@ -version: "3.9" services: execution: stop_grace_period: 30s 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 b5449b40e..9d9c127bc 100644 --- a/cli/actions/testdata/getContainers_tests/case_fullNode/docker-compose.yml +++ b/cli/actions/testdata/getContainers_tests/case_fullNode/docker-compose.yml @@ -1,4 +1,3 @@ -version: "3.9" services: execution: stop_grace_period: 30s @@ -86,7 +85,7 @@ services: - --target-peers=${CC_PEER_COUNT} - --execution-endpoints=${EC_AUTH_URL} - --execution-jwt=/tmp/jwt/jwtsecret - - --eth1-endpoints=${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 6a7703e20..8632b4b54 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-endpoints=${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 c3862f9a3..a33b9a9ba 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-endpoints=${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 6a3522fed..98debf6ef 100644 --- a/cli/actions/testdata/getContainers_tests/case_noMev/docker-compose.yml +++ b/cli/actions/testdata/getContainers_tests/case_noMev/docker-compose.yml @@ -1,4 +1,3 @@ -version: "3.9" services: execution: stop_grace_period: 30s @@ -72,7 +71,7 @@ services: - --target-peers=${CC_PEER_COUNT} - --execution-endpoints=${EC_AUTH_URL} - --execution-jwt=/tmp/jwt/jwtsecret - - --eth1-endpoints=${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 8a9fc5c90..f06ba0ab1 100644 --- a/cli/actions/testdata/getContainers_tests/case_noValidator/docker-compose.yml +++ b/cli/actions/testdata/getContainers_tests/case_noValidator/docker-compose.yml @@ -1,4 +1,3 @@ -version: "3.9" services: execution: stop_grace_period: 30s @@ -86,7 +85,7 @@ services: - --target-peers=${CC_PEER_COUNT} - --execution-endpoints=${EC_AUTH_URL} - --execution-jwt=/tmp/jwt/jwtsecret - - --eth1-endpoints=${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 2bab1356c..72761b190 100644 --- a/cli/actions/testdata/getContainers_tests/case_validatorNF/docker-compose.yml +++ b/cli/actions/testdata/getContainers_tests/case_validatorNF/docker-compose.yml @@ -1,4 +1,3 @@ -version: "3.9" services: execution: stop_grace_period: 30s @@ -86,7 +85,7 @@ services: - --target-peers=${CC_PEER_COUNT} - --execution-endpoints=${EC_AUTH_URL} - --execution-jwt=/tmp/jwt/jwtsecret - - --eth1-endpoints=${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 1903ac560..e7dd21d14 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" @@ -40,7 +41,6 @@ import ( const ( NetworkMainnet = "mainnet" - NetworkGoerli = "goerli" NetworkSepolia = "sepolia" NetworkGnosis = "gnosis" NetworkChiado = "chiado" @@ -80,6 +80,7 @@ type CliCmdOptions struct { keystorePassphrasePath string keystorePassphrase string withdrawalAddress string + nodeSetup string numberOfValidators int64 existingValidators int64 installDependencies bool @@ -97,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 @@ -104,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, @@ -615,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, NetworkGoerli, NetworkSepolia, NetworkGnosis, NetworkChiado, NetworkHolesky} + opts := sedgeOpts.CreateSedgeOptions(o.nodeSetup) + options := opts.SupportedNetworks() + index, err := p.Select("Select network", "", options) if err != nil { return err @@ -793,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 } @@ -848,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) @@ -871,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 } @@ -930,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 94a11f47b..5c6f68385 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, NetworkGoerli, 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, NetworkGoerli, 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, NetworkGoerli, NetworkSepolia, NetworkGnosis, NetworkChiado, NetworkHolesky}).Return(5, 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, NetworkGoerli, 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, NetworkGoerli, NetworkSepolia, NetworkGnosis, NetworkChiado, NetworkHolesky}).Return(5, 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), @@ -323,7 +333,7 @@ func TestCli(t *testing.T) { Type: "consensus", Image: configs.ClientImages.Consensus.Lodestar.String(), }, - Network: NetworkGoerli, + Network: NetworkMainnet, CheckpointSyncUrl: "http://checkpoint.sync", FeeRecipient: "0x2d07a21ebadde0c13e8b91022a7e5732eb6bf5d5", MapAllPorts: true, @@ -335,7 +345,8 @@ func TestCli(t *testing.T) { } gomock.InOrder( - prompter.EXPECT().Select("Select network", "", []string{NetworkMainnet, NetworkGoerli, NetworkSepolia, NetworkGnosis, NetworkChiado, NetworkHolesky}).Return(1, 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), @@ -372,17 +383,20 @@ func TestCli(t *testing.T) { MapAllPorts: false, 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 network", "", []string{NetworkMainnet, NetworkGoerli, NetworkSepolia, NetworkGnosis, NetworkChiado, NetworkHolesky}).Return(5, 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), prompter.EXPECT().Select("Select consensus client", "", ETHClients["consensus"]).Return(3, nil), prompter.EXPECT().InputURL("Checkpoint sync URL", configs.NetworksConfigs()[genData.Network].CheckpointSyncURL, false).Return("https://checkpoint-sync.holesky.ethpandaops.io/", 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), @@ -419,7 +433,8 @@ func TestCli(t *testing.T) { } gomock.InOrder( - prompter.EXPECT().Select("Select network", "", []string{NetworkMainnet, NetworkGoerli, 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), @@ -458,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 3b96e1a20..4cc90f82c 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 ( @@ -100,6 +102,7 @@ You can generate: - Consensus Node - Validator Node - Mev-Boost Instance +- Lido CSM node `, Args: cobra.NoArgs, } @@ -110,8 +113,9 @@ 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, goerli, sepolia, holesky, gnosis, chiado, etc.") + 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())) cmd.PersistentFlags().StringVar(&containerTag, "container-tag", "", "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-.") return cmd @@ -257,6 +261,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) @@ -477,3 +488,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 ce2b6c767..001787964 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 } @@ -1102,7 +1108,7 @@ func TestGenerateCmd(t *testing.T) { consensusApiUrl: "http://localhost:4000", }, globalFlags{ - network: "goerli", + network: "holesky", }, nil, }, @@ -1117,7 +1123,7 @@ func TestGenerateCmd(t *testing.T) { consensusApiUrl: "localhost/4000", }, globalFlags{ - network: "goerli", + network: "gnosis", }, fmt.Errorf(configs.InvalidUrlFlagError, "consensus api", "localhost/4000"), }, @@ -1147,7 +1153,7 @@ func TestGenerateCmd(t *testing.T) { consensusApiUrl: "localhost:4000", }, globalFlags{ - network: "goerli", + network: "gnosis", }, fmt.Errorf(configs.InvalidUrlFlagError, "consensus api", "localhost:4000"), }, @@ -1223,7 +1229,7 @@ func TestGenerateCmd(t *testing.T) { graffiti: "sedge-graffiti-sedge", }, globalFlags{ - network: "goerli", + network: "holesky", }, fmt.Errorf(configs.ErrGraffitiLength, "sedge-graffiti-sedge", 20), }, @@ -1310,6 +1316,60 @@ func TestGenerateCmd(t *testing.T) { globalFlags{}, 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/importKeys_test.go b/cli/importKeys_test.go index 863eca826..32bf8b056 100644 --- a/cli/importKeys_test.go +++ b/cli/importKeys_test.go @@ -43,7 +43,7 @@ func TestImportKeys_NumberOfArguments(t *testing.T) { }, { name: "with flags", - args: []string{"--network", "goerli"}, + args: []string{"--network", "mainnet"}, }, } for _, tt := range tests { @@ -85,7 +85,7 @@ func TestImportKeys_ArgsAndFlags(t *testing.T) { name: "with flags", args: []string{ "prysm", - "--network", "goerli", + "--network", "mainnet", "--from", "/tmp/keystore", "--path", "/tmp/sedge", "--start-validator", @@ -96,7 +96,7 @@ func TestImportKeys_ArgsAndFlags(t *testing.T) { }, expectedOptions: actions.ImportValidatorKeysOptions{ ValidatorClient: "prysm", - Network: "goerli", + Network: "mainnet", StartValidator: true, GenerationPath: "/tmp/sedge", From: "/tmp/keystore", @@ -106,7 +106,7 @@ func TestImportKeys_ArgsAndFlags(t *testing.T) { name: "with shorthand flags", args: []string{ "teku", - "-n", "goerli", + "-n", "mainnet", "--from", "/tmp/keystore", "-p", "/tmp/sedge", "--stop-validator", @@ -117,7 +117,7 @@ func TestImportKeys_ArgsAndFlags(t *testing.T) { }, expectedOptions: actions.ImportValidatorKeysOptions{ ValidatorClient: "teku", - Network: "goerli", + Network: "mainnet", From: "/tmp/keystore", GenerationPath: "/tmp/sedge", StopValidator: true, diff --git a/cli/keys.go b/cli/keys.go index d7d5bc9a3..f7bef2098 100644 --- a/cli/keys.go +++ b/cli/keys.go @@ -21,24 +21,27 @@ 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" + "github.com/NethermindEth/sedge/internal/utils" eth2 "github.com/protolambda/zrnt/eth2/configs" log "github.com/sirupsen/logrus" "github.com/spf13/cobra" ) 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 { @@ -83,6 +86,10 @@ func KeysCmd(cmdRunner commands.CommandRunner, p ui.Prompter) *cobra.Command { if err := configs.NetworkCheck(flags.network); err != nil { log.Fatal(err.Error()) } + // Validate fee recipient + if flags.ethWithdrawalAddress != "" && !utils.IsAddress(flags.ethWithdrawalAddress) { + log.Fatal(configs.ErrInvalidWithdrawalAddr) + } // Ensure that path is absolute log.Debugf("Path to keystore folder: %s", flags.path) absPath, err := filepath.Abs(flags.path) @@ -93,7 +100,21 @@ func KeysCmd(cmdRunner commands.CommandRunner, p ui.Prompter) *cobra.Command { return nil }, Run: func(cmd *cobra.Command, args []string) { - // TODO: allow usage of withdrawal address + // 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.ethWithdrawalAddress != "" { + log.Warn(configs.WithdrawalAddressDefinedWarning) + } // Get keystore passphrase if !flags.randomPassphrase && flags.passphrasePath != "" { content, err := readFileContent(flags.passphrasePath) @@ -153,14 +174,25 @@ func KeysCmd(cmdRunner commands.CommandRunner, p ui.Prompter) *cobra.Command { flags.numberVal = numberVal } + keystorePath := filepath.Join(flags.path, "keystore") + + var withdrawalAddress string + if flags.lidoNode { + withdrawalAddress, _ = contracts.WithdrawalAddress(flags.network) + withdrawalAddress = withdrawalAddress[2:] + } else if flags.ethWithdrawalAddress != "" { + withdrawalAddress = flags.ethWithdrawalAddress[2:] + } + data := keystores.ValidatorKeysGenData{ - Mnemonic: mnemonic, - Passphrase: passphrase, - OutputPath: keystorePath, - MinIndex: uint64(flags.existingVal), - MaxIndex: uint64(flags.existingVal) + uint64(flags.numberVal), - NetworkName: flags.network, - ForkVersion: configs.NetworksConfigs()[flags.network].GenesisForkVersion, + Mnemonic: mnemonic, + Passphrase: passphrase, + OutputPath: keystorePath, + MinIndex: uint64(flags.existingVal), + MaxIndex: uint64(flags.existingVal) + uint64(flags.numberVal), + NetworkName: flags.network, + ForkVersion: configs.NetworksConfigs()[flags.network].GenesisForkVersion, + WithdrawalAddress: withdrawalAddress, // Constants UseUniquePassphrase: true, Insecure: false, @@ -178,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.Flags().StringVarP(&flags.network, "network", "n", "mainnet", "Target network. e.g. mainnet, goerli, sepolia, holesky, gnosis, chiado etc.") + 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 eab966d56..f9aadd682 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" ) @@ -45,7 +46,7 @@ func FullNodeSubCmd(sedgeAction actions.SedgeActions) *cobra.Command { It will not generate a validator configuration if the --no-validator flag is set to true. -On mainnet, sepolia and goerli, mev-boost will be activated by default unless you run it with --no-mev-boost flag. +On mainnet and sepolia mev-boost will be activated by default unless you run it with --no-mev-boost flag. If you don't provide a execution, consensus or validator client, it will be chosen randomly. If one of the consensus or validator is provided, but the other one is omitted, then the same pair of clients will be used for both consensus and validator. @@ -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} @@ -79,10 +88,12 @@ Additionally, you can use this syntax ':' to override the cmd.Flags().StringVarP(&flags.validatorName, "validator", "v", "", "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") 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") @@ -125,7 +136,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}) @@ -170,7 +189,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}) @@ -181,7 +208,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") @@ -229,7 +257,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 @@ -239,7 +275,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.") @@ -271,9 +308,10 @@ 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, goerli, sepolia etc.") + cmd.Flags().StringVarP(&network, "network", "n", "mainnet", "Target network. e.g. mainnet, sepolia etc.") cmd.Flags().SortFlags = false return cmd } diff --git a/cli/testdata/down_tests/case_1/sedge-data/docker-compose.yml b/cli/testdata/down_tests/case_1/sedge-data/docker-compose.yml index 3739673e8..d337595c7 100644 --- a/cli/testdata/down_tests/case_1/sedge-data/docker-compose.yml +++ b/cli/testdata/down_tests/case_1/sedge-data/docker-compose.yml @@ -65,7 +65,7 @@ services: - --rest-api-host-allowlist=* - --rest-api-enabled=true - --rest-api-port=4000 - - --eth1-endpoints=${EC_NODE} + - --eth1=${EC_NODE} - --eth1-deposit-contract-max-request-size=150 logging: driver: "json-file" diff --git a/cli/testdata/logs_tests/case_1/sedge-data/docker-compose.yml b/cli/testdata/logs_tests/case_1/sedge-data/docker-compose.yml index 3739673e8..d337595c7 100644 --- a/cli/testdata/logs_tests/case_1/sedge-data/docker-compose.yml +++ b/cli/testdata/logs_tests/case_1/sedge-data/docker-compose.yml @@ -65,7 +65,7 @@ services: - --rest-api-host-allowlist=* - --rest-api-enabled=true - --rest-api-port=4000 - - --eth1-endpoints=${EC_NODE} + - --eth1=${EC_NODE} - --eth1-deposit-contract-max-request-size=150 logging: driver: "json-file" diff --git a/cli/testdata/run_tests/no_env/docker-compose.yml b/cli/testdata/run_tests/no_env/docker-compose.yml index 42f52d075..41a203c61 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-endpoints=${EC_API_URL} + - --eth1 - --debug-level=${CC_LOG_LEVEL} - --validator-monitor-auto - --subscribe-all-subnets diff --git a/cli/testdata/run_tests/no_image/docker-compose.yml b/cli/testdata/run_tests/no_image/docker-compose.yml index 253d5a617..3397a5b00 100644 --- a/cli/testdata/run_tests/no_image/docker-compose.yml +++ b/cli/testdata/run_tests/no_image/docker-compose.yml @@ -1,4 +1,3 @@ -version: "3.9" services: execution: stop_grace_period: 30m diff --git a/cli/testdata/run_tests/no_version/docker-compose.yml b/cli/testdata/run_tests/no_version/docker-compose.yml index a28ee5271..a23d4e0d3 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-endpoints=${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 42f52d075..a23d4e0d3 100644 --- a/cli/testdata/run_tests/valid/docker-compose.yml +++ b/cli/testdata/run_tests/valid/docker-compose.yml @@ -1,4 +1,3 @@ -version: "3.9" services: execution: stop_grace_period: 30s @@ -88,7 +87,7 @@ services: - --target-peers=${CC_PEER_COUNT} - --execution-endpoints=${EC_AUTH_URL} - --execution-jwt=/tmp/jwt/jwtsecret - - --eth1-endpoints=${EC_API_URL} + - --eth1 - --debug-level=${CC_LOG_LEVEL} - --validator-monitor-auto - --subscribe-all-subnets diff --git a/codecov.yml b/codecov.yml new file mode 100644 index 000000000..c4cd07f89 --- /dev/null +++ b/codecov.yml @@ -0,0 +1,2 @@ +ignore: + - "e2e" \ No newline at end of file diff --git a/configs/client_images.yaml b/configs/client_images.yaml index e76021133..59788a393 100644 --- a/configs/client_images.yaml +++ b/configs/client_images.yaml @@ -1,39 +1,39 @@ execution: geth: name: ethereum/client-go - version: v1.13.5 + version: v1.14.6 besu: name: hyperledger/besu - version: 23.10.2 + version: 24.6.0 nethermind: name: nethermind/nethermind - version: 1.23.0 + version: 1.27.0 erigon: name: thorax/erigon - version: v2.55.1 + version: v2.60.2 consensus: lighthouse: name: sigp/lighthouse - version: v4.5.0 + version: v5.2.1 lodestar: name: chainsafe/lodestar - version: v1.12.0 + version: v1.19.0 teku: name: consensys/teku - version: 23.11.0 + version: 24.6.1 prysm: name: gcr.io/prysmaticlabs/prysm/beacon-chain - version: v4.1.1 + version: v5.0.4 validator: lighthouse: name: sigp/lighthouse - version: v4.5.0 + version: v5.2.1 lodestar: name: chainsafe/lodestar - version: v1.12.0 + version: v1.19.0 teku: name: consensys/teku - version: 23.11.0 + version: 24.6.1 prysm: name: gcr.io/prysmaticlabs/prysm/validator - version: v4.1.1 + version: v5.0.4 \ No newline at end of file diff --git a/configs/errors.go b/configs/errors.go index abdedcae5..8b82002f7 100644 --- a/configs/errors.go +++ b/configs/errors.go @@ -17,71 +17,78 @@ package configs // All the strings that are needed for error logging. const ( - ReadingInstructionError = "failed to read instructions from file %s" - IncorrectClientError = "incorrect %s client name \"%s\". Please provide correct client name. Use 'clients' command to see the list of supported clients" - ClosingFileError = "failed to close file %s" - ScriptIsNotRunningError = "services of docker-compose script provided are not running. Error: %v" - GettingLogsError = "failed to get logs for services %s. Error: %v" - DockerComposePsReturnedEmptyError = "'docker compose ps --services' returned empty string" - InvalidVolumePathError = "invalid path provided: %s. If you intended to pass a host directory, use absolute path" - ZipError = "all lists must have the same size" - CommandError = "command '%s' throws error: %v" - DistroInfoError = "failed to get linux distribution info. Error: %v" - EmptyClientMapError = "is not possible to select a random element from an empty collection" - NoSupportedClientsError = "collection of clients given for random choice doesn't have any supported client. Check the target network (flag --network). Use 'clients' command to see the list of supported clients for every supported network" - NetworkValidationFailedError = "'network' flag validation failed. Error: %v" - UnknownNetworkError = "unknown network \"%s\". Please provide correct network name. Use 'networks' command to see the list of supported networks" - GenerateJWTSecretError = "JWT secret generation failed. Error: %v" - GetPWDError = "something failed trying to get current working directory. Error: %v" - EmptyFeeRecipientError = "you should provide an Ethereum address for the Fee Recipient" - KeystorePasswordError = "keystore password must have more than 8 characters" - PortOccupationError = "port occupation check failed. Error: %v" - DefaultPortInvalidError = "default %s can not be zero" - PrintFileError = "error printing file content: %v" - CleaningEnvFileError = "error cleaning env file: %v" - CleaningDCFileError = "error cleaning docker compose file: %v" - PassphraseReadFileError = "error reading passphrase file: %v" - MnemonicReadFileError = "error reading passphrase file: %v" - MnemonicGenerationError = "error creating mnemonic: %v" - KeyEntryGenerationError = "error generating keystore: could not read sufficient secure random bytes" - AESParamsCreationError = "failed to create AES128CTR params: %w" - SecretEncryptionError = "failed to encrypt secret: %w" - KeystoreOutputExistingError = "output folder for keystores already exists" - KeystoreGenerationError = "error generating keystores: %v" - KeystoreDerivationError = "keystore %s cannot be derived, continuing to next keystore" - KeystoreExistingInWalletError = "keystore with name \"%s\" already exists" - KeystoreImportingError = "failed to import keystore with pubkey %s into output wallet: %v" - InvalidMnemonicError = "mnemonic is not valid" - BadMnemonicError = "bad mnemonic: %v" - ForkVersionDecodeError = "cannot decode fork version: %v" - DepositFileWriteError = "cannot write deposit file: %v" - KeystoreSecretKeyCreationError = "failed to create validator private key for path %q: %v" - WithdrawalSecretKeyCreationError = "failed to create withdrawal private key for path %q: %v" - KeystoreSecretKeyConvertionError = "cannot convert validator priv key: %v" - DepositDataEncodingError = "could not encode deposit data to json: %v" - InvalidLoggingFlag = "bad logging flag: %v" - CannotGenerateSecret = "cannot generate 32 bytes long secret" - ShowMnemonicError = "error displaying mnemonic: %v" - InvalidFilePathOrUrl = "invalid filepath or url: %s" - CannotGetUrlContent = "cannot get url %s content: %v" - CannotReadFileContent = "cannot read file %s content: %v" - ErrorCheckingFile = "error checking file %s: %v" - DestFileAlreadyExist = "destiny file %s already exist" - ErrorCreatingFile = "error creating file %s: %v" - ErrorDownloadingFile = "error downloading file from %s: %v" - ErrorCopyingFile = "error copying file from %s: %v" - ErrorWritingDeployBlockFile = "error writing custom deploy block file %s: %v" - InvalidUrlFlagError = "invalid %s url %s. URL must be in the format http(s)://:///... or http://///" - InvalidEnodeError = "invalid enode %s. Bootnode must be in the format enode://@:" - InvalidEnrError = "invalid enr %s. ENR must be in the format enr:" - InvalidService = "provided service %s is invalid" - SetupContainersErr = "error setting up service containers: %w" - StartingContainersErr = "error starting service containers: %w" - ReadingYmlErr = "error reading yml file: %w" - ParsingYmlErr = "error parsing yml file, it seems is not a valid docker-compose script: %w" - ServicesNotFoundErr = "services not found in the docker-compose script" - InvalidComposeErr = "provided docker-compose script is invalid: %w" - ErrDuplicatedBootNode = "duplicated boot node" - ErrGraffitiLength = "graffiti must have 16 characters at most. Provided graffiti %s has %d characters" - ErrCMDArgsNotSupported = "command %s does not support arguments. Please use flags instead" + ReadingInstructionError = "failed to read instructions from file %s" + IncorrectClientError = "incorrect %s client name \"%s\". Please provide correct client name. Use 'clients' command to see the list of supported clients" + ClosingFileError = "failed to close file %s" + ScriptIsNotRunningError = "services of docker-compose script provided are not running. Error: %v" + GettingLogsError = "failed to get logs for services %s. Error: %v" + DockerComposePsReturnedEmptyError = "'docker compose ps --services' returned empty string" + InvalidVolumePathError = "invalid path provided: %s. If you intended to pass a host directory, use absolute path" + ZipError = "all lists must have the same size" + CommandError = "command '%s' throws error: %v" + DistroInfoError = "failed to get linux distribution info. Error: %v" + EmptyClientMapError = "is not possible to select a random element from an empty collection" + NoSupportedClientsError = "collection of clients given for random choice doesn't have any supported client. Check the target network (flag --network). Use 'clients' command to see the list of supported clients for every supported network" + NetworkValidationFailedError = "'network' flag validation failed. Error: %v" + UnknownNetworkError = "unknown network \"%s\". Please provide correct network name. Use 'networks' command to see the list of supported networks" + GenerateJWTSecretError = "JWT secret generation failed. Error: %v" + GetPWDError = "something failed trying to get current working directory. Error: %v" + EmptyFeeRecipientError = "you should provide an Ethereum address for the Fee Recipient" + KeystorePasswordError = "keystore password must have more than 8 characters" + PortOccupationError = "port occupation check failed. Error: %v" + DefaultPortInvalidError = "default %s can not be zero" + PrintFileError = "error printing file content: %v" + CleaningEnvFileError = "error cleaning env file: %v" + CleaningDCFileError = "error cleaning docker compose file: %v" + PassphraseReadFileError = "error reading passphrase file: %v" + MnemonicReadFileError = "error reading passphrase file: %v" + MnemonicGenerationError = "error creating mnemonic: %v" + KeyEntryGenerationError = "error generating keystore: could not read sufficient secure random bytes" + AESParamsCreationError = "failed to create AES128CTR params: %w" + SecretEncryptionError = "failed to encrypt secret: %w" + KeystoreOutputExistingError = "output folder for keystores already exists" + KeystoreGenerationError = "error generating keystores: %v" + KeystoreDerivationError = "keystore %s cannot be derived, continuing to next keystore" + KeystoreExistingInWalletError = "keystore with name \"%s\" already exists" + KeystoreImportingError = "failed to import keystore with pubkey %s into output wallet: %v" + InvalidMnemonicError = "mnemonic is not valid" + BadMnemonicError = "bad mnemonic: %v" + ForkVersionDecodeError = "cannot decode fork version: %v" + DepositFileWriteError = "cannot write deposit file: %v" + KeystoreSecretKeyCreationError = "failed to create validator private key for path %q: %v" + WithdrawalSecretKeyCreationError = "failed to create withdrawal private key for path %q: %v" + KeystoreSecretKeyConvertionError = "cannot convert validator priv key: %v" + DepositDataEncodingError = "could not encode deposit data to json: %v" + InvalidLoggingFlag = "bad logging flag: %v" + CannotGenerateSecret = "cannot generate 32 bytes long secret" + ShowMnemonicError = "error displaying mnemonic: %v" + InvalidFilePathOrUrl = "invalid filepath or url: %s" + CannotGetUrlContent = "cannot get url %s content: %v" + CannotReadFileContent = "cannot read file %s content: %v" + ErrorCheckingFile = "error checking file %s: %v" + DestFileAlreadyExist = "destiny file %s already exist" + ErrorCreatingFile = "error creating file %s: %v" + ErrorDownloadingFile = "error downloading file from %s: %v" + ErrorCopyingFile = "error copying file from %s: %v" + ErrorWritingDeployBlockFile = "error writing custom deploy block file %s: %v" + InvalidUrlFlagError = "invalid %s url %s. URL must be in the format http(s)://:///... or http://///" + InvalidEnodeError = "invalid enode %s. Bootnode must be in the format enode://@:" + InvalidEnrError = "invalid enr %s. ENR must be in the format enr:" + InvalidService = "provided service %s is invalid" + SetupContainersErr = "error setting up service containers: %w" + StartingContainersErr = "error starting service containers: %w" + ReadingYmlErr = "error reading yml file: %w" + ParsingYmlErr = "error parsing yml file, it seems is not a valid docker-compose script: %w" + ServicesNotFoundErr = "services not found in the docker-compose script" + InvalidComposeErr = "provided docker-compose script is invalid: %w" + ErrDuplicatedBootNode = "duplicated boot node" + ErrGraffitiLength = "graffiti must have 16 characters at most. Provided graffiti %s has %d characters" + ErrCMDArgsNotSupported = "command %s does not support arguments. Please use flags instead" + 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 25110ef76..77e953d15 100644 --- a/configs/init.go +++ b/configs/init.go @@ -32,20 +32,7 @@ var networksConfigs map[string]NetworkConfig = map[string]NetworkConfig{ "https://0xac6e77dfe25ecd6110b8e780608cce0dab71fdd5ebea22a16c0205200f2f8e2e3ad3b71d3499c54ad14d6c21b41a37ae@boost-relay.flashbots.net", "https://0xa1559ace749633b997cb3fdacffb890aeebdb0f5a3b6aaa7eeeaf1a38af0a8fe88b9e4b1f61f236d2e64d95733327a62@relay.ultrasound.money", }, - }, - NetworkGoerli: { - Name: NetworkGoerli, - NetworkService: "merge", - GenesisForkVersion: "0x00001020", - SupportsMEVBoost: true, - CheckpointSyncURL: "https://goerli.checkpoint-sync.ethpandaops.io", - RelayURLs: []string{ - "https://0xafa4c6985aa049fb79dd37010438cfebeb0f2bd42b115b89dd678dab0670c1de38da0c4e9138c9290a398ecd9a0b3110@builder-relay-goerli.flashbots.net", - "https://0x821f2a65afb70e7f2e820a925a9b4c80a159620582c1766b1b09729fec178b11ea22abb3a51f07b288be815a1a2ff516@bloxroute.max-profit.builder.goerli.blxrbdn.com", - "https://0x8f7b17a74569b7a57e9bdafd2e159380759f5dc3ccbd4bf600414147e8c4e1dc6ebada83c0139ac15850eb6c975e82d0@builder-relay-goerli.blocknative.com", - "https://0xb1d229d9c21298a87846c7022ebeef277dfc321fe674fa45312e20b5b6c400bfde9383f801848d7837ed5fc449083a12@relay-goerli.edennetwork.io", - "https://0xb1559beef7b5ba3127485bbbb090362d9f497ba64e177ee2c8e7db74746306efad687f2cf8574e38d70067d40ef136dc@relay-stag.ultrasound.money", - }, + Weight: 1, }, NetworkSepolia: { Name: NetworkSepolia, @@ -56,30 +43,41 @@ 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", - SupportsMEVBoost: false, + GenesisForkVersion: "0x01017000", + SupportsMEVBoost: true, CheckpointSyncURL: "https://checkpoint-sync.holesky.ethpandaops.io/", + RelayURLs: []string{ + "https://0xafa4c6985aa049fb79dd37010438cfebeb0f2bd42b115b89dd678dab0670c1de38da0c4e9138c9290a398ecd9a0b3110@boost-relay-holesky.flashbots.net", + "https://0x8db06236d88cf080e541f894507f6c933d40333405c36c8ea00158c165628ea57ad59b024467fe7d4d31113fadc0e187@holesky.agnostic-relay.net", + "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 ebd6391fa..d4b9be4f6 100644 --- a/configs/messages.go +++ b/configs/messages.go @@ -23,43 +23,45 @@ import ( // All the strings that are needed for debugging and info logging, and constant strings. const ( - DefaultMevBoostEndpoint = "http://mev-boost" - DefaultEnvFileName = ".env" - CheckingDependencies = "Checking dependencies: %s" - DependenciesPending = "pending dependencies: %s" - DependenciesOK = "All dependencies are installed on host machine" - GeneratingDockerComposeScript = "Generating docker-compose script for current selection of clients" - GeneratingEnvFile = "Generating environment file for current selection of clients" - GeneratedDockerComposeScript = "Generated docker-compose script for current selection of clients" - GeneratedEnvFile = "Generated environment file for current selection of clients" - CleaningGeneratedFiles = "Cleaning generated docker-compose and environment files" - CleanedGeneratedFiles = "Cleaned generated files" - GenerationEnd = "Generation of files successfully, happy staking! You can use now 'sedge run' to start the setup." - Exiting = "Exiting..." - InstructionsFor = "Instructions for %s" - OSNotSupported = "installation not supported for %s" - ProvideClients = "Please provide both execution client and consensus client" - CreatedFile = "Created file %s" - DefaultSedgeDataFolderName = "sedge-data" - ClientNotSupported = "client %s is not supported. Please use 'clients' command to see the list of supported clients" - PrintingFile = "File %s:" - SupportedClients = "Supported clients of type %s: %v" - ConfigClientsMsg = "Provided clients of type %s in configuration file: %v" - RunningDockerCompose = "Running docker-compose script" - Component = "component" - RunningCommand = "Running command: %s" - UnableToProceed = "Unable to proceed. Please check the logs for more details" - CheckingDockerEngine = "Checking if docker engine is on" - DepositCLIDockerImageUrl = "nethermindeth/staking-deposit-cli" //"github.com/ethereum/staking-deposit-cli" - DepositCLIDockerImageName = "nethermindeth/staking-deposit-cli" //"deposit-cli:local" - GeneratingKeystores = "Generating keystores..." - GeneratingKeystoresLegacy = "Generating keystore folder" - KeystoresGenerated = "Keystores generated successfully" - GeneratingDepositData = "Generating deposit data..." - DepositDataGenerated = "Deposit data generated successfully" - 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" + DefaultMevBoostEndpoint = "http://mev-boost" + DefaultEnvFileName = ".env" + CheckingDependencies = "Checking dependencies: %s" + DependenciesPending = "pending dependencies: %s" + DependenciesOK = "All dependencies are installed on host machine" + GeneratingDockerComposeScript = "Generating docker-compose script for current selection of clients" + GeneratingEnvFile = "Generating environment file for current selection of clients" + GeneratedDockerComposeScript = "Generated docker-compose script for current selection of clients" + GeneratedEnvFile = "Generated environment file for current selection of clients" + CleaningGeneratedFiles = "Cleaning generated docker-compose and environment files" + CleanedGeneratedFiles = "Cleaned generated files" + GenerationEnd = "Generation of files successfully, happy staking! You can use now 'sedge run' to start the setup." + Exiting = "Exiting..." + InstructionsFor = "Instructions for %s" + OSNotSupported = "installation not supported for %s" + ProvideClients = "Please provide both execution client and consensus client" + CreatedFile = "Created file %s" + DefaultSedgeDataFolderName = "sedge-data" + ClientNotSupported = "client %s is not supported. Please use 'clients' command to see the list of supported clients" + PrintingFile = "File %s:" + SupportedClients = "Supported clients of type %s: %v" + ConfigClientsMsg = "Provided clients of type %s in configuration file: %v" + RunningDockerCompose = "Running docker-compose script" + Component = "component" + RunningCommand = "Running command: %s" + UnableToProceed = "Unable to proceed. Please check the logs for more details" + CheckingDockerEngine = "Checking if docker engine is on" + DepositCLIDockerImageUrl = "nethermindeth/staking-deposit-cli" //"github.com/ethereum/staking-deposit-cli" + DepositCLIDockerImageName = "nethermindeth/staking-deposit-cli" //"deposit-cli:local" + GeneratingKeystores = "Generating keystores..." + GeneratingKeystoresLegacy = "Generating keystore folder" + 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" + WithdrawalAddressDefinedWarning = "You have defined a withdrawal address for your validators. Make sure this is intended. Deposits made with this withdrawal address cannot be changed. If you want to change the withdrawal address, you will have to exit your validators and create new validators with the new withdrawal address." ReviewKeystorePath = "In case you used custom paths for the 'cli' or the 'keys' commands, please review if the keystore path in the generated .env file points to the generated keystore folder (the .env key should be KEYSTORE_DIR). If not, change the path in the .env file to the correct one." NodesSynced = "Execution and Consensus clients are synced, proceeding to start validator node" diff --git a/configs/networks.go b/configs/networks.go index afd327c2e..a5a51a889 100644 --- a/configs/networks.go +++ b/configs/networks.go @@ -24,7 +24,6 @@ import ( const ( // Network names NetworkMainnet = "mainnet" - NetworkGoerli = "goerli" NetworkSepolia = "sepolia" NetworkGnosis = "gnosis" NetworkChiado = "chiado" @@ -36,7 +35,7 @@ var ErrInvalidNetwork = errors.New("invalid network") func NetworkCheck(value string) error { switch value { - case NetworkMainnet, NetworkGoerli, NetworkSepolia, NetworkGnosis, NetworkChiado, NetworkHolesky, NetworkCustom: + case NetworkMainnet, NetworkSepolia, NetworkGnosis, NetworkChiado, NetworkHolesky, NetworkCustom: return nil default: return fmt.Errorf("%w: %s", ErrInvalidNetwork, value) @@ -47,7 +46,6 @@ func NetworkSupported() []string { // notest return []string{ NetworkMainnet, - NetworkGoerli, NetworkSepolia, NetworkGnosis, NetworkChiado, @@ -58,7 +56,7 @@ func NetworkSupported() []string { func NetworkEpochTime(network string) time.Duration { switch network { - case NetworkMainnet, NetworkGoerli, NetworkSepolia: + case NetworkMainnet, NetworkSepolia: return 7 * time.Minute case NetworkGnosis, NetworkChiado: return 2 * time.Minute @@ -71,3 +69,11 @@ func SupportsMEVBoost(network string) bool { out, ok := networksConfigs[network] return ok && out.SupportsMEVBoost } + +func GetPublicRPCs(network string) ([]string, error) { + rpcs, exists := networkRPCs[network] + if !exists { + return nil, fmt.Errorf("invalid network") + } + return rpcs.PublicRPCs, nil +} diff --git a/configs/networks_test.go b/configs/networks_test.go index 90bed5cd5..d11f995f7 100644 --- a/configs/networks_test.go +++ b/configs/networks_test.go @@ -14,9 +14,9 @@ func TestNetworkCheck(t *testing.T) { wantErr: false, }, { - name: "Valid network, goerli", + name: "Invalid network, goerli", network: "goerli", - wantErr: false, + wantErr: true, }, { name: "Valid network, sepolia", @@ -65,15 +65,20 @@ func TestSupportMEVBoost(t *testing.T) { want: true, }, { - name: "Valid network, goerli", + name: "Invalid network, goerli", network: "goerli", - want: true, + want: false, }, { name: "Valid network, sepolia", network: "sepolia", want: true, }, + { + name: "Valid network, holesky", + network: "holesky", + want: true, + }, { name: "Valid network, gnosis", network: "gnosis", diff --git a/configs/public_rpcs.go b/configs/public_rpcs.go new file mode 100644 index 000000000..e40ece860 --- /dev/null +++ b/configs/public_rpcs.go @@ -0,0 +1,28 @@ +package configs + +type RPC struct { + NetworkName string + PublicRPCs []string +} + +var networkRPCs = map[string]RPC{ + NetworkMainnet: { + NetworkName: NetworkMainnet, + PublicRPCs: []string{ + "https://eth.llamarpc.com", + "https://eth-pokt.nodies.app", + "https://rpc.mevblocker.io", + "https://ethereum-rpc.publicnode.com", + "https://rpc.flashbots.net", + }, + }, + NetworkHolesky: { + NetworkName: NetworkHolesky, + PublicRPCs: []string{ + "https://holesky.drpc.org", + "https://ethereum-holesky-rpc.publicnode.com", + "https://endpoints.omniatech.io/v1/eth/holesky/public", + "https://ethereum-holesky.blockpi.network/v1/rpc/public", + }, + }, +} diff --git a/configs/types.go b/configs/types.go index cb3af28b0..599b32882 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 cb6778870..e947b3b7a 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 @@ -42,8 +43,8 @@ This is an example of what you can expect: ``` sedge cli 2023-03-20 21:54:08 -- [INFO] [Logger Init] Log level: info -2023-03-20 21:54:08 -- [INFO] You are running the latest version of sedge. Version: v1.3.0 -? Select network goerli +2023-03-20 21:54:08 -- [INFO] You are running the latest version of sedge. Version: v1.3.1 +? Select network mainnet ? Select node type full-node ? Generation path /root/sedge-data ? Container tag, sedge will add to each container and the network, a suffix with the tag @@ -51,22 +52,22 @@ sedge cli ? Enable MEV Boost? Yes ? Mev-Boost image flashbots/mev-boost:latest ? Insert relay URLs if you don't want to use the default values listed below Default values are listed below. ( -https://0xafa4c6985aa049fb79dd37010438cfebeb0f2bd42b115b89dd678dab0670c1de38da0c4e9138c9290a398ecd9a0b3110@builder-relay-goerli.flashbots.net -https://0x821f2a65afb70e7f2e820a925a9b4c80a159620582c1766b1b09729fec178b11ea22abb3a51f07b288be815a1a2ff516@bloxroute.max-profit.builder.goerli.blxrbdn.com +https://0xac6e77dfe25ecd6110b8e780608cce0dab71fdd5ebea22a16c0205200f2f8e2e3ad3b71d3499c54ad14d6c21b41a37ae@boost-relay.flashbots.net +https://0x8b5d2e73e2a3a55c6c87b8b6eb92e0149a125c852751db1422fa951e42a09b82c142c3ea98d0d9930b056a3bc9896b8f@bloxroute.max-profit.blxrbdn.com ? Insert relay URLs if you don't want to use the default values listed below Default values are listed below. -https://0xafa4c6985aa049fb79dd37010438cfebeb0f2bd42b115b89dd678dab0670c1de38da0c4e9138c9290a398ecd9a0b3110@builder-relay-goerli.flashbots.net -https://0x821f2a65afb70e7f2e820a925a9b4c80a159620582c1766b1b09729fec178b11ea22abb3a51f07b288be815a1a2ff516@bloxroute.max-profit.builder.goerli.blxrbdn.com -https://0x8f7b17a74569b7a57e9bdafd2e159380759f5dc3ccbd4bf600414147e8c4e1dc6ebada83c0139ac15850eb6c975e82d0@builder-relay-goerli.blocknative.com -https://0xb1d229d9c21298a87846c7022ebeef277dfc321fe674fa45312e20b5b6c400bfde9383f801848d7837ed5fc449083a12@relay-goerli.edennetwork.io -https://0xb1559beef7b5ba3127485bbbb090362d9f497ba64e177ee2c8e7db74746306efad687f2cf8574e38d70067d40ef136dc@relay-stag.ultrasound.money +https://0xac6e77dfe25ecd6110b8e780608cce0dab71fdd5ebea22a16c0205200f2f8e2e3ad3b71d3499c54ad14d6c21b41a37ae@boost-relay.flashbots.net +https://0x8b5d2e73e2a3a55c6c87b8b6eb92e0149a125c852751db1422fa951e42a09b82c142c3ea98d0d9930b056a3bc9896b8f@bloxroute.max-profit.blxrbdn.com +https://0x9000009807ed12c1f08bf4e81c6da3ba8e3fc3d953898ce0102433094e5f22f21102ec057841fcb81978ed1ea0fa8246@builder-relay-mainnet.blocknative.com +https://0xb3ee7afcf27f1f1259ac1787876318c6584ee353097a50ed84f51a1f21a323b3736f271a895c7ce918c038e4265918be@relay.edennetwork.io +https://0xa1559ace749633b997cb3fdacffb890aeebdb0f5a3b6aaa7eeeaf1a38af0a8fe88b9e4b1f61f236d2e64d95733327a62@relay.ultrasound.money ? Select execution client nethermind ? Select consensus client prysm ? Select validator client prysm ? Validator grace period. This is the number of epochs the validator will wait for security reasons before starting 2 ? Graffiti to be used by the validator (press enter to skip it) neth-prysm -? Checkpoint sync URL https://goerli.checkpoint-sync.ethpandaops.io +? Checkpoint sync URL https://beaconstate.ethstaker.cc ? Please enter the Fee Recipient address 0xEf8801eaf234ff82801821FFe2d78D60a0237F97 ? Do you want to expose all ports? No ? Select JWT source create diff --git a/docs/docs/commands/clients.mdx b/docs/docs/commands/clients.mdx index 2e703b792..210be660a 100644 --- a/docs/docs/commands/clients.mdx +++ b/docs/docs/commands/clients.mdx @@ -31,7 +31,7 @@ The execution of `sedge clients` will result in an output like this, that will s ``` $ sedge clients 2023-10-13 14:13:44 -- [INFO] [Logger Init] Log level: info -2023-10-13 14:13:45 -- [INFO] You are running the latest version of sedge. Version: v1.3.0 +2023-10-13 14:13:45 -- [INFO] You are running the latest version of sedge. Version: v1.3.1 2023-10-13 14:13:45 -- [INFO] Listing supported clients for network chiado # Execution Clients Consensus Clients Validator Clients @@ -57,15 +57,6 @@ $ sedge clients 2 erigon teku teku 3 - lodestar lodestar -2023-10-13 14:13:45 -- [INFO] Listing supported clients for network goerli - - # Execution Clients Consensus Clients Validator Clients -=== =================== =================== =================== - 1 nethermind lighthouse lighthouse - 2 geth prysm prysm - 3 erigon teku teku - 4 besu lodestar lodestar - 2023-10-13 14:13:45 -- [INFO] Listing supported clients for network holesky # Execution Clients Consensus Clients Validator Clients diff --git a/docs/docs/commands/deps.mdx b/docs/docs/commands/deps.mdx index 4615d86ad..fe31f1b17 100644 --- a/docs/docs/commands/deps.mdx +++ b/docs/docs/commands/deps.mdx @@ -75,7 +75,7 @@ The execution of `sedge deps check` will result in an output like this if everyt ``` $ sedge deps check 2023-03-21 02:56:04 -- [INFO] [Logger Init] Log level: info -2023-03-21 02:56:05 -- [INFO] You are running the latest version of sedge. Version: v1.3.0 +2023-03-21 02:56:05 -- [INFO] You are running the latest version of sedge. Version: v1.4.0 2023-03-21 02:56:05 -- [INFO] docker is installed 2023-03-21 02:56:06 -- [INFO] All dependencies are installed and running ``` diff --git a/docs/docs/commands/down.mdx b/docs/docs/commands/down.mdx index 73019f32a..88b0c5640 100644 --- a/docs/docs/commands/down.mdx +++ b/docs/docs/commands/down.mdx @@ -38,7 +38,7 @@ The execution of `sedge down` will close and remove all the opened containers an ``` $ sedge down 2022-00-00 00:00:00 -- [INFO] [Logger Init] Log level: info -2022-00-00 00:00:00 -- [INFO] You are running the latest version of sedge. Version: v1.3.0 +2022-00-00 00:00:00 -- [INFO] You are running the latest version of sedge. Version: v1.4.0 [sudo] password for maceo: [+] Running 7/7 ⠿ Container execution-client Removed 93.8s diff --git a/docs/docs/commands/generate.mdx b/docs/docs/commands/generate.mdx index 456eb31aa..7f07ec999 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,8 +37,9 @@ 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, goerli, 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-data") Global Flags: @@ -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 @@ -62,7 +73,7 @@ Generate a docker-compose and an environment file with a full node configuration It will not generate a validator configuration if the --no-validator flag is set to true. -On mainnet, sepolia and goerli, mev-boost will be activated by default unless you run it with --no-mev-boost flag. +On mainnet and sepolia mev-boost will be activated by default unless you run it with --no-mev-boost flag. If you don't provide a execution, consensus or validator client, it will be chosen randomly. If one of the consensus or validator is provided, but the other one is omitted, then the same pair of clients will be used for both consensus and validator. @@ -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, goerli, 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, goerli, 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, goerli, 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, goerli, 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, goerli, 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 bf2f2b3c6..90fa62f77 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 @@ -78,7 +79,7 @@ To import the validator keys, and start the validator client after the import, r ```shell $ sedge import-key --from keystore -n sepolia --start-validator prysm 2023-01-26 11:59:34 -- [INFO] [Logger Init] Log level: info -2023-01-26 11:59:34 -- [INFO] You are running the latest version of sedge. Version: v1.3.0 +2023-01-26 11:59:34 -- [INFO] You are running the latest version of sedge. Version: v1.4.0 # highlight-next-line 2023-01-26 11:59:34 -- [WARN] The keys path is not the default one, copying the keys to the default path /root/sedge/example/sedge-data/keystore 2023-01-26 11:59:34 -- [INFO] Importing validator keys diff --git a/docs/docs/commands/keys.mdx b/docs/docs/commands/keys.mdx index 2921b05ae..848b13865 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, goerli, 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 967668d3e..66cb25367 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