Skip to content

Commit

Permalink
error handling (#45)
Browse files Browse the repository at this point in the history
* better error handling

---------

Co-authored-by: fbrv <[email protected]>
  • Loading branch information
fbrv and fbrv authored Aug 1, 2024
1 parent bb7cb29 commit 90cafdf
Show file tree
Hide file tree
Showing 28 changed files with 233 additions and 138 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ bollard = "0.16.1"
# misc
clap = { version = "4.5.4", features = ["derive", "env"] }
thiserror = "1.0.61"
color-eyre = "0.6.3"
eyre = "0.6.12"
url = "2.5.0"
uuid = { version = "1.8.0", features = ["v4", "fast-rng", "serde"] }
Expand Down
2 changes: 2 additions & 0 deletions bin/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ tracing-subscriber.workspace = true

# misc
clap.workspace = true
eyre.workspace = true
color-eyre.workspace = true

[[bin]]
name = "commit-boost"
Expand Down
4 changes: 3 additions & 1 deletion bin/commit_boost.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ use clap::Parser;

/// Main entry point of the Commit Boost CLI
#[tokio::main]
async fn main() {
async fn main() -> eyre::Result<()> {
color_eyre::install()?;
// set default backtrace unless provided
if std::env::var_os("RUST_BACKTRACE").is_none() {
std::env::set_var("RUST_BACKTRACE", "1");
Expand All @@ -14,4 +15,5 @@ async fn main() {
eprintln!("Error: {err}");
std::process::exit(1)
};
Ok(())
}
8 changes: 6 additions & 2 deletions bin/default_pbs.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
use cb_common::{config::load_pbs_config, utils::initialize_tracing_log};
use cb_pbs::{DefaultBuilderApi, PbsService, PbsState};
use eyre::Result;

#[tokio::main]
async fn main() {
async fn main() -> Result<()> {
color_eyre::install()?;

// set default backtrace unless provided
if std::env::var_os("RUST_BACKTRACE").is_none() {
std::env::set_var("RUST_BACKTRACE", "1");
Expand All @@ -14,6 +17,7 @@ async fn main() {
let pbs_config = load_pbs_config().expect("failed to load pbs config");
let state = PbsState::<()>::new(pbs_config);

PbsService::init_metrics();
PbsService::init_metrics()?;
PbsService::run::<(), DefaultBuilderApi>(state).await;
Ok(())
}
9 changes: 6 additions & 3 deletions bin/signer_module.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
use cb_common::{config::StartSignerConfig, utils::initialize_tracing_log};
use cb_signer::service::SigningService;
use eyre::Result;

#[tokio::main]
async fn main() {
async fn main() -> Result<()> {
color_eyre::install()?;

// set default backtrace unless provided
if std::env::var_os("RUST_BACKTRACE").is_none() {
std::env::set_var("RUST_BACKTRACE", "1");
}

initialize_tracing_log();

let config = StartSignerConfig::load_from_env();
SigningService::run(config).await;
let config = StartSignerConfig::load_from_env()?;
SigningService::run(config).await
}
8 changes: 5 additions & 3 deletions crates/cli/src/docker_cmd.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
use std::process::{Command, Stdio};

pub fn handle_docker_start(compose_path: String, env_path: String) -> eyre::Result<()> {
use eyre::Result;

pub fn handle_docker_start(compose_path: String, env_path: String) -> Result<()> {
println!("Starting Commit-Boost with compose file: {}", compose_path);

// load env file
Expand All @@ -24,7 +26,7 @@ pub fn handle_docker_start(compose_path: String, env_path: String) -> eyre::Resu
Ok(())
}

pub fn handle_docker_stop(compose_path: String, env_path: String) -> eyre::Result<()> {
pub fn handle_docker_stop(compose_path: String, env_path: String) -> Result<()> {
println!("Stopping Commit-Boost with compose file: {}", compose_path);

// load env file
Expand All @@ -46,7 +48,7 @@ pub fn handle_docker_stop(compose_path: String, env_path: String) -> eyre::Resul
}

// TODO: we shouldnt use docker logs
pub fn handle_docker_logs(compose_path: String) -> eyre::Result<()> {
pub fn handle_docker_logs(compose_path: String) -> Result<()> {
println!("Querying Commit-Boost with compose file: {}", compose_path);

// TODO: if permission denied, print warning to run as sudo
Expand Down
7 changes: 4 additions & 3 deletions crates/cli/src/docker_init.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ use docker_compose_types::{
Compose, DependsOnOptions, Environment, LoggingParameters, MapOrEmpty, NetworkSettings,
Networks, Ports, Service, Services, SingleValue, Volumes,
};
use eyre::Result;
use indexmap::IndexMap;
use serde::Serialize;

Expand All @@ -28,10 +29,10 @@ const SIGNER_NETWORK: &str = "signer_network";

// TODO: do more validation for paths, images, etc
#[allow(unused_assignments)]
pub fn handle_docker_init(config_path: String, output_dir: String) -> eyre::Result<()> {
pub fn handle_docker_init(config_path: String, output_dir: String) -> Result<()> {
println!("Initializing Commit-Boost with config file: {}", config_path);

let cb_config = CommitBoostConfig::from_file(&config_path);
let cb_config = CommitBoostConfig::from_file(&config_path)?;

let mut services = IndexMap::new();

Expand Down Expand Up @@ -158,7 +159,7 @@ pub fn handle_docker_init(config_path: String, output_dir: String) -> eyre::Resu
};

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

let signer_service = Service {
Expand Down
10 changes: 5 additions & 5 deletions crates/common/src/commit/client.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use std::sync::Arc;

use alloy::rpc::types::beacon::{BlsPublicKey, BlsSignature};
use eyre::WrapErr;
use reqwest::header::{HeaderMap, HeaderValue, AUTHORIZATION};
use serde::{Deserialize, Serialize};

Expand All @@ -27,21 +28,20 @@ pub struct SignerClient {

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

let mut auth_value =
HeaderValue::from_str(&format!("Bearer {}", jwt)).expect("invalid jwt");
HeaderValue::from_str(&format!("Bearer {}", jwt)).wrap_err("invalid jwt")?;
auth_value.set_sensitive(true);
headers.insert(AUTHORIZATION, auth_value);
let client = reqwest::Client::builder()
.timeout(DEFAULT_REQUEST_TIMEOUT)
.default_headers(headers)
.build()
.unwrap();
.build()?;

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

/// Request a list of validator pubkeys for which signatures can be
Expand Down
5 changes: 2 additions & 3 deletions crates/common/src/commit/request.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
use alloy::rpc::types::beacon::{BlsPublicKey, BlsSignature};
use blst::BLST_ERROR;
use serde::{Deserialize, Serialize};
use ssz_derive::{Decode, Encode};
use tree_hash::TreeHash;
use tree_hash_derive::TreeHash;

use crate::{signature::verify_signed_builder_message, types::Chain};
use crate::{error::BlstErrorWrapper, signature::verify_signed_builder_message, types::Chain};

// TODO: might need to adapt the SignedProxyDelegation so that it goes through
// web3 signer
Expand All @@ -23,7 +22,7 @@ pub struct SignedProxyDelegation {
}

impl SignedProxyDelegation {
pub fn validate(&self, chain: Chain) -> Result<(), BLST_ERROR> {
pub fn validate(&self, chain: Chain) -> Result<(), BlstErrorWrapper> {
verify_signed_builder_message(
chain,
&self.message.delegator,
Expand Down
80 changes: 41 additions & 39 deletions crates/common/src/config.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use std::{collections::HashMap, sync::Arc};

use eyre::{eyre, ContextCompat};
use eyre::{eyre, ContextCompat, Result, WrapErr};
use serde::{de::DeserializeOwned, Deserialize, Serialize};

use crate::{
Expand Down Expand Up @@ -43,29 +43,29 @@ pub struct CommitBoostConfig {
pub metrics: MetricsConfig,
}

fn load_from_file<T: DeserializeOwned>(path: &str) -> T {
let config_file = std::fs::read_to_string(path)
.unwrap_or_else(|_| panic!("Unable to find config file: '{}'", path));
toml::from_str(&config_file).unwrap()
fn load_from_file<T: DeserializeOwned>(path: &str) -> Result<T> {
let config_file =
std::fs::read_to_string(path).wrap_err(format!("Unable to find config file: {path}"))?;
toml::from_str(&config_file).wrap_err("could not deserialize toml from string")
}

fn load_file_from_env<T: DeserializeOwned>(env: &str) -> T {
let path = std::env::var(env).unwrap_or_else(|_| panic!("{env} is not set"));
fn load_file_from_env<T: DeserializeOwned>(env: &str) -> Result<T> {
let path = std::env::var(env).wrap_err(format!("{env} is not set"))?;
load_from_file(&path)
}

/// Loads a map of module id -> jwt token from a json env
fn load_jwts() -> HashMap<String, String> {
let jwts = std::env::var(JWTS_ENV).unwrap_or_else(|_| panic!("{JWTS_ENV} is not set"));
serde_json::from_str(&jwts).unwrap_or_else(|_| panic!("Failed to parse jwts: {jwts}"))
fn load_jwts() -> Result<HashMap<String, String>> {
let jwts = std::env::var(JWTS_ENV).wrap_err(format!("{JWTS_ENV} is not set"))?;
serde_json::from_str(&jwts).wrap_err("could not deserialize json from string")
}

impl CommitBoostConfig {
pub fn from_file(path: &str) -> Self {
pub fn from_file(path: &str) -> Result<Self> {
load_from_file(path)
}

pub fn from_env_path() -> Self {
pub fn from_env_path() -> Result<Self> {
load_file_from_env(CB_CONFIG_ENV)
}
}
Expand All @@ -92,18 +92,18 @@ pub struct StartSignerConfig {
}

impl StartSignerConfig {
pub fn load_from_env() -> Self {
let config = CommitBoostConfig::from_env_path();
pub fn load_from_env() -> Result<Self> {
let config = CommitBoostConfig::from_env_path()?;

let jwts = load_jwts();
let server_port = load_env_var_infallible(SIGNER_SERVER_ENV).parse().unwrap();
let jwts = load_jwts()?;
let server_port = load_env_var(SIGNER_SERVER_ENV)?.parse()?;

StartSignerConfig {
Ok(StartSignerConfig {
chain: config.chain,
loader: config.signer.expect("Signer config is missing").loader,
server_port,
jwts,
}
})
}
}

Expand All @@ -121,9 +121,9 @@ pub struct ModuleMetricsConfig {
}

impl ModuleMetricsConfig {
pub fn load_from_env() -> Self {
let server_port = load_env_var_infallible(METRICS_SERVER_ENV).parse().unwrap();
ModuleMetricsConfig { server_port }
pub fn load_from_env() -> Result<Self> {
let server_port = load_env_var(METRICS_SERVER_ENV)?.parse()?;
Ok(ModuleMetricsConfig { server_port })
}
}

Expand Down Expand Up @@ -163,9 +163,10 @@ fn default_pbs() -> String {
}

/// Loads the default pbs config, i.e. with no signer client or custom data
pub fn load_pbs_config() -> eyre::Result<PbsModuleConfig<()>> {
let config = CommitBoostConfig::from_env_path();
let relay_clients = config.relays.into_iter().map(RelayClient::new).collect();
pub fn load_pbs_config() -> Result<PbsModuleConfig<()>> {
let config = CommitBoostConfig::from_env_path()?;
let relay_clients =
config.relays.into_iter().map(RelayClient::new).collect::<Result<Vec<RelayClient>>>()?;

Ok(PbsModuleConfig {
chain: config.chain,
Expand All @@ -177,7 +178,7 @@ pub fn load_pbs_config() -> eyre::Result<PbsModuleConfig<()>> {
}

/// Loads a custom pbs config, i.e. with signer client and/or custom data
pub fn load_pbs_custom_config<T: DeserializeOwned>() -> eyre::Result<PbsModuleConfig<T>> {
pub fn load_pbs_custom_config<T: DeserializeOwned>() -> Result<PbsModuleConfig<T>> {
#[derive(Debug, Deserialize)]
struct CustomPbsConfig<U> {
#[serde(flatten)]
Expand All @@ -194,17 +195,19 @@ pub fn load_pbs_custom_config<T: DeserializeOwned>() -> eyre::Result<PbsModuleCo
}

// load module config including the extra data (if any)
let cb_config: StubConfig<T> = load_file_from_env(CB_CONFIG_ENV);
let relay_clients = cb_config.relays.into_iter().map(RelayClient::new).collect();
let cb_config: StubConfig<T> = load_file_from_env(CB_CONFIG_ENV)?;
let relay_clients =
cb_config.relays.into_iter().map(RelayClient::new).collect::<Result<Vec<RelayClient>>>()?;

let signer_client = if cb_config.pbs.static_config.with_signer {
// if custom pbs requires a signer client, load jwt
let module_jwt = load_env_var_infallible(MODULE_JWT_ENV);
let signer_server_address = load_env_var_infallible(SIGNER_SERVER_ENV);
let module_jwt = load_env_var(MODULE_JWT_ENV)?;
let signer_server_address = load_env_var(SIGNER_SERVER_ENV)?;
Some(SignerClient::new(signer_server_address, &module_jwt))
} else {
None
};
}
.transpose()?;

Ok(PbsModuleConfig {
chain: cb_config.chain,
Expand Down Expand Up @@ -242,10 +245,10 @@ pub struct StartModuleConfig<T = ()> {
/// - [CB_CONFIG_ENV] - the path to the config file
/// - [MODULE_JWT_ENV] - the jwt token for the module
// TODO: add metrics url here
pub fn load_module_config<T: DeserializeOwned>() -> eyre::Result<StartModuleConfig<T>> {
let module_id = load_env_var_infallible(MODULE_ID_ENV);
let module_jwt = load_env_var_infallible(MODULE_JWT_ENV);
let signer_server_address = load_env_var_infallible(SIGNER_SERVER_ENV);
pub fn load_module_config<T: DeserializeOwned>() -> Result<StartModuleConfig<T>> {
let module_id = load_env_var(MODULE_ID_ENV)?;
let module_jwt = load_env_var(MODULE_JWT_ENV)?;
let signer_server_address = load_env_var(SIGNER_SERVER_ENV)?;

#[derive(Debug, Deserialize)]
struct ThisModuleConfig<U> {
Expand All @@ -269,7 +272,7 @@ pub fn load_module_config<T: DeserializeOwned>() -> eyre::Result<StartModuleConf
}

// load module config including the extra data (if any)
let cb_config: StubConfig<T> = load_file_from_env(CB_CONFIG_ENV);
let cb_config: StubConfig<T> = load_file_from_env(CB_CONFIG_ENV)?;

// find all matching modules config
let matches: Vec<ThisModuleConfig<T>> = cb_config
Expand All @@ -286,7 +289,7 @@ pub fn load_module_config<T: DeserializeOwned>() -> eyre::Result<StartModuleConf
.find(|m| m.static_config.id == module_id)
.wrap_err(format!("failed to find module for {module_id}"))?;

let signer_client = SignerClient::new(signer_server_address, &module_jwt);
let signer_client = SignerClient::new(signer_server_address, &module_jwt)?;

Ok(StartModuleConfig {
id: module_config.static_config.id,
Expand All @@ -297,7 +300,6 @@ pub fn load_module_config<T: DeserializeOwned>() -> eyre::Result<StartModuleConf
}
}

// TODO: propagate errors
pub fn load_env_var_infallible(env: &str) -> String {
std::env::var(env).unwrap_or_else(|_| panic!("{env} is not set"))
pub fn load_env_var(env: &str) -> Result<String> {
std::env::var(env).wrap_err("{env} is not set")
}
Loading

0 comments on commit 90cafdf

Please sign in to comment.