-
Notifications
You must be signed in to change notification settings - Fork 149
feat(networkconfig): CLI for custom SSV config generation #2156
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
MatusKysel
merged 15 commits into
networkconfig-from-beacon-node
from
networkconfig-generate-ssv
May 27, 2025
Merged
Changes from all commits
Commits
Show all changes
15 commits
Select commit
Hold shift + click to select a range
3cdda27
networkconfig: CLI for custom SSV config generation
nkryuchkov 17eb427
implement JSON marshaling and YAML marshaling/unmarshaling
nkryuchkov cf5db78
remove TotalEthereumValidators
nkryuchkov 72f4d8d
simplify marshaling/unmarshaling logic
nkryuchkov 1337765
fix markdown formatting
nkryuchkov e226819
use yaml@v3
nkryuchkov b91c135
add tests
nkryuchkov a286f15
simplify unmarshaling
nkryuchkov c93cc43
Merge branch 'networkconfig-from-beacon-node' into networkconfig-gene…
nkryuchkov aa5d378
Merge branch 'networkconfig-from-beacon-node' into networkconfig-gene…
nkryuchkov 144e380
fix linter
nkryuchkov 74167bd
Merge branch 'networkconfig-from-beacon-node' into networkconfig-gene…
nkryuchkov 180db70
Merge branch 'networkconfig-from-beacon-node' into networkconfig-gene…
nkryuchkov 6d720fe
Merge branch 'networkconfig-from-beacon-node' into networkconfig-gene…
nkryuchkov ff3f2d2
add missing fields to LocalTestnet
nkryuchkov File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,160 @@ | ||
| # SSV Config Generator | ||
|
|
||
| **SSV Config Generator** is a command-line tool designed to generate configuration file for SSV Node. It streamlines the setup process by allowing users to specify various parameters through flags, which are then compiled into a YAML configuration file. This tool ensures that the SSV network setup is consistent, customizable, and easy to manage. | ||
|
|
||
| ## Table of Contents | ||
|
|
||
| - [Usage](#usage) | ||
| - [Flags](#flags) | ||
| - [Examples](#examples) | ||
| - [Configuration](#configuration) | ||
|
|
||
| ## Usage | ||
|
|
||
| The `generate-config` command allows you to generate a YAML configuration file by specifying various parameters through command-line flags. | ||
|
|
||
| ### Syntax | ||
|
|
||
| ```bash | ||
| ssvnode generate-config [flags] | ||
| ``` | ||
|
|
||
| ### Flags | ||
|
|
||
| | Flag | Type | Default | Description | | ||
| |--------------------------------------|--------|-----------------------------------|----------------------------------------------------------------------------| | ||
| | `--output-path` | string | `./config/config.local.yaml` | Output path for the generated configuration file. | | ||
| | `--log-level` | string | `info` | Sets the logging level (e.g., `debug`, `info`, `warn`, `error`). | | ||
| | `--db-path` | string | `./data/db` | Path to the database directory. | | ||
| | `--discovery` | string | `mdns` | Discovery method. | | ||
| | `--consensus-client` | string | _Mandatory_ | Address of the consensus client (e.g., `http://localhost:9000`). | | ||
| | `--execution-client` | string | _Mandatory_ | Address of the execution client (e.g., `http://localhost:8545`). | | ||
| | `--operator-private-key` | string | | Secret key for the operator. | | ||
| | `--metrics-api-port` | int | `0` | Port number for the Metrics API (set to `0` to disable). | | ||
| | `--ssv-domain` | string | Derived from local testnet config | Hex-encoded domain type (prefixed with `0x`). | | ||
| | `--ssv-registry-sync-offset` | uint64 | Derived from local testnet config | Registry sync offset for the network. | | ||
| | `--ssv-registry-contract-addr` | string | Derived from local testnet config | Ethereum address of the network registry contract (e.g., `0xYourAddress`). | | ||
| | `--ssv-bootnodes` | string | Derived from local testnet config | Comma-separated list of network bootnodes. | | ||
| | `--ssv-discovery-protocol-id` | string | Derived from local testnet config | Hex-encoded discovery protocol ID (prefixed with `0x`). | | ||
| | `--ssv-alan-fork-epoch` | uint64 | Derived from local testnet config | Epoch at which the Alan fork occurs in the network. | | ||
| | `--ssv-max-validators-per-committee` | int | Derived from local testnet config | Max validators per committee. | | ||
|
|
||
|
|
||
| **Note:** The `--consensus-client` and `--execution-client` flags are mandatory and must be provided when running the CLI. | ||
|
|
||
| ## Examples | ||
|
|
||
| ### Basic Configuration | ||
|
|
||
| Generate a configuration file with default settings, specifying only the mandatory flags: | ||
|
|
||
| ```bash | ||
| ssvnode generate-config \ | ||
| --consensus-client "http://localhost:9000" \ | ||
| --execution-client "http://localhost:8545" | ||
| ``` | ||
|
|
||
| This command generates a `config.local.yaml` file in the `./config` directory with default settings for all other parameters. | ||
|
|
||
| ### Custom Output Path and Log Level | ||
|
|
||
| Generate a configuration file with a custom output path and set the log level to `debug`: | ||
|
|
||
| ```bash | ||
| ssvnode generate-config \ | ||
| --consensus-client "http://consensus.example.com:9000" \ | ||
| --execution-client "http://execution.example.com:8545" \ | ||
| --output-path "/etc/ssv/config.yaml" \ | ||
| --log-level "debug" | ||
| ``` | ||
|
|
||
| ### Specify Operator Private Key and Enable Metrics API | ||
|
|
||
| Generate a configuration with an operator's private key and enable the Metrics API on port `8080`: | ||
|
|
||
| ```bash | ||
| ssvnode generate-config \ | ||
| --consensus-client "http://consensus.example.com:9000" \ | ||
| --execution-client "http://execution.example.com:8545" \ | ||
| --operator-private-key "your-operator-private-key" \ | ||
| --metrics-api-port 8080 | ||
| ``` | ||
|
|
||
| ### Advanced Network Configuration | ||
|
|
||
| Customize network settings such as bootnodes, discovery protocol ID, fork epoch, etc: | ||
|
|
||
| ```bash | ||
| ssvnode generate-config \ | ||
| --consensus-client "http://consensus.example.com:9000" \ | ||
| --execution-client "http://execution.example.com:8545" \ | ||
| --ssv-domain "0x12345678" \ | ||
| --ssv-registry-sync-offset 50 \ | ||
| --ssv-registry-contract-addr "0xYourRegistryContractAddress" \ | ||
| --ssv-bootnodes "enode://bootnode1@127.0.0.1:30303,enode://bootnode2@127.0.0.1:30304" \ | ||
| --ssv-discovery-protocol-id "0x1234567890ab" \ | ||
| --ssv-max-validators-per-committee 560 | ||
| ``` | ||
|
|
||
| ## Configuration | ||
|
|
||
| The generated YAML configuration file (`config.local.yaml` by default) follows the structure defined by the `Config` struct. Below is an overview of each section and its corresponding fields: | ||
|
|
||
| ### YAML Structure | ||
|
|
||
| ```yaml | ||
| global: | ||
| LogLevel: info | ||
| db: | ||
| Path: ./data/db | ||
| eth2: | ||
| BeaconNodeAddr: http://localhost:9000 | ||
| eth1: | ||
| ETH1Addr: http://localhost:8545 | ||
| p2p: | ||
| Discovery: mdns | ||
| ssv: | ||
| Network: LocalTestnetSSV | ||
| CustomNetwork: | ||
| DomainType: "0x12345678" | ||
| RegistrySyncOffset: 0 | ||
| RegistryContractAddr: "0xYourRegistryContractAddress" | ||
| Bootnodes: | ||
| - "enode://bootnode1@127.0.0.1:30303" | ||
| - "enode://bootnode2@127.0.0.1:30304" | ||
| DiscoveryProtocolID: "0x1234567890ab" | ||
| OperatorPrivateKey: your-operator-private-key | ||
| MetricsAPIPort: 8080 | ||
| ``` | ||
|
|
||
| ### Sections | ||
|
|
||
| - **global** | ||
| - `LogLevel`: Specifies the logging level (e.g., `debug`, `info`, `warn`, `error`). | ||
|
|
||
| - **db** | ||
| - `Path`: Path to the database directory. | ||
|
|
||
| - **eth2** | ||
| - `BeaconNodeAddr`: Address of the consensus client (Beacon Node). | ||
|
|
||
| - **eth1** | ||
| - `ETH1Addr`: Address of the execution client (ETH1 Node). | ||
|
|
||
| - **p2p** | ||
| - `Discovery`: Peer-to-peer discovery method (e.g., `mdns`). | ||
|
|
||
| - **ssv** | ||
| - `Network`: Name of the network. | ||
| - `CustomNetwork`: Contains custom network parameters. | ||
| - `DomainType`: Hex-encoded domain type (prefixed with `0x`). | ||
| - `RegistrySyncOffset`: Registry sync offset for the network. | ||
| - `RegistryContractAddr`: Ethereum address of the network registry contract. | ||
| - `Bootnodes`: List of network bootnodes. | ||
| - `DiscoveryProtocolID`: Hex-encoded discovery protocol ID (prefixed with `0x`). | ||
|
|
||
| - **OperatorPrivateKey** | ||
| - `OperatorPrivateKey`: Secret key for the operator. | ||
|
|
||
| - **MetricsAPIPort** | ||
| - `MetricsAPIPort`: Port number for the Metrics API. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,149 @@ | ||
| package cli | ||
|
|
||
| import ( | ||
| "encoding/hex" | ||
| "fmt" | ||
| "log" | ||
| "math/big" | ||
| "os" | ||
| "strings" | ||
|
|
||
| ethcommon "github.com/ethereum/go-ethereum/common" | ||
| "github.com/spf13/cobra" | ||
| spectypes "github.com/ssvlabs/ssv-spec/types" | ||
| "gopkg.in/yaml.v3" | ||
|
|
||
| "github.com/ssvlabs/ssv/networkconfig" | ||
| ) | ||
|
|
||
| const ( | ||
| defaultOutputPath = "./config/config.local.yaml" | ||
| defaultLogLevel = "info" | ||
| defaultDBPath = "./data/db" | ||
| defaultDiscovery = "mdns" | ||
| sliceSeparator = "," | ||
| configFilePermissions = 0644 | ||
| ) | ||
|
|
||
| var ( | ||
| defaultNetwork = networkconfig.LocalTestnet | ||
| ) | ||
|
|
||
| var ( | ||
| outputPath string | ||
| logLevel string | ||
| dbPath string | ||
| discovery string | ||
| consensusClient string | ||
| executionClient string | ||
| operatorPrivateKey string | ||
| metricsAPIPort int | ||
| ssvDomain string | ||
| ssvRegistrySyncOffset uint64 | ||
| ssvRegistryContractAddr string | ||
| ssvBootnodes string | ||
| ssvDiscoveryProtocolID string | ||
| ) | ||
|
|
||
| type SSVConfig struct { | ||
| Global struct { | ||
| LogLevel string `yaml:"LogLevel,omitempty"` | ||
| } `yaml:"global,omitempty"` | ||
| DB struct { | ||
| Path string `yaml:"Path,omitempty"` | ||
| } `yaml:"db,omitempty"` | ||
| ConsensusClient struct { | ||
| Address string `yaml:"BeaconNodeAddr,omitempty"` | ||
| } `yaml:"eth2,omitempty"` | ||
| ExecutionClient struct { | ||
| Address string `yaml:"ETH1Addr,omitempty"` | ||
| } `yaml:"eth1,omitempty"` | ||
| P2P struct { | ||
| Discovery string `yaml:"Discovery,omitempty"` | ||
| } `yaml:"p2p,omitempty"` | ||
| SSV struct { | ||
| NetworkName string `yaml:"Network,omitempty" env:"NETWORK" env-description:"Network is the network of this node,omitempty"` | ||
| CustomNetwork *networkconfig.SSVConfig `yaml:"CustomNetwork,omitempty" env:"CUSTOM_NETWORK" env-description:"Custom network parameters,omitempty"` | ||
| } `yaml:"ssv,omitempty"` | ||
| OperatorPrivateKey string `yaml:"OperatorPrivateKey,omitempty"` | ||
| MetricsAPIPort int `yaml:"MetricsAPIPort,omitempty"` | ||
| } | ||
|
|
||
| // generateConfigCmd is the command to generate ssv operator config. | ||
| var generateConfigCmd = &cobra.Command{ | ||
| Use: "generate-config", | ||
| Short: "generates ssv operator config", | ||
| Run: func(cmd *cobra.Command, args []string) { | ||
| parsedDomain, err := hex.DecodeString(strings.TrimPrefix(ssvDomain, "0x")) | ||
| if err != nil { | ||
| log.Fatalf("Failed to decode network domain: %v", err) | ||
| } | ||
|
|
||
| parsedDiscoveryProtocolID, err := hex.DecodeString(strings.TrimPrefix(ssvDiscoveryProtocolID, "0x")) | ||
| if err != nil { | ||
| log.Fatalf("Failed to decode discovery protocol ID: %v", err) | ||
| } | ||
|
|
||
| var parsedDiscoveryProtocolIDArr [6]byte | ||
| if len(parsedDiscoveryProtocolID) != 0 { | ||
| parsedDiscoveryProtocolIDArr = [6]byte(parsedDiscoveryProtocolID) | ||
| } | ||
|
|
||
| var bootnodes []string | ||
| if ssvBootnodes != "" { | ||
| bootnodes = strings.Split(ssvBootnodes, sliceSeparator) | ||
| } | ||
|
|
||
| var config SSVConfig | ||
| config.Global.LogLevel = logLevel | ||
| config.DB.Path = dbPath | ||
| config.ConsensusClient.Address = consensusClient | ||
| config.ExecutionClient.Address = executionClient | ||
| config.P2P.Discovery = discovery | ||
| config.OperatorPrivateKey = operatorPrivateKey | ||
| config.MetricsAPIPort = metricsAPIPort | ||
| config.SSV.CustomNetwork = &networkconfig.SSVConfig{ | ||
| DomainType: spectypes.DomainType(parsedDomain), | ||
| RegistrySyncOffset: new(big.Int).SetUint64(ssvRegistrySyncOffset), | ||
| RegistryContractAddr: ethcommon.HexToAddress(ssvRegistryContractAddr), | ||
| Bootnodes: bootnodes, | ||
| DiscoveryProtocolID: parsedDiscoveryProtocolIDArr, | ||
| } | ||
|
|
||
| data, err := yaml.Marshal(&config) | ||
| if err != nil { | ||
| log.Fatalf("Failed to marshal YAML: %v", err) | ||
| } | ||
|
|
||
| err = os.WriteFile(outputPath, data, configFilePermissions) | ||
| if err != nil { | ||
| log.Fatalf("Failed to write file: %v", err) | ||
| } | ||
|
|
||
| log.Printf("Saved config into '%s':", outputPath) | ||
| fmt.Println(string(data)) | ||
| }, | ||
| } | ||
|
|
||
| func init() { | ||
| generateConfigCmd.Flags().StringVarP(&outputPath, "output-path", "o", defaultOutputPath, "Output path for generated config") | ||
| generateConfigCmd.Flags().StringVar(&logLevel, "log-level", defaultLogLevel, "Log level") | ||
| generateConfigCmd.Flags().StringVar(&dbPath, "db-path", defaultDBPath, "DB path") | ||
| generateConfigCmd.Flags().StringVar(&discovery, "discovery", defaultDiscovery, "Discovery") | ||
| generateConfigCmd.Flags().StringVar(&consensusClient, "consensus-client", "", "Consensus client (required)") | ||
| _ = generateConfigCmd.MarkFlagRequired("consensus-client") | ||
| generateConfigCmd.Flags().StringVar(&executionClient, "execution-client", "", "Execution client (required)") | ||
| _ = generateConfigCmd.MarkFlagRequired("execution-client") | ||
| generateConfigCmd.Flags().StringVar(&operatorPrivateKey, "operator-private-key", "", "Secret key") | ||
| generateConfigCmd.Flags().IntVar(&metricsAPIPort, "metrics-api-port", 0, "Metrics API port") | ||
|
|
||
| ssvDomainDefault := "0x" + hex.EncodeToString(defaultNetwork.DomainType[:]) | ||
| generateConfigCmd.Flags().StringVar(&ssvDomain, "ssv-domain", ssvDomainDefault, "SSV domain type") | ||
| generateConfigCmd.Flags().Uint64Var(&ssvRegistrySyncOffset, "ssv-registry-sync-offset", defaultNetwork.RegistrySyncOffset.Uint64(), "SSV registry sync offset") | ||
| generateConfigCmd.Flags().StringVar(&ssvRegistryContractAddr, "ssv-registry-contract-addr", defaultNetwork.RegistryContractAddr.String(), "SSV registry contract addr") | ||
| generateConfigCmd.Flags().StringVar(&ssvBootnodes, "ssv-bootnodes", strings.Join(defaultNetwork.Bootnodes, sliceSeparator), "SSV bootnodes (comma-separated)") | ||
| ssvDiscoveryProtocolIDDefault := "0x" + hex.EncodeToString(defaultNetwork.DiscoveryProtocolID[:]) | ||
| generateConfigCmd.Flags().StringVar(&ssvDiscoveryProtocolID, "ssv-discovery-protocol-id", ssvDiscoveryProtocolIDDefault, "SSV discovery protocol ID") | ||
|
|
||
| RootCmd.AddCommand(generateConfigCmd) | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.