Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 13 additions & 4 deletions config.example.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand All @@ -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)
Expand All @@ -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"

Expand Down
30 changes: 19 additions & 11 deletions crates/cli/src/docker_init.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
},
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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()
}
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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",
Expand Down Expand Up @@ -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!(
Expand All @@ -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),
Expand All @@ -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");
}

Expand Down
1 change: 1 addition & 0 deletions crates/common/src/commit/request.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
}
Expand Down
44 changes: 26 additions & 18 deletions crates/common/src/config/signer.rs
Original file line number Diff line number Diff line change
@@ -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,
Expand All @@ -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<ProxyStore>,
#[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<ProxyStore>,
},
/// Remote signer module with compatible API
Remote {
/// Complete url of the base API endpoint
url: Url,
},
}

fn default_signer() -> String {
Expand All @@ -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"),
}
}
}
30 changes: 21 additions & 9 deletions docs/docs/get_started/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -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:

<details>
<summary>Lighthouse</summary>
Expand All @@ -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"
Expand All @@ -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"
Expand All @@ -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"
Expand All @@ -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"
Expand All @@ -140,6 +142,16 @@ We currently support Lighthouse, Prysm, Teku and Lodestar's keystores so it's ea
:::
</details>

### 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:
Expand Down
Loading