Skip to content

Commit 90cafdf

Browse files
fbrvfbrv
andauthored
error handling (#45)
* better error handling --------- Co-authored-by: fbrv <fabio@gattaca.com>
1 parent bb7cb29 commit 90cafdf

28 files changed

+233
-138
lines changed

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ bollard = "0.16.1"
6969
# misc
7070
clap = { version = "4.5.4", features = ["derive", "env"] }
7171
thiserror = "1.0.61"
72+
color-eyre = "0.6.3"
7273
eyre = "0.6.12"
7374
url = "2.5.0"
7475
uuid = { version = "1.8.0", features = ["v4", "fast-rng", "serde"] }

bin/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ tracing-subscriber.workspace = true
2828

2929
# misc
3030
clap.workspace = true
31+
eyre.workspace = true
32+
color-eyre.workspace = true
3133

3234
[[bin]]
3335
name = "commit-boost"

bin/commit_boost.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@ use clap::Parser;
22

33
/// Main entry point of the Commit Boost CLI
44
#[tokio::main]
5-
async fn main() {
5+
async fn main() -> eyre::Result<()> {
6+
color_eyre::install()?;
67
// set default backtrace unless provided
78
if std::env::var_os("RUST_BACKTRACE").is_none() {
89
std::env::set_var("RUST_BACKTRACE", "1");
@@ -14,4 +15,5 @@ async fn main() {
1415
eprintln!("Error: {err}");
1516
std::process::exit(1)
1617
};
18+
Ok(())
1719
}

bin/default_pbs.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
use cb_common::{config::load_pbs_config, utils::initialize_tracing_log};
22
use cb_pbs::{DefaultBuilderApi, PbsService, PbsState};
3+
use eyre::Result;
34

45
#[tokio::main]
5-
async fn main() {
6+
async fn main() -> Result<()> {
7+
color_eyre::install()?;
8+
69
// set default backtrace unless provided
710
if std::env::var_os("RUST_BACKTRACE").is_none() {
811
std::env::set_var("RUST_BACKTRACE", "1");
@@ -14,6 +17,7 @@ async fn main() {
1417
let pbs_config = load_pbs_config().expect("failed to load pbs config");
1518
let state = PbsState::<()>::new(pbs_config);
1619

17-
PbsService::init_metrics();
20+
PbsService::init_metrics()?;
1821
PbsService::run::<(), DefaultBuilderApi>(state).await;
22+
Ok(())
1923
}

bin/signer_module.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,18 @@
11
use cb_common::{config::StartSignerConfig, utils::initialize_tracing_log};
22
use cb_signer::service::SigningService;
3+
use eyre::Result;
34

45
#[tokio::main]
5-
async fn main() {
6+
async fn main() -> Result<()> {
7+
color_eyre::install()?;
8+
69
// set default backtrace unless provided
710
if std::env::var_os("RUST_BACKTRACE").is_none() {
811
std::env::set_var("RUST_BACKTRACE", "1");
912
}
1013

1114
initialize_tracing_log();
1215

13-
let config = StartSignerConfig::load_from_env();
14-
SigningService::run(config).await;
16+
let config = StartSignerConfig::load_from_env()?;
17+
SigningService::run(config).await
1518
}

crates/cli/src/docker_cmd.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
use std::process::{Command, Stdio};
22

3-
pub fn handle_docker_start(compose_path: String, env_path: String) -> eyre::Result<()> {
3+
use eyre::Result;
4+
5+
pub fn handle_docker_start(compose_path: String, env_path: String) -> Result<()> {
46
println!("Starting Commit-Boost with compose file: {}", compose_path);
57

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

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

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

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

5254
// TODO: if permission denied, print warning to run as sudo

crates/cli/src/docker_init.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ use docker_compose_types::{
1313
Compose, DependsOnOptions, Environment, LoggingParameters, MapOrEmpty, NetworkSettings,
1414
Networks, Ports, Service, Services, SingleValue, Volumes,
1515
};
16+
use eyre::Result;
1617
use indexmap::IndexMap;
1718
use serde::Serialize;
1819

@@ -28,10 +29,10 @@ const SIGNER_NETWORK: &str = "signer_network";
2829
2930
// TODO: do more validation for paths, images, etc
3031
#[allow(unused_assignments)]
31-
pub fn handle_docker_init(config_path: String, output_dir: String) -> eyre::Result<()> {
32+
pub fn handle_docker_init(config_path: String, output_dir: String) -> Result<()> {
3233
println!("Initializing Commit-Boost with config file: {}", config_path);
3334

34-
let cb_config = CommitBoostConfig::from_file(&config_path);
35+
let cb_config = CommitBoostConfig::from_file(&config_path)?;
3536

3637
let mut services = IndexMap::new();
3738

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

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

164165
let signer_service = Service {

crates/common/src/commit/client.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use std::sync::Arc;
22

33
use alloy::rpc::types::beacon::{BlsPublicKey, BlsSignature};
4+
use eyre::WrapErr;
45
use reqwest::header::{HeaderMap, HeaderValue, AUTHORIZATION};
56
use serde::{Deserialize, Serialize};
67

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

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

3435
let mut auth_value =
35-
HeaderValue::from_str(&format!("Bearer {}", jwt)).expect("invalid jwt");
36+
HeaderValue::from_str(&format!("Bearer {}", jwt)).wrap_err("invalid jwt")?;
3637
auth_value.set_sensitive(true);
3738
headers.insert(AUTHORIZATION, auth_value);
3839
let client = reqwest::Client::builder()
3940
.timeout(DEFAULT_REQUEST_TIMEOUT)
4041
.default_headers(headers)
41-
.build()
42-
.unwrap();
42+
.build()?;
4343

44-
Self { url: url.into(), client }
44+
Ok(Self { url: url.into(), client })
4545
}
4646

4747
/// Request a list of validator pubkeys for which signatures can be

crates/common/src/commit/request.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
11
use alloy::rpc::types::beacon::{BlsPublicKey, BlsSignature};
2-
use blst::BLST_ERROR;
32
use serde::{Deserialize, Serialize};
43
use ssz_derive::{Decode, Encode};
54
use tree_hash::TreeHash;
65
use tree_hash_derive::TreeHash;
76

8-
use crate::{signature::verify_signed_builder_message, types::Chain};
7+
use crate::{error::BlstErrorWrapper, signature::verify_signed_builder_message, types::Chain};
98

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

2524
impl SignedProxyDelegation {
26-
pub fn validate(&self, chain: Chain) -> Result<(), BLST_ERROR> {
25+
pub fn validate(&self, chain: Chain) -> Result<(), BlstErrorWrapper> {
2726
verify_signed_builder_message(
2827
chain,
2928
&self.message.delegator,

crates/common/src/config.rs

Lines changed: 41 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use std::{collections::HashMap, sync::Arc};
22

3-
use eyre::{eyre, ContextCompat};
3+
use eyre::{eyre, ContextCompat, Result, WrapErr};
44
use serde::{de::DeserializeOwned, Deserialize, Serialize};
55

66
use crate::{
@@ -43,29 +43,29 @@ pub struct CommitBoostConfig {
4343
pub metrics: MetricsConfig,
4444
}
4545

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

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

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

6363
impl CommitBoostConfig {
64-
pub fn from_file(path: &str) -> Self {
64+
pub fn from_file(path: &str) -> Result<Self> {
6565
load_from_file(path)
6666
}
6767

68-
pub fn from_env_path() -> Self {
68+
pub fn from_env_path() -> Result<Self> {
6969
load_file_from_env(CB_CONFIG_ENV)
7070
}
7171
}
@@ -92,18 +92,18 @@ pub struct StartSignerConfig {
9292
}
9393

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

98-
let jwts = load_jwts();
99-
let server_port = load_env_var_infallible(SIGNER_SERVER_ENV).parse().unwrap();
98+
let jwts = load_jwts()?;
99+
let server_port = load_env_var(SIGNER_SERVER_ENV)?.parse()?;
100100

101-
StartSignerConfig {
101+
Ok(StartSignerConfig {
102102
chain: config.chain,
103103
loader: config.signer.expect("Signer config is missing").loader,
104104
server_port,
105105
jwts,
106-
}
106+
})
107107
}
108108
}
109109

@@ -121,9 +121,9 @@ pub struct ModuleMetricsConfig {
121121
}
122122

123123
impl ModuleMetricsConfig {
124-
pub fn load_from_env() -> Self {
125-
let server_port = load_env_var_infallible(METRICS_SERVER_ENV).parse().unwrap();
126-
ModuleMetricsConfig { server_port }
124+
pub fn load_from_env() -> Result<Self> {
125+
let server_port = load_env_var(METRICS_SERVER_ENV)?.parse()?;
126+
Ok(ModuleMetricsConfig { server_port })
127127
}
128128
}
129129

@@ -163,9 +163,10 @@ fn default_pbs() -> String {
163163
}
164164

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

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

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

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

200202
let signer_client = if cb_config.pbs.static_config.with_signer {
201203
// if custom pbs requires a signer client, load jwt
202-
let module_jwt = load_env_var_infallible(MODULE_JWT_ENV);
203-
let signer_server_address = load_env_var_infallible(SIGNER_SERVER_ENV);
204+
let module_jwt = load_env_var(MODULE_JWT_ENV)?;
205+
let signer_server_address = load_env_var(SIGNER_SERVER_ENV)?;
204206
Some(SignerClient::new(signer_server_address, &module_jwt))
205207
} else {
206208
None
207-
};
209+
}
210+
.transpose()?;
208211

209212
Ok(PbsModuleConfig {
210213
chain: cb_config.chain,
@@ -242,10 +245,10 @@ pub struct StartModuleConfig<T = ()> {
242245
/// - [CB_CONFIG_ENV] - the path to the config file
243246
/// - [MODULE_JWT_ENV] - the jwt token for the module
244247
// TODO: add metrics url here
245-
pub fn load_module_config<T: DeserializeOwned>() -> eyre::Result<StartModuleConfig<T>> {
246-
let module_id = load_env_var_infallible(MODULE_ID_ENV);
247-
let module_jwt = load_env_var_infallible(MODULE_JWT_ENV);
248-
let signer_server_address = load_env_var_infallible(SIGNER_SERVER_ENV);
248+
pub fn load_module_config<T: DeserializeOwned>() -> Result<StartModuleConfig<T>> {
249+
let module_id = load_env_var(MODULE_ID_ENV)?;
250+
let module_jwt = load_env_var(MODULE_JWT_ENV)?;
251+
let signer_server_address = load_env_var(SIGNER_SERVER_ENV)?;
249252

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

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

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

289-
let signer_client = SignerClient::new(signer_server_address, &module_jwt);
292+
let signer_client = SignerClient::new(signer_server_address, &module_jwt)?;
290293

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

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

0 commit comments

Comments
 (0)