diff --git a/config.example.toml b/config.example.toml index 3199fa18..1d53d522 100644 --- a/config.example.toml +++ b/config.example.toml @@ -105,7 +105,7 @@ frequency_get_header_ms = 300 [[mux]] # Unique ID for the mux config id = "test_mux" -# Which validator pubkeys to match against this mux config. This can be empty or omitted if a loader is specified. +# Which validator pubkeys to match against this mux config. This can be empty or omitted if a loader is specified. # Any keys loaded via the loader will be added to this list. validator_pubkeys = [ "0x80c7f782b2467c5898c5516a8b6595d75623960b4afc4f71ee07d40985d20e117ba35e7cd352a3e75fb85a8668a3b745", @@ -124,15 +124,24 @@ id = "example-relay" headers = { X-MyCustomHeader = "ADifferentCustomValue" } # Configuration for the Signer Module, only required if any `commit` module is present, or if `pbs.with_signer = true` +# Currently two types of Signer modules are supported (only one can be used at a time): +# - Remote: a remote Web3Signer instance +# - Local: a local Signer module +# More details on the docs (https://commit-boost.github.io/commit-boost-client/get_started/configuration/#local-signer) # OPTIONAL -[signer] +# Remote: +# [signer.remote] +# URL of the Web3Signer instance +# url = "https://remote.signer.url" +# Local: +[signer.local] # Docker image to use for the Signer module. # OPTIONAL, DEFAULT: ghcr.io/commit-boost/signer:latest docker_image = "ghcr.io/commit-boost/signer:latest" # Configuration for how the Signer module should load validator keys. Currently two types of loaders are supported: # - File: load keys from a plain text file (unsafe, use only for testing purposes) # - ValidatorsDir: load keys from a `keys` and `secrets` file/folder (ERC-2335 style keystores). More details can be found in the docs (https://commit-boost.github.io/commit-boost-client/get_started/configuration/) -[signer.loader] +[signer.local.loader] # File: path to the keys file key_path = "./keys.example.json" # ValidatorsDir: format of the keystore (lighthouse, prysm, teku or lodestar) @@ -152,7 +161,7 @@ key_path = "./keys.example.json" # Configuration for how the Signer module should store proxy delegations. Currently one type of store is supported: # - File: store keys and delegations from a plain text file (unsafe, use only for testing purposes) # OPTIONAL, if missing proxies are lost on restart -[signer.store] +[signer.local.store] # File: path to the keys file proxy_dir = "./proxies" diff --git a/crates/cli/src/docker_init.rs b/crates/cli/src/docker_init.rs index e82858c6..f946cd19 100644 --- a/crates/cli/src/docker_init.rs +++ b/crates/cli/src/docker_init.rs @@ -6,10 +6,10 @@ use std::{ use cb_common::{ config::{ - CommitBoostConfig, LogsSettings, ModuleKind, BUILDER_PORT_ENV, BUILDER_URLS_ENV, - CHAIN_SPEC_ENV, CONFIG_DEFAULT, CONFIG_ENV, JWTS_ENV, LOGS_DIR_DEFAULT, LOGS_DIR_ENV, - METRICS_PORT_ENV, MODULE_ID_ENV, MODULE_JWT_ENV, PBS_ENDPOINT_ENV, PBS_MODULE_NAME, - PROXY_DIR_DEFAULT, PROXY_DIR_ENV, SIGNER_DEFAULT, SIGNER_DIR_KEYS_DEFAULT, + CommitBoostConfig, LogsSettings, ModuleKind, SignerConfig, BUILDER_PORT_ENV, + BUILDER_URLS_ENV, CHAIN_SPEC_ENV, CONFIG_DEFAULT, CONFIG_ENV, JWTS_ENV, LOGS_DIR_DEFAULT, + LOGS_DIR_ENV, METRICS_PORT_ENV, MODULE_ID_ENV, MODULE_JWT_ENV, PBS_ENDPOINT_ENV, + PBS_MODULE_NAME, PROXY_DIR_DEFAULT, PROXY_DIR_ENV, SIGNER_DEFAULT, SIGNER_DIR_KEYS_DEFAULT, SIGNER_DIR_KEYS_ENV, SIGNER_DIR_SECRETS_DEFAULT, SIGNER_DIR_SECRETS_ENV, SIGNER_KEYS_ENV, SIGNER_MODULE_NAME, SIGNER_PORT_ENV, SIGNER_URL_ENV, }, @@ -74,7 +74,11 @@ pub fn handle_docker_init(config_path: String, output_dir: String) -> Result<()> // address for signer API communication let signer_port = 20000; - let signer_server = format!("http://cb_signer:{signer_port}"); + let signer_server = if let Some(SignerConfig::Remote { url }) = &cb_config.signer { + url.to_string() + } else { + format!("http://cb_signer:{signer_port}") + }; let builder_events_port = 30000; let mut builder_events_modules = Vec::new(); @@ -153,7 +157,11 @@ pub fn handle_docker_init(config_path: String, output_dir: String) -> Result<()> networks: Networks::Simple(module_networks), volumes: module_volumes, environment: Environment::KvPair(module_envs), - depends_on: DependsOnOptions::Simple(vec!["cb_signer".to_owned()]), + depends_on: if let Some(SignerConfig::Remote { .. }) = &cb_config.signer { + DependsOnOptions::Simple(vec![]) + } else { + DependsOnOptions::Simple(vec!["cb_signer".to_owned()]) + }, env_file, ..Service::default() } @@ -285,7 +293,7 @@ pub fn handle_docker_init(config_path: String, output_dir: String) -> Result<()> services.insert("cb_pbs".to_owned(), Some(pbs_service)); // setup signer service - if let Some(signer_config) = cb_config.signer { + if let Some(SignerConfig::Local { docker_image, loader, store }) = cb_config.signer { if needs_signer_module { if metrics_enabled { targets.push(PrometheusTargetConfig { @@ -319,7 +327,7 @@ pub fn handle_docker_init(config_path: String, output_dir: String) -> Result<()> let mut volumes = vec![config_volume.clone()]; volumes.extend(chain_spec_volume.clone()); - match signer_config.loader { + match loader { SignerLoader::File { key_path } => { volumes.push(Volumes::Simple(format!( "{}:{}:ro", @@ -348,7 +356,7 @@ pub fn handle_docker_init(config_path: String, output_dir: String) -> Result<()> } }; - if let Some(store) = signer_config.store { + if let Some(store) = store { match store { ProxyStore::File { proxy_dir } => { volumes.push(Volumes::Simple(format!( @@ -372,7 +380,7 @@ pub fn handle_docker_init(config_path: String, output_dir: String) -> Result<()> let signer_service = Service { container_name: Some("cb_signer".to_owned()), - image: Some(signer_config.docker_image), + image: Some(docker_image), networks: Networks::Simple(signer_networks), volumes, environment: Environment::KvPair(signer_envs), @@ -381,7 +389,7 @@ pub fn handle_docker_init(config_path: String, output_dir: String) -> Result<()> services.insert("cb_signer".to_owned(), Some(signer_service)); } - } else if needs_signer_module { + } else if cb_config.signer.is_none() && needs_signer_module { panic!("Signer module required but no signer config provided"); } diff --git a/crates/common/src/commit/request.rs b/crates/common/src/commit/request.rs index f2adeba2..f3b056ee 100644 --- a/crates/common/src/commit/request.rs +++ b/crates/common/src/commit/request.rs @@ -136,6 +136,7 @@ pub enum EncryptionScheme { // TODO(David): This struct shouldn't be visible to module authors #[derive(Debug, Clone, Serialize, Deserialize)] pub struct GenerateProxyRequest { + #[serde(rename = "pubkey")] pub consensus_pubkey: BlsPublicKey, pub scheme: EncryptionScheme, } diff --git a/crates/common/src/config/signer.rs b/crates/common/src/config/signer.rs index ab630d5d..6f38a800 100644 --- a/crates/common/src/config/signer.rs +++ b/crates/common/src/config/signer.rs @@ -1,6 +1,7 @@ use bimap::BiHashMap; -use eyre::Result; +use eyre::{bail, Result}; use serde::{Deserialize, Serialize}; +use url::Url; use super::{ constants::SIGNER_IMAGE_DEFAULT, @@ -13,14 +14,23 @@ use crate::{ }; #[derive(Debug, Serialize, Deserialize, Clone)] -pub struct SignerConfig { - /// Docker image of the module - #[serde(default = "default_signer")] - pub docker_image: String, - /// Which keys to load - pub loader: SignerLoader, - /// How to store keys - pub store: Option, +#[serde(rename_all = "snake_case")] +pub enum SignerConfig { + /// Local signer module + Local { + /// Docker image of the module + #[serde(default = "default_signer")] + docker_image: String, + /// Which keys to load + loader: SignerLoader, + /// How to store keys + store: Option, + }, + /// Remote signer module with compatible API + Remote { + /// Complete url of the base API endpoint + url: Url, + }, } fn default_signer() -> String { @@ -43,14 +53,12 @@ impl StartSignerConfig { let jwts = load_jwts()?; let server_port = load_env_var(SIGNER_PORT_ENV)?.parse()?; - let signer_config = config.signer.expect("Signer config is missing"); - - Ok(StartSignerConfig { - chain: config.chain, - loader: signer_config.loader, - server_port, - jwts, - store: signer_config.store, - }) + match config.signer { + Some(SignerConfig::Local { loader, store, .. }) => { + Ok(StartSignerConfig { chain: config.chain, loader, server_port, jwts, store }) + } + Some(SignerConfig::Remote { .. }) => bail!("Remote signer configured"), + None => bail!("Signer config is missing"), + } } } diff --git a/docs/docs/get_started/configuration.md b/docs/docs/get_started/configuration.md index 53e8b462..12b3a29b 100644 --- a/docs/docs/get_started/configuration.md +++ b/docs/docs/get_started/configuration.md @@ -31,17 +31,20 @@ Note that in this setup, the signer module will not be started. ## Signer module -To start the signer module, you need to include its parameters in the config file: +Commit-Boost supports both local and remote signers. The signer module is responsible for signing the transactions that other modules generates. Please note that only one signer at a time is allowed. + +### Local signer + +To start a local signer module, you need to include its parameters in the config file ```toml -[signer] -[signer.loader] +[signer.local.loader] format = "lighthouse" keys_path = "/path/to/keys" secrets_path = "/path/to.secrets" ``` -We currently support Lighthouse, Prysm, Teku and Lodestar's keystores so it's easier to load the keys. We're working on adding support for additional keystores, including remote signers. These are the expected file structures for each format: +We currently support Lighthouse, Prysm, Teku and Lodestar's keystores so it's easier to load the keys. We're working on adding support for additional keystores. These are the expected file structures for each format:
Lighthouse @@ -61,7 +64,7 @@ We currently support Lighthouse, Prysm, Teku and Lodestar's keystores so it's ea #### Config: ```toml [signer] - [signer.loader] + [signer.local.loader] format = "lighthouse" keys_path = "keys" secrets_path = "secrets" @@ -84,7 +87,7 @@ We currently support Lighthouse, Prysm, Teku and Lodestar's keystores so it's ea #### Config: ```toml [signer] - [signer.loader] + [signer.local.loader] format = "prysm" keys_path = "wallet/direct/accounts/all-accounts.keystore.json" secrets_path = "secrets/password.txt" @@ -107,7 +110,7 @@ We currently support Lighthouse, Prysm, Teku and Lodestar's keystores so it's ea #### Config: ```toml [signer] - [signer.loader] + [signer.local.loader] format = "teku" keys_path = "keys" secrets_path = "secrets" @@ -128,8 +131,7 @@ We currently support Lighthouse, Prysm, Teku and Lodestar's keystores so it's ea #### Config: ```toml - [signer] - [signer.loader] + [signer.local.loader] format = "lodestar" keys_path = "keys" secrets_path = "secrets/password.txt" @@ -140,6 +142,16 @@ We currently support Lighthouse, Prysm, Teku and Lodestar's keystores so it's ea :::
+### Remote signer + +You might choose to use an external service to sign the transactions. For now, we support Web3Signer but we're working on adding support for additional signers. + +The parameters needed for the remote signer are: + +```toml +[signer.remote] +url = "https://remote.signer.url" +``` ## Custom module We currently provide a test module that needs to be built locally. To build the module run: