From d476fa8978553fbf412c723cf952543a0bcc29c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20I=C3=B1aki=20Bilbao?= Date: Tue, 3 Dec 2024 16:19:43 -0300 Subject: [PATCH 1/5] Add Remote signer config option --- crates/cli/src/docker_init.rs | 32 +++++++++++++--------- crates/common/src/commit/request.rs | 1 + crates/common/src/config/signer.rs | 41 +++++++++++++++++------------ 3 files changed, 45 insertions(+), 29 deletions(-) diff --git a/crates/cli/src/docker_init.rs b/crates/cli/src/docker_init.rs index e82858c6..486c7a08 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 + } else { + &format!("http://cb_signer:{signer_port}") + }; let builder_events_port = 30000; let mut builder_events_modules = Vec::new(); @@ -108,7 +112,7 @@ pub fn handle_docker_init(config_path: String, output_dir: String) -> Result<()> get_env_val(MODULE_ID_ENV, &module.id), get_env_val(CONFIG_ENV, CONFIG_DEFAULT), get_env_interp(MODULE_JWT_ENV, &jwt_name), - get_env_val(SIGNER_URL_ENV, &signer_server), + get_env_val(SIGNER_URL_ENV, signer_server), ]); // Pass on the env variables @@ -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..fc2a04e9 100644 --- a/crates/common/src/config/signer.rs +++ b/crates/common/src/config/signer.rs @@ -13,14 +13,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: String, + }, } fn default_signer() -> String { @@ -43,14 +52,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 { .. }) => Err(eyre::eyre!("Remote signer configured")), + None => Err(eyre::eyre!("Signer config is missing")), + } } } From 01beacfa4774fd4d3d02a286e717cdb634972f7a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20I=C3=B1aki=20Bilbao?= Date: Tue, 3 Dec 2024 16:39:58 -0300 Subject: [PATCH 2/5] Update docs --- docs/docs/get_started/configuration.md | 30 ++++++++++++++++++-------- 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/docs/docs/get_started/configuration.md b/docs/docs/get_started/configuration.md index 53e8b462..04b33c62 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. + +### 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: From c1aa3c9b08b8aca4d245d8ea2e7da56045393859 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20I=C3=B1aki=20Bilbao?= Date: Tue, 3 Dec 2024 16:47:46 -0300 Subject: [PATCH 3/5] Update example config --- config.example.toml | 17 +++++++++++++---- docs/docs/get_started/configuration.md | 2 +- 2 files changed, 14 insertions(+), 5 deletions(-) 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/docs/docs/get_started/configuration.md b/docs/docs/get_started/configuration.md index 04b33c62..12b3a29b 100644 --- a/docs/docs/get_started/configuration.md +++ b/docs/docs/get_started/configuration.md @@ -31,7 +31,7 @@ Note that in this setup, the signer module will not be started. ## Signer module -Commit-Boost supports both local and remote signers. The signer module is responsible for signing the transactions that other modules generates. +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 From b09ab57046c857c709e5ff705a096a0a3fd4a99f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20I=C3=B1aki=20Bilbao?= Date: Thu, 5 Dec 2024 15:37:22 -0300 Subject: [PATCH 4/5] Update crates/common/src/config/signer.rs Co-authored-by: ltitanb <163874448+ltitanb@users.noreply.github.com> --- crates/common/src/config/signer.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/common/src/config/signer.rs b/crates/common/src/config/signer.rs index fc2a04e9..8098602f 100644 --- a/crates/common/src/config/signer.rs +++ b/crates/common/src/config/signer.rs @@ -56,7 +56,7 @@ impl StartSignerConfig { Some(SignerConfig::Local { loader, store, .. }) => { Ok(StartSignerConfig { chain: config.chain, loader, server_port, jwts, store }) } - Some(SignerConfig::Remote { .. }) => Err(eyre::eyre!("Remote signer configured")), + Some(SignerConfig::Remote { .. }) => bail!("Remote signer configured"), None => Err(eyre::eyre!("Signer config is missing")), } } From fd34ef93ae2bf39ad3e7fe651b0f6516cd9552ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20I=C3=B1aki=20Bilbao?= Date: Thu, 5 Dec 2024 15:41:53 -0300 Subject: [PATCH 5/5] Change remote URL type to Url --- crates/cli/src/docker_init.rs | 6 +++--- crates/common/src/config/signer.rs | 7 ++++--- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/crates/cli/src/docker_init.rs b/crates/cli/src/docker_init.rs index 486c7a08..f946cd19 100644 --- a/crates/cli/src/docker_init.rs +++ b/crates/cli/src/docker_init.rs @@ -75,9 +75,9 @@ pub fn handle_docker_init(config_path: String, output_dir: String) -> Result<()> // address for signer API communication let signer_port = 20000; let signer_server = if let Some(SignerConfig::Remote { url }) = &cb_config.signer { - url + url.to_string() } else { - &format!("http://cb_signer:{signer_port}") + format!("http://cb_signer:{signer_port}") }; let builder_events_port = 30000; @@ -112,7 +112,7 @@ pub fn handle_docker_init(config_path: String, output_dir: String) -> Result<()> get_env_val(MODULE_ID_ENV, &module.id), get_env_val(CONFIG_ENV, CONFIG_DEFAULT), get_env_interp(MODULE_JWT_ENV, &jwt_name), - get_env_val(SIGNER_URL_ENV, signer_server), + get_env_val(SIGNER_URL_ENV, &signer_server), ]); // Pass on the env variables diff --git a/crates/common/src/config/signer.rs b/crates/common/src/config/signer.rs index 8098602f..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, @@ -28,7 +29,7 @@ pub enum SignerConfig { /// Remote signer module with compatible API Remote { /// Complete url of the base API endpoint - url: String, + url: Url, }, } @@ -57,7 +58,7 @@ impl StartSignerConfig { Ok(StartSignerConfig { chain: config.chain, loader, server_port, jwts, store }) } Some(SignerConfig::Remote { .. }) => bail!("Remote signer configured"), - None => Err(eyre::eyre!("Signer config is missing")), + None => bail!("Signer config is missing"), } } }