Skip to content
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

feat: add binary support #117

Merged
merged 6 commits into from
Sep 13, 2024
Merged
Show file tree
Hide file tree
Changes from 5 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
2 changes: 1 addition & 1 deletion bin/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ pub mod prelude {
},
config::{
load_builder_module_config, load_commit_module_config, load_pbs_config,
load_pbs_custom_config, StartCommitModuleConfig,
load_pbs_custom_config, LogsSettings, StartCommitModuleConfig,
},
pbs::{BuilderEvent, BuilderEventClient, OnBuilderApiEvent},
signer::{BlsPublicKey, BlsSignature, EcdsaPublicKey, EcdsaSignature},
Expand Down
109 changes: 59 additions & 50 deletions crates/cli/src/docker_init.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,14 @@ use std::{path::Path, vec};

use cb_common::{
config::{
CommitBoostConfig, LogsSettings, ModuleKind, BUILDER_SERVER_ENV, CB_BASE_LOG_PATH,
CB_CONFIG_ENV, CB_CONFIG_NAME, JWTS_ENV, MAX_LOG_FILES_ENV, METRICS_SERVER_ENV,
MODULE_ID_ENV, MODULE_JWT_ENV, PBS_MODULE_NAME, RUST_LOG_ENV, SIGNER_DIR_KEYS,
SIGNER_DIR_KEYS_ENV, SIGNER_DIR_SECRETS, SIGNER_DIR_SECRETS_ENV, SIGNER_KEYS,
SIGNER_KEYS_ENV, SIGNER_MODULE_NAME, SIGNER_SERVER_ENV, USE_FILE_LOGS_ENV,
CommitBoostConfig, LogsSettings, ModuleKind, BUILDER_PORT_ENV, BUILDER_URLS_ENV,
CONFIG_DEFAULT, CONFIG_ENV, JWTS_ENV, LOGS_DIR_DEFAULT, LOGS_DIR_ENV, METRICS_PORT_ENV,
MODULE_ID_ENV, MODULE_JWT_ENV, PBS_MODULE_NAME, SIGNER_DEFAULT, SIGNER_DIR_KEYS_DEFAULT,
SIGNER_DIR_KEYS_ENV, SIGNER_DIR_SECRETS, SIGNER_DIR_SECRETS_ENV, SIGNER_KEYS_ENV,
SIGNER_MODULE_NAME, SIGNER_PORT_ENV, SIGNER_URL_ENV,
},
loader::SignerLoader,
types::ModuleId,
utils::random_jwt,
};
use docker_compose_types::{
Expand Down Expand Up @@ -38,26 +39,13 @@ pub fn handle_docker_init(config_path: String, output_dir: String) -> Result<()>
let cb_config = CommitBoostConfig::from_file(&config_path)?;

let metrics_enabled = cb_config.metrics.is_some();

// Logging
let logging_envs = if let Some(log_config) = &cb_config.logs {
let mut envs = vec![
get_env_bool(USE_FILE_LOGS_ENV, true),
get_env_val(RUST_LOG_ENV, &log_config.log_level),
];
if let Some(max_files) = log_config.max_log_files {
envs.push(get_env_uval(MAX_LOG_FILES_ENV, max_files as u64))
}
envs
} else {
vec![]
};
let log_to_file = cb_config.logs.is_some();

let mut services = IndexMap::new();
let mut volumes = IndexMap::new();

// config volume to pass to all services
let config_volume = Volumes::Simple(format!("./{}:{}:ro", config_path, CB_CONFIG_NAME));
let config_volume = Volumes::Simple(format!("./{}:{}:ro", config_path, CONFIG_DEFAULT));

let mut jwts = IndexMap::new();
// envs to write in .env file
Expand All @@ -69,7 +57,7 @@ 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!("cb_signer:{signer_port}");
let signer_server = format!("http://cb_signer:{signer_port}");

let builder_events_port = 30000;
let mut builder_events_modules = Vec::new();
Expand Down Expand Up @@ -102,9 +90,9 @@ pub fn handle_docker_init(config_path: String, output_dir: String) -> Result<()>
// module ids are assumed unique, so envs dont override each other
let mut module_envs = IndexMap::from([
get_env_val(MODULE_ID_ENV, &module.id),
get_env_val(CB_CONFIG_ENV, CB_CONFIG_NAME),
get_env_val(CONFIG_ENV, CONFIG_DEFAULT),
get_env_interp(MODULE_JWT_ENV, &jwt_name),
get_env_val(SIGNER_SERVER_ENV, &signer_server),
get_env_val(SIGNER_URL_ENV, &signer_server),
]);

// Pass on the env variables
Expand All @@ -118,10 +106,13 @@ pub fn handle_docker_init(config_path: String, output_dir: String) -> Result<()>
let env_file = module.env_file.map(EnvFile::Simple);

if metrics_enabled {
let (key, val) = get_env_uval(METRICS_SERVER_ENV, metrics_port as u64);
let (key, val) = get_env_uval(METRICS_PORT_ENV, metrics_port as u64);
module_envs.insert(key, val);
}
if log_to_file {
let (key, val) = get_env_val(LOGS_DIR_ENV, LOGS_DIR_DEFAULT);
module_envs.insert(key, val);
}
module_envs.extend(logging_envs.clone());

envs.insert(jwt_name.clone(), jwt.clone());
jwts.insert(module.id.clone(), jwt);
Expand Down Expand Up @@ -150,18 +141,22 @@ pub fn handle_docker_init(config_path: String, output_dir: String) -> Result<()>
}
// an event module just needs a port to listen on
ModuleKind::Events => {
builder_events_modules.push(format!("{module_cid}:{builder_events_port}"));
builder_events_modules
.push(format!("http://{module_cid}:{builder_events_port}"));

// module ids are assumed unique, so envs dont override each other
let mut module_envs = IndexMap::from([
get_env_val(MODULE_ID_ENV, &module.id),
get_env_val(CB_CONFIG_ENV, CB_CONFIG_NAME),
get_env_val(BUILDER_SERVER_ENV, &builder_events_port.to_string()),
get_env_val(CONFIG_ENV, CONFIG_DEFAULT),
get_env_uval(BUILDER_PORT_ENV, builder_events_port),
]);
module_envs.extend(logging_envs.clone());

if metrics_enabled {
let (key, val) = get_env_uval(METRICS_SERVER_ENV, metrics_port as u64);
let (key, val) = get_env_uval(METRICS_PORT_ENV, metrics_port as u64);
module_envs.insert(key, val);
}
if log_to_file {
let (key, val) = get_env_val(LOGS_DIR_ENV, LOGS_DIR_DEFAULT);
module_envs.insert(key, val);
}

Expand Down Expand Up @@ -200,16 +195,19 @@ pub fn handle_docker_init(config_path: String, output_dir: String) -> Result<()>
});
}

let mut pbs_envs = IndexMap::from([get_env_val(CB_CONFIG_ENV, CB_CONFIG_NAME)]);
pbs_envs.extend(logging_envs.clone());
let mut pbs_envs = IndexMap::from([get_env_val(CONFIG_ENV, CONFIG_DEFAULT)]);

if metrics_enabled {
let (key, val) = get_env_uval(METRICS_SERVER_ENV, metrics_port as u64);
let (key, val) = get_env_uval(METRICS_PORT_ENV, metrics_port as u64);
pbs_envs.insert(key, val);
}
if log_to_file {
let (key, val) = get_env_val(LOGS_DIR_ENV, LOGS_DIR_DEFAULT);
pbs_envs.insert(key, val);
}

if !builder_events_modules.is_empty() {
let env = builder_events_modules.join(",");
let (k, v) = get_env_val(BUILDER_SERVER_ENV, &env);
let (k, v) = get_env_val(BUILDER_URLS_ENV, &env);
pbs_envs.insert(k, v);
}

Expand Down Expand Up @@ -253,33 +251,39 @@ pub fn handle_docker_init(config_path: String, output_dir: String) -> Result<()>
}

let mut signer_envs = IndexMap::from([
get_env_val(CB_CONFIG_ENV, CB_CONFIG_NAME),
get_env_val(CONFIG_ENV, CONFIG_DEFAULT),
get_env_same(JWTS_ENV),
get_env_uval(SIGNER_SERVER_ENV, signer_port as u64),
get_env_uval(SIGNER_PORT_ENV, signer_port as u64),
]);
signer_envs.extend(logging_envs);

if metrics_enabled {
let (key, val) = get_env_uval(METRICS_SERVER_ENV, metrics_port as u64);
let (key, val) = get_env_uval(METRICS_PORT_ENV, metrics_port as u64);
signer_envs.insert(key, val);
}
if log_to_file {
let (key, val) = get_env_val(LOGS_DIR_ENV, LOGS_DIR_DEFAULT);
signer_envs.insert(key, val);
}

// write jwts to env
let jwts_json = serde_json::to_string(&jwts).unwrap().clone();
envs.insert(JWTS_ENV.into(), format!("{jwts_json:?}"));
envs.insert(JWTS_ENV.into(), format_comma_separated(&jwts));

// volumes
let mut volumes = vec![config_volume.clone()];

// TODO: generalize this, different loaders may not need volumes but eg ports
match signer_config.loader {
SignerLoader::File { key_path } => {
volumes.push(Volumes::Simple(format!("./{}:{}:ro", key_path, SIGNER_KEYS)));
let (k, v) = get_env_val(SIGNER_KEYS_ENV, SIGNER_KEYS);
volumes.push(Volumes::Simple(format!("./{}:{}:ro", key_path, SIGNER_DEFAULT)));
let (k, v) = get_env_val(SIGNER_KEYS_ENV, SIGNER_DEFAULT);
signer_envs.insert(k, v);
}
SignerLoader::ValidatorsDir { keys_path, secrets_path } => {
volumes.push(Volumes::Simple(format!("{}:{}:ro", keys_path, SIGNER_DIR_KEYS)));
let (k, v) = get_env_val(SIGNER_DIR_KEYS_ENV, SIGNER_DIR_KEYS);
volumes.push(Volumes::Simple(format!(
"{}:{}:ro",
keys_path, SIGNER_DIR_KEYS_DEFAULT
)));
let (k, v) = get_env_val(SIGNER_DIR_KEYS_ENV, SIGNER_DIR_KEYS_DEFAULT);
signer_envs.insert(k, v);

volumes.push(Volumes::Simple(format!(
Expand Down Expand Up @@ -513,9 +517,9 @@ fn get_env_uval(k: &str, v: u64) -> (String, Option<SingleValue>) {
(k.into(), Some(SingleValue::Unsigned(v)))
}

fn get_env_bool(k: &str, v: bool) -> (String, Option<SingleValue>) {
(k.into(), Some(SingleValue::Bool(v)))
}
// fn get_env_bool(k: &str, v: bool) -> (String, Option<SingleValue>) {
// (k.into(), Some(SingleValue::Bool(v)))
// }

/// A prometheus target, use to dynamically add targets to the prometheus config
#[derive(Debug, Serialize)]
Expand All @@ -531,11 +535,16 @@ struct PrometheusLabelsConfig {

fn get_log_volume(maybe_config: &Option<LogsSettings>, module_id: &str) -> Option<Volumes> {
maybe_config.as_ref().map(|config| {
let p = config.log_dir_path.join(module_id);
let p = config.log_dir_path.join(module_id.to_lowercase());
Volumes::Simple(format!(
"{}:{}",
p.to_str().expect("could not convert pathbuf to str"),
CB_BASE_LOG_PATH
LOGS_DIR_DEFAULT
))
})
}

/// Formats as a comma separated list of key=value
fn format_comma_separated(map: &IndexMap<ModuleId, String>) -> String {
map.iter().map(|(k, v)| format!("{}={}", k, v)).collect::<Vec<_>>().join(",")
}
8 changes: 4 additions & 4 deletions crates/common/src/commit/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use alloy::rpc::types::beacon::BlsSignature;
use eyre::WrapErr;
use reqwest::header::{HeaderMap, HeaderValue, AUTHORIZATION};
use serde::Deserialize;
use url::Url;

use super::{
constants::{GENERATE_PROXY_KEY_PATH, GET_PUBKEYS_PATH, REQUEST_SIGNATURE_PATH},
Expand All @@ -25,14 +26,13 @@ use crate::{
#[derive(Debug, Clone)]
pub struct SignerClient {
/// Url endpoint of the Signer Module
url: Arc<String>,
url: Arc<Url>,
client: reqwest::Client,
}

impl SignerClient {
/// Create a new SignerClient
pub fn new(signer_server_address: String, jwt: &str) -> eyre::Result<Self> {
let url = format!("http://{}", signer_server_address);
pub fn new(signer_server_url: Url, jwt: &str) -> eyre::Result<Self> {
let mut headers = HeaderMap::new();

let mut auth_value =
Expand All @@ -44,7 +44,7 @@ impl SignerClient {
.default_headers(headers)
.build()?;

Ok(Self { url: url.into(), client })
Ok(Self { url: signer_server_url.into(), client })
}

/// Request a list of validator pubkeys for which signatures can be
Expand Down
76 changes: 51 additions & 25 deletions crates/common/src/config/constants.rs
Original file line number Diff line number Diff line change
@@ -1,30 +1,56 @@
pub const MODULE_ID_ENV: &str = "CB_MODULE_ID";
pub const MODULE_JWT_ENV: &str = "CB_SIGNER_JWT";
pub const METRICS_SERVER_ENV: &str = "METRICS_SERVER";
pub const SIGNER_SERVER_ENV: &str = "SIGNER_SERVER";
pub const BUILDER_SERVER_ENV: &str = "BUILDER_SERVER";
pub const MAX_LOG_FILES_ENV: &str = "MAX_LOG_FILES";
pub const RUST_LOG_ENV: &str = "RUST_LOG";
pub const USE_FILE_LOGS_ENV: &str = "USE_FILE_LOGS";

pub const CB_BASE_LOG_PATH: &str = "/var/logs/commit-boost";

pub const CB_CONFIG_ENV: &str = "CB_CONFIG";
pub const CB_CONFIG_NAME: &str = "/cb-config.toml";

pub const SIGNER_KEYS_ENV: &str = "CB_SIGNER_FILE";
pub const SIGNER_KEYS: &str = "/keys.json";
pub const SIGNER_DIR_KEYS_ENV: &str = "SIGNER_LOADER_DIR_KEYS";
pub const SIGNER_DIR_KEYS: &str = "/keys";
pub const SIGNER_DIR_SECRETS_ENV: &str = "SIGNER_LOADER_DIR_SECRETS";
pub const SIGNER_DIR_SECRETS: &str = "/secrets";
///////////////////////// COMMMON /////////////////////////

pub const JWTS_ENV: &str = "CB_JWTS";
/// Path to the main toml config file
pub const CONFIG_ENV: &str = "CB_CONFIG";
pub const CONFIG_DEFAULT: &str = "/cb-config.toml";

/// Where to receive scrape requests from Prometheus
pub const METRICS_PORT_ENV: &str = "CB_METRICS_PORT";

// TODO: replace these with an actual image in the registry
pub const PBS_DEFAULT_IMAGE: &str = "ghcr.io/commit-boost/pbs:latest";
pub const SIGNER_IMAGE: &str = "ghcr.io/commit-boost/signer:latest";
/// Path to logs directory
pub const LOGS_DIR_ENV: &str = "CB_LOGS_DIR";
pub const LOGS_DIR_DEFAULT: &str = "/var/logs/commit-boost";

// Module names
///////////////////////// PBS /////////////////////////

pub const PBS_IMAGE_DEFAULT: &str = "ghcr.io/commit-boost/pbs:latest";
pub const PBS_MODULE_NAME: &str = "pbs";

/// Urls the pbs modules should post events to (comma separated)
pub const BUILDER_URLS_ENV: &str = "CB_BUILDER_URLS";

///////////////////////// SIGNER /////////////////////////

pub const SIGNER_IMAGE_DEFAULT: &str = "ghcr.io/commit-boost/signer:latest";
pub const SIGNER_MODULE_NAME: &str = "signer";

/// Where the signer module should open the server
pub const SIGNER_PORT_ENV: &str = "CB_SIGNER_PORT";

/// Comma separated list module_id=jwt_secret
pub const JWTS_ENV: &str = "CB_JWTS";

/// Path to json file with plaintext keys (testing only)
pub const SIGNER_KEYS_ENV: &str = "CB_SIGNER_LOADER_FILE";
pub const SIGNER_DEFAULT: &str = "/keys.json";
/// Path to `keys` folder
pub const SIGNER_DIR_KEYS_ENV: &str = "CB_SIGNER_LOADER_KEYS_DIR";
pub const SIGNER_DIR_KEYS_DEFAULT: &str = "/keys";
/// Path to `secrets` folder
pub const SIGNER_DIR_SECRETS_ENV: &str = "CB_SIGNER_LOADER_SECRETS_DIR";
pub const SIGNER_DIR_SECRETS: &str = "/secrets";

///////////////////////// MODULES /////////////////////////

/// The unique ID of the module
pub const MODULE_ID_ENV: &str = "CB_MODULE_ID";

// Commit modules
/// The JWT secret for the module to communicate with the signer module
pub const MODULE_JWT_ENV: &str = "CB_SIGNER_JWT";
/// Where to send signature request
pub const SIGNER_URL_ENV: &str = "CB_SIGNER_URL";

/// Events modules
/// Where to receive builder events
pub const BUILDER_PORT_ENV: &str = "CB_BUILDER_PORT";
30 changes: 28 additions & 2 deletions crates/common/src/config/log.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
use std::path::PathBuf;

use eyre::Result;
use serde::{Deserialize, Serialize};

use super::CB_BASE_LOG_PATH;
use super::{load_optional_env_var, CommitBoostConfig, LOGS_DIR_DEFAULT, LOGS_DIR_ENV};

#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct LogsSettings {
Expand All @@ -14,8 +15,33 @@ pub struct LogsSettings {
pub max_log_files: Option<usize>,
}

impl Default for LogsSettings {
fn default() -> Self {
LogsSettings {
log_dir_path: default_log_dir_path(),
log_level: default_log_level(),
max_log_files: None,
}
}
}

impl LogsSettings {
pub fn from_env_config() -> Result<Option<Self>> {
let mut config = CommitBoostConfig::from_env_path()?;

// Override log dir path if env var is set
if let Some(log_config) = config.logs.as_mut() {
if let Some(log_dir) = load_optional_env_var(LOGS_DIR_ENV) {
log_config.log_dir_path = log_dir.into();
}
}

Ok(config.logs)
}
}

fn default_log_dir_path() -> PathBuf {
CB_BASE_LOG_PATH.into()
LOGS_DIR_DEFAULT.into()
}

pub fn default_log_level() -> String {
Expand Down
Loading
Loading