diff --git a/Cargo.lock b/Cargo.lock index 8ec885c0..36877245 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1438,17 +1438,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "builder_log" -version = "0.8.1-rc.1" -dependencies = [ - "async-trait", - "commit-boost", - "eyre", - "tokio", - "tracing", -] - [[package]] name = "bumpalo" version = "3.17.0" diff --git a/Cargo.toml b/Cargo.toml index c39ad54b..22dc2386 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,5 @@ [workspace] -members = ["benches/*", "bin", "crates/*", "examples/builder_log", "examples/da_commit", "examples/status_api", "tests"] +members = ["benches/*", "bin", "crates/*", "examples/da_commit", "examples/status_api", "tests"] resolver = "2" [workspace.package] diff --git a/bin/src/lib.rs b/bin/src/lib.rs index e0747d2c..9c45ebef 100644 --- a/bin/src/lib.rs +++ b/bin/src/lib.rs @@ -9,7 +9,6 @@ pub mod prelude { load_builder_module_config, load_commit_module_config, load_pbs_config, load_pbs_custom_config, LogsSettings, StartCommitModuleConfig, PBS_MODULE_NAME, }, - pbs::{BuilderEvent, BuilderEventClient, OnBuilderApiEvent}, signer::EcdsaSignature, types::{BlsPublicKey, BlsSignature, Chain}, utils::{initialize_tracing_log, utcnow_ms, utcnow_ns, utcnow_sec, utcnow_us}, diff --git a/config.example.toml b/config.example.toml index 8ed5b139..dfb5fd09 100644 --- a/config.example.toml +++ b/config.example.toml @@ -241,15 +241,14 @@ proxy_dir = "./proxies" # secrets_path = "./tests/data/proxy/secrets" # Commit-Boost can optionally run "modules" which extend the capabilities of the sidecar. -# Currently, two types of modules are supported: +# Currently, one type of module is supported: # - "commit": modules which request commitment signatures from the validator keys -# - "events": modules which callback to BuilderAPI events as triggered from the PBS modules, used e.g. for monitoring # If any "commit" module is present, then the [signer] section should also be configured # OPTIONAL [[modules]] # Unique ID of the module id = "DA_COMMIT" -# Type of the module. Supported values: commit, events +# Type of the module. Supported values: commit type = "commit" # Docker image of the module docker_image = "test_da_commit" diff --git a/crates/cli/src/docker_init.rs b/crates/cli/src/docker_init.rs index 570d5d97..81b80233 100644 --- a/crates/cli/src/docker_init.rs +++ b/crates/cli/src/docker_init.rs @@ -6,16 +6,15 @@ use std::{ use cb_common::{ config::{ - CommitBoostConfig, LogsSettings, ModuleKind, SignerConfig, SignerType, BUILDER_PORT_ENV, - BUILDER_URLS_ENV, CHAIN_SPEC_ENV, CONFIG_DEFAULT, CONFIG_ENV, DIRK_CA_CERT_DEFAULT, - DIRK_CA_CERT_ENV, DIRK_CERT_DEFAULT, DIRK_CERT_ENV, DIRK_DIR_SECRETS_DEFAULT, - DIRK_DIR_SECRETS_ENV, DIRK_KEY_DEFAULT, DIRK_KEY_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, PROXY_DIR_KEYS_DEFAULT, - PROXY_DIR_KEYS_ENV, PROXY_DIR_SECRETS_DEFAULT, PROXY_DIR_SECRETS_ENV, SIGNER_DEFAULT, - SIGNER_DIR_KEYS_DEFAULT, SIGNER_DIR_KEYS_ENV, SIGNER_DIR_SECRETS_DEFAULT, - SIGNER_DIR_SECRETS_ENV, SIGNER_ENDPOINT_ENV, SIGNER_KEYS_ENV, SIGNER_MODULE_NAME, - SIGNER_PORT_DEFAULT, SIGNER_URL_ENV, + CommitBoostConfig, LogsSettings, ModuleKind, SignerConfig, SignerType, CHAIN_SPEC_ENV, + CONFIG_DEFAULT, CONFIG_ENV, DIRK_CA_CERT_DEFAULT, DIRK_CA_CERT_ENV, DIRK_CERT_DEFAULT, + DIRK_CERT_ENV, DIRK_DIR_SECRETS_DEFAULT, DIRK_DIR_SECRETS_ENV, DIRK_KEY_DEFAULT, + DIRK_KEY_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, + PROXY_DIR_KEYS_DEFAULT, PROXY_DIR_KEYS_ENV, PROXY_DIR_SECRETS_DEFAULT, + PROXY_DIR_SECRETS_ENV, SIGNER_DEFAULT, SIGNER_DIR_KEYS_DEFAULT, SIGNER_DIR_KEYS_ENV, + SIGNER_DIR_SECRETS_DEFAULT, SIGNER_DIR_SECRETS_ENV, SIGNER_ENDPOINT_ENV, SIGNER_KEYS_ENV, + SIGNER_MODULE_NAME, SIGNER_PORT_DEFAULT, SIGNER_URL_ENV, }, pbs::{BUILDER_V1_API_PATH, GET_STATUS_PATH}, signer::{ProxyStore, SignerLoader}, @@ -81,9 +80,6 @@ pub async fn handle_docker_init(config_path: PathBuf, output_dir: PathBuf) -> Re format!("http://cb_signer:{signer_port}") }; - let builder_events_port = 30000; - let mut builder_events_modules = Vec::new(); - let mut warnings = Vec::new(); let needs_signer_module = cb_config.pbs.with_signer || @@ -185,58 +181,6 @@ pub async fn handle_docker_init(config_path: PathBuf, output_dir: PathBuf) -> Re ..Service::default() } } - // an event module just needs a port to listen on - ModuleKind::Events => { - let mut ports = vec![]; - 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(CONFIG_ENV, CONFIG_DEFAULT), - get_env_uval(BUILDER_PORT_ENV, builder_events_port), - ]); - - if let Some((key, val)) = chain_spec_env.clone() { - module_envs.insert(key, val); - } - if let Some(metrics_config) = &cb_config.metrics { - if metrics_config.enabled { - let host_endpoint = - SocketAddr::from((metrics_config.host, metrics_port)); - ports.push(format!("{}:{}", host_endpoint, metrics_port)); - warnings.push(format!( - "{} has an exported port on {}", - module_cid, metrics_port - )); - targets.push(format!("{host_endpoint}")); - let (key, val) = get_env_uval(METRICS_PORT_ENV, metrics_port as u64); - module_envs.insert(key, val); - - metrics_port += 1; - } - } - if log_to_file { - let (key, val) = get_env_val(LOGS_DIR_ENV, LOGS_DIR_DEFAULT); - module_envs.insert(key, val); - } - - // volumes - let mut module_volumes = vec![config_volume.clone()]; - module_volumes.extend(chain_spec_volume.clone()); - module_volumes.extend(get_log_volume(&cb_config.logs, &module.id)); - - Service { - container_name: Some(module_cid.clone()), - image: Some(module.docker_image), - ports: Ports::Short(ports), - volumes: module_volumes, - environment: Environment::KvPair(module_envs), - depends_on: DependsOnOptions::Simple(vec!["cb_pbs".to_owned()]), - ..Service::default() - } - } }; services.insert(module_cid, Some(module_service)); @@ -283,11 +227,6 @@ pub async fn handle_docker_init(config_path: PathBuf, output_dir: PathBuf) -> Re 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_URLS_ENV, &env); - pbs_envs.insert(k, v); - } // inside the container expose on 0.0.0.0 let container_endpoint = diff --git a/crates/common/src/config/constants.rs b/crates/common/src/config/constants.rs index 406f1375..67248596 100644 --- a/crates/common/src/config/constants.rs +++ b/crates/common/src/config/constants.rs @@ -19,9 +19,6 @@ pub const LOGS_DIR_DEFAULT: &str = "/var/logs/commit-boost"; 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"; - /// Where to receive BuilderAPI calls from beacon node pub const PBS_ENDPOINT_ENV: &str = "CB_PBS_ENDPOINT"; @@ -95,7 +92,3 @@ pub const MODULE_ID_ENV: &str = "CB_MODULE_ID"; 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"; diff --git a/crates/common/src/config/module.rs b/crates/common/src/config/module.rs index 16b089ca..89758883 100644 --- a/crates/common/src/config/module.rs +++ b/crates/common/src/config/module.rs @@ -10,7 +10,6 @@ use crate::{ constants::{CONFIG_ENV, MODULE_ID_ENV, MODULE_JWT_ENV, SIGNER_URL_ENV}, load_env_var, utils::load_file_from_env, - BUILDER_PORT_ENV, }, types::{Chain, Jwt, ModuleId}, }; @@ -19,8 +18,6 @@ use crate::{ pub enum ModuleKind { #[serde(alias = "commit")] Commit, - #[serde(alias = "events")] - Events, } /// Static module config from config file @@ -120,8 +117,6 @@ pub struct StartBuilderModuleConfig { pub id: ModuleId, /// Chain spec pub chain: Chain, - /// Where to listen for Builder events - pub server_port: u16, /// Opaque module config pub extra: T, } @@ -129,7 +124,6 @@ pub struct StartBuilderModuleConfig { pub fn load_builder_module_config() -> eyre::Result> { let module_id = ModuleId(load_env_var(MODULE_ID_ENV)?); - let builder_events_port: u16 = load_env_var(BUILDER_PORT_ENV)?.parse()?; #[derive(Debug, Deserialize)] struct ThisModuleConfig { @@ -176,7 +170,6 @@ pub fn load_builder_module_config() -> eyre::Result, /// Signer client to call Signer API pub signer_client: Option, - /// Event publisher - pub event_publisher: Option, /// Muxes config pub muxes: Option>, } @@ -253,7 +251,6 @@ pub async fn load_pbs_config() -> Result { let relay_clients = config.relays.into_iter().map(RelayClient::new).collect::>>()?; - let maybe_publiher = BuilderEventPublisher::new_from_env()?; let mut all_relays = HashMap::with_capacity(relay_clients.len()); if let Some(muxes) = &muxes { @@ -281,7 +278,6 @@ pub async fn load_pbs_config() -> Result { relays: relay_clients, all_relays, signer_client: None, - event_publisher: maybe_publiher, muxes, }) } @@ -329,7 +325,6 @@ pub async fn load_pbs_custom_config() -> Result<(PbsModuleC let relay_clients = cb_config.relays.into_iter().map(RelayClient::new).collect::>>()?; - let maybe_publiher = BuilderEventPublisher::new_from_env()?; let mut all_relays = HashMap::with_capacity(relay_clients.len()); if let Some(muxes) = &muxes { @@ -371,7 +366,6 @@ pub async fn load_pbs_custom_config() -> Result<(PbsModuleC relays: relay_clients, all_relays, signer_client, - event_publisher: maybe_publiher, muxes, }, cb_config.pbs.extra, diff --git a/crates/common/src/pbs/constants.rs b/crates/common/src/pbs/constants.rs index d3b060d9..b17392f9 100644 --- a/crates/common/src/pbs/constants.rs +++ b/crates/common/src/pbs/constants.rs @@ -17,7 +17,6 @@ pub const HEADER_VERSION_KEY: &str = "X-CommitBoost-Version"; pub const HEADER_VERSION_VALUE: &str = COMMIT_BOOST_VERSION; pub const HEADER_START_TIME_UNIX_MS: &str = "Date-Milliseconds"; -pub const BUILDER_EVENTS_PATH: &str = "/builder_events"; pub const DEFAULT_PBS_JWT_KEY: &str = "DEFAULT_PBS"; pub const DEFAULT_PBS_PORT: u16 = 18550; diff --git a/crates/common/src/pbs/event.rs b/crates/common/src/pbs/event.rs deleted file mode 100644 index 653b5bea..00000000 --- a/crates/common/src/pbs/event.rs +++ /dev/null @@ -1,143 +0,0 @@ -use std::{net::SocketAddr, time::Duration}; - -use alloy::{primitives::B256, rpc::types::beacon::relay::ValidatorRegistration}; -use async_trait::async_trait; -use axum::{ - extract::State, - response::{IntoResponse, Response}, - routing::post, - Json, -}; -use eyre::{bail, Result}; -use reqwest::StatusCode; -use serde::{Deserialize, Serialize}; -use tokio::net::TcpListener; -use tracing::{error, info, trace, warn}; -use url::Url; - -use super::{ - GetHeaderParams, GetHeaderResponse, SignedBlindedBeaconBlock, SubmitBlindedBlockResponse, -}; -use crate::{ - config::{load_optional_env_var, BUILDER_URLS_ENV, HTTP_TIMEOUT_SECONDS_DEFAULT}, - pbs::{BuilderApiVersion, BUILDER_EVENTS_PATH}, -}; - -#[derive(Debug, Clone, Serialize, Deserialize)] -pub enum BuilderEvent { - GetHeaderRequest(GetHeaderParams), - GetHeaderResponse(Box>), - GetStatusEvent, - GetStatusResponse, - SubmitBlockRequest(Box, BuilderApiVersion), - SubmitBlockResponseV1(Box), - SubmitBlockResponseV2, - MissedPayload { - /// Hash for the block for which no payload was received - block_hash: B256, - }, - RegisterValidatorRequest(Vec), - RegisterValidatorResponse, - ReloadEvent, - ReloadResponse, -} - -#[derive(Debug, Clone)] -pub struct BuilderEventPublisher { - client: reqwest::Client, - endpoints: Vec, -} - -impl BuilderEventPublisher { - pub fn new(endpoints: Vec, http_timeout: Duration) -> Result { - for endpoint in &endpoints { - if endpoint.scheme() != "https" { - warn!("BuilderEventPublisher endpoint {endpoint} is insecure, consider using HTTPS if possible instead"); - } - } - Ok(Self { client: reqwest::ClientBuilder::new().timeout(http_timeout).build()?, endpoints }) - } - - pub fn new_from_env() -> Result> { - let http_timeout = Duration::from_secs(HTTP_TIMEOUT_SECONDS_DEFAULT); - - load_optional_env_var(BUILDER_URLS_ENV) - .map(|joined| { - let endpoints = joined - .trim() - .split(',') - .map(|base| { - let url = base.trim().parse::()?.join(BUILDER_EVENTS_PATH)?; - Ok(url) - }) - .collect::>>()?; - - Self::new(endpoints, http_timeout) - }) - .transpose() - } - - pub fn publish(&self, event: BuilderEvent) { - for endpoint in self.endpoints.clone() { - let client = self.client.clone(); - let event = event.clone(); - - tokio::spawn(async move { - trace!("Sending events to {}", endpoint); - if let Err(err) = client - .post(endpoint) - .json(&event) - .send() - .await - .and_then(|res| res.error_for_status()) - { - error!("Failed to publish event: {:?}", err) - }; - }); - } - } - - pub fn n_subscribers(&self) -> usize { - self.endpoints.len() - } -} - -pub struct BuilderEventClient { - pub port: u16, - pub processor: T, -} - -impl BuilderEventClient { - pub fn new(port: u16, processor: T) -> Self { - Self { port, processor } - } - - pub async fn run(self) -> eyre::Result<()> { - info!("Starting builder events server on port {}", self.port); - - let router = axum::Router::new() - .route(BUILDER_EVENTS_PATH, post(handle_builder_event::)) - .with_state(self.processor); - let address = SocketAddr::from(([0, 0, 0, 0], self.port)); - let listener = TcpListener::bind(&address).await?; - - axum::serve(listener, router).await?; - - bail!("Builder events stopped") - } -} - -async fn handle_builder_event( - State(processor): State, - Json(event): Json, -) -> Response { - trace!("Handling builder event"); - processor.on_builder_api_event(event).await; - StatusCode::OK.into_response() -} - -#[async_trait] -/// This is what modules are expected to implement to process BuilderApi events -pub trait OnBuilderApiEvent { - async fn on_builder_api_event(&self, event: BuilderEvent); -} diff --git a/crates/common/src/pbs/mod.rs b/crates/common/src/pbs/mod.rs index 53baced4..af2c07b4 100644 --- a/crates/common/src/pbs/mod.rs +++ b/crates/common/src/pbs/mod.rs @@ -1,12 +1,10 @@ mod builder; mod constants; pub mod error; -mod event; mod relay; mod types; pub use builder::*; pub use constants::*; -pub use event::*; pub use relay::*; pub use types::*; diff --git a/crates/pbs/src/routes/get_header.rs b/crates/pbs/src/routes/get_header.rs index 53aa194d..77607c28 100644 --- a/crates/pbs/src/routes/get_header.rs +++ b/crates/pbs/src/routes/get_header.rs @@ -5,7 +5,7 @@ use axum::{ response::IntoResponse, }; use cb_common::{ - pbs::{BuilderEvent, GetHeaderParams}, + pbs::GetHeaderParams, utils::{get_user_agent, ms_into_slot}, }; use reqwest::StatusCode; @@ -30,8 +30,6 @@ pub async fn handle_get_header>( let state = state.read().clone(); - state.publish_event(BuilderEvent::GetHeaderRequest(params.clone())); - let ua = get_user_agent(&req_headers); let ms_into_slot = ms_into_slot(params.slot, state.config.chain); @@ -39,8 +37,6 @@ pub async fn handle_get_header>( match A::get_header(params, req_headers, state.clone()).await { Ok(res) => { - state.publish_event(BuilderEvent::GetHeaderResponse(Box::new(res.clone()))); - if let Some(max_bid) = res { info!(value_eth = format_ether(max_bid.value()), block_hash =% max_bid.block_hash(), "received header"); diff --git a/crates/pbs/src/routes/register_validator.rs b/crates/pbs/src/routes/register_validator.rs index 93c84c3f..acb0168a 100644 --- a/crates/pbs/src/routes/register_validator.rs +++ b/crates/pbs/src/routes/register_validator.rs @@ -1,6 +1,6 @@ use alloy::rpc::types::beacon::relay::ValidatorRegistration; use axum::{extract::State, http::HeaderMap, response::IntoResponse, Json}; -use cb_common::{pbs::BuilderEvent, utils::get_user_agent}; +use cb_common::utils::get_user_agent; use reqwest::StatusCode; use tracing::{error, info, trace}; @@ -20,14 +20,12 @@ pub async fn handle_register_validator>( let state = state.read().clone(); trace!(?registrations); - state.publish_event(BuilderEvent::RegisterValidatorRequest(registrations.clone())); let ua = get_user_agent(&req_headers); info!(ua, num_registrations = registrations.len(), "new request"); if let Err(err) = A::register_validator(registrations, req_headers, state.clone()).await { - state.publish_event(BuilderEvent::RegisterValidatorResponse); error!(%err, "all relays failed registration"); let err = PbsClientError::NoResponse; diff --git a/crates/pbs/src/routes/reload.rs b/crates/pbs/src/routes/reload.rs index 5326c726..5ba33329 100644 --- a/crates/pbs/src/routes/reload.rs +++ b/crates/pbs/src/routes/reload.rs @@ -1,5 +1,5 @@ use axum::{extract::State, http::HeaderMap, response::IntoResponse}; -use cb_common::{pbs::BuilderEvent, utils::get_user_agent}; +use cb_common::utils::get_user_agent; use reqwest::StatusCode; use tracing::{error, info}; @@ -16,15 +16,12 @@ pub async fn handle_reload>( ) -> Result { let prev_state = state.read().clone(); - prev_state.publish_event(BuilderEvent::ReloadEvent); - let ua = get_user_agent(&req_headers); info!(ua, relay_check = prev_state.config.pbs_config.relay_check); match A::reload(prev_state.clone()).await { Ok(new_state) => { - prev_state.publish_event(BuilderEvent::ReloadResponse); info!("config reload successful"); *state.write() = new_state; diff --git a/crates/pbs/src/routes/status.rs b/crates/pbs/src/routes/status.rs index b8cf3408..d0f68ac7 100644 --- a/crates/pbs/src/routes/status.rs +++ b/crates/pbs/src/routes/status.rs @@ -1,5 +1,5 @@ use axum::{extract::State, http::HeaderMap, response::IntoResponse}; -use cb_common::{pbs::BuilderEvent, utils::get_user_agent}; +use cb_common::utils::get_user_agent; use reqwest::StatusCode; use tracing::{error, info}; @@ -17,15 +17,12 @@ pub async fn handle_get_status>( ) -> Result { let state = state.read().clone(); - state.publish_event(BuilderEvent::GetStatusEvent); - let ua = get_user_agent(&req_headers); info!(ua, relay_check = state.config.pbs_config.relay_check, "new request"); match A::get_status(req_headers, state.clone()).await { Ok(_) => { - state.publish_event(BuilderEvent::GetStatusResponse); info!("relay check successful"); BEACON_NODE_STATUS.with_label_values(&["200", STATUS_ENDPOINT_TAG]).inc(); diff --git a/crates/pbs/src/routes/submit_block.rs b/crates/pbs/src/routes/submit_block.rs index 10674c09..a3590c6c 100644 --- a/crates/pbs/src/routes/submit_block.rs +++ b/crates/pbs/src/routes/submit_block.rs @@ -1,6 +1,6 @@ use axum::{extract::State, http::HeaderMap, response::IntoResponse, Json}; use cb_common::{ - pbs::{BuilderApiVersion, BuilderEvent, SignedBlindedBeaconBlock}, + pbs::{BuilderApiVersion, SignedBlindedBeaconBlock}, utils::{get_user_agent, timestamp_of_slot_start_millis, utcnow_ms}, }; use reqwest::StatusCode; @@ -57,11 +57,6 @@ async fn handle_submit_block_impl>( let state = state.read().clone(); - state.publish_event(BuilderEvent::SubmitBlockRequest( - Box::new(signed_blinded_block.clone()), - api_version, - )); - let now = utcnow_ms(); let slot = signed_blinded_block.slot(); let block_hash = signed_blinded_block.block_hash(); @@ -74,9 +69,6 @@ async fn handle_submit_block_impl>( Ok(res) => match res { Some(block_response) => { trace!(?block_response); - state.publish_event(BuilderEvent::SubmitBlockResponseV1(Box::new( - block_response.clone(), - ))); info!("received unblinded block (v1)"); BEACON_NODE_STATUS @@ -85,7 +77,6 @@ async fn handle_submit_block_impl>( Ok((StatusCode::OK, Json(block_response).into_response())) } None => { - state.publish_event(BuilderEvent::SubmitBlockResponseV2); info!("received unblinded block (v2)"); BEACON_NODE_STATUS @@ -97,7 +88,6 @@ async fn handle_submit_block_impl>( Err(err) => { error!(%err, %block_hash, "CRITICAL: no payload received from relays. Check previous logs or use the Relay Data API"); - state.publish_event(BuilderEvent::MissedPayload { block_hash }); let err = PbsClientError::NoPayload; BEACON_NODE_STATUS diff --git a/crates/pbs/src/service.rs b/crates/pbs/src/service.rs index 730e229f..6dc2c92d 100644 --- a/crates/pbs/src/service.rs +++ b/crates/pbs/src/service.rs @@ -25,9 +25,7 @@ pub struct PbsService; impl PbsService { pub async fn run>(state: PbsState) -> Result<()> { let addr = state.config.endpoint; - let events_subs = - state.config.event_publisher.as_ref().map(|e| e.n_subscribers()).unwrap_or_default(); - info!(version = COMMIT_BOOST_VERSION, commit_hash = COMMIT_BOOST_COMMIT, ?addr, events_subs, chain =? state.config.chain, "starting PBS service"); + info!(version = COMMIT_BOOST_VERSION, commit_hash = COMMIT_BOOST_COMMIT, ?addr, chain =? state.config.chain, "starting PBS service"); let app = create_app_router::(RwLock::new(state).into()); let listener = TcpListener::bind(addr).await?; diff --git a/crates/pbs/src/state.rs b/crates/pbs/src/state.rs index f641c069..4403b348 100644 --- a/crates/pbs/src/state.rs +++ b/crates/pbs/src/state.rs @@ -2,7 +2,7 @@ use std::sync::Arc; use cb_common::{ config::{PbsConfig, PbsModuleConfig}, - pbs::{BuilderEvent, RelayClient}, + pbs::RelayClient, types::BlsPublicKey, }; use parking_lot::RwLock; @@ -37,12 +37,6 @@ impl PbsState where S: BuilderApiState, { - pub fn publish_event(&self, e: BuilderEvent) { - if let Some(publisher) = self.config.event_publisher.as_ref() { - publisher.publish(e); - } - } - // Getters pub fn pbs_config(&self) -> &PbsConfig { &self.config.pbs_config diff --git a/docs/docs/developing/custom-modules.md b/docs/docs/developing/custom-modules.md index 7282db70..cf224448 100644 --- a/docs/docs/developing/custom-modules.md +++ b/docs/docs/developing/custom-modules.md @@ -1,11 +1,12 @@ --- sidebar_position: 1 --- + # Custom Modules + Commit-Boost aims to provide an open platform for developers to create and distribute commitment protocols sidecars. -There are three ways to leverage Commit-Boost modularity: +There are two ways to leverage Commit-Boost modularity: 1. Commit Modules, which request signatures from the proposer, e.g. for preconfirmations ([example](https://github.com/Commit-Boost/commit-boost-client/tree/78bdc47bf89082f4d1ea302f9a3f86f609966b28/examples/da_commit)). 2. PBS Modules, which tweak the default PBS Module with additional logic, e.g. verifying additional constraints in `get_header` ([example](https://github.com/Commit-Boost/commit-boost-client/tree/78bdc47bf89082f4d1ea302f9a3f86f609966b28/examples/status_api)). -3. PBS Events, which trigger based on the different events of the PBS lifecycle and can be used e.g. for monitoring and reporting ([example](https://github.com/Commit-Boost/commit-boost-client/tree/78bdc47bf89082f4d1ea302f9a3f86f609966b28/examples/builder_log)). diff --git a/docs/docs/get_started/configuration.md b/docs/docs/get_started/configuration.md index c3f49712..74fb3f24 100644 --- a/docs/docs/get_started/configuration.md +++ b/docs/docs/get_started/configuration.md @@ -10,6 +10,7 @@ Commit-Boost needs a configuration file detailing all the services that you want - For some additional examples on config presets, check out [here](https://github.com/Commit-Boost/commit-boost-client/tree/main/configs). ## Minimal PBS setup on Holesky + ```toml chain = "Holesky" @@ -57,122 +58,134 @@ We currently support Lighthouse, Prysm, Teku, Lodestar, and Nimbus's keystores s
Lighthouse - #### File structure: - ``` - ├── keys - │   ├── - │   │   └── voting-keystore.json - │   └── - │   └── voting-keystore.json - └── secrets -    ├── -    └── - ``` +#### File structure: - #### Config: - ```toml - [pbs] - ... - with_signer = true +``` +├── keys +│   ├── +│   │   └── voting-keystore.json +│   └── +│   └── voting-keystore.json +└── secrets +    ├── +    └── +``` - [signer] - port = 20000 +#### Config: + +```toml +[pbs] +... +with_signer = true + +[signer] +port = 20000 + +[signer.local.loader] +format = "lighthouse" +keys_path = "keys" +secrets_path = "secrets" +``` - [signer.local.loader] - format = "lighthouse" - keys_path = "keys" - secrets_path = "secrets" - ```
Prysm - #### File structure: - ``` - ├── wallet - │   └── direct - │      └── accounts - │         └──all-accounts.keystore.json - └── secrets -    └── password.txt - ``` +#### File structure: - #### Config: - ```toml - [pbs] - ... - with_signer = true +``` +├── wallet +│   └── direct +│      └── accounts +│         └──all-accounts.keystore.json +└── secrets +    └── password.txt +``` - [signer] - port = 20000 +#### Config: + +```toml +[pbs] +... +with_signer = true + +[signer] +port = 20000 + +[signer.local.loader] +format = "prysm" +keys_path = "wallet/direct/accounts/all-accounts.keystore.json" +secrets_path = "secrets/password.txt" +``` - [signer.local.loader] - format = "prysm" - keys_path = "wallet/direct/accounts/all-accounts.keystore.json" - secrets_path = "secrets/password.txt" - ```
Teku - #### File structure: - ``` - ├── keys - │   ├── .json - │   └── .json - └── secrets -    ├── .txt -    └── .txt - ``` +#### File structure: - #### Config: - ```toml - [pbs] - ... - with_signer = true +``` +├── keys +│   ├── .json +│   └── .json +└── secrets +    ├── .txt +    └── .txt +``` + +#### Config: + +```toml +[pbs] +... +with_signer = true + +[signer] +port = 20000 + +[signer.local.loader] +format = "teku" +keys_path = "keys" +secrets_path = "secrets" +``` - [signer] - port = 20000 - - [signer.local.loader] - format = "teku" - keys_path = "keys" - secrets_path = "secrets" - ```
Lodestar - #### File structure: - ``` - ├── keys - │   ├── .json - │   └── .json - └── secrets -    └── password.txt - ``` +#### File structure: - #### Config: - ```toml - [pbs] - ... - with_signer = true +``` +├── keys +│   ├── .json +│   └── .json +└── secrets +    └── password.txt +``` - [signer] - port = 20000 - - [signer.local.loader] - format = "lodestar" - keys_path = "keys" - secrets_path = "secrets/password.txt" - ``` +#### Config: + +```toml +[pbs] +... +with_signer = true + +[signer] +port = 20000 + +[signer.local.loader] +format = "lodestar" +keys_path = "keys" +secrets_path = "secrets/password.txt" +``` + +:::note +All keys have the same password stored in `secrets/password.txt` +::: - :::note - All keys have the same password stored in `secrets/password.txt` - :::
@@ -215,78 +228,81 @@ To persist proxy keys across restarts, you must enable the proxy store in the co
File - The keys are stored in plain text in a file. This method is unsafe and should only be used for testing. +The keys are stored in plain text in a file. This method is unsafe and should only be used for testing. - #### File structure +#### File structure - ``` - - └── - └── bls - ├── - └── - ``` +``` + +└── + └── bls + ├── + └── +``` - #### Configuration +#### Configuration - ```toml - [signer.local.store] - proxy_dir = "path/to/proxy_dir" - ``` +```toml +[signer.local.store] +proxy_dir = "path/to/proxy_dir" +``` + +Where each `` file contains the following: - Where each `` file contains the following: - ```json - { - "secret": "0x...", - "delegation": { - "message": { - "delegator": "0x...", - "proxy": "0x..." - }, - "signature": "0x..." - } +```json +{ + "secret": "0x...", + "delegation": { + "message": { + "delegator": "0x...", + "proxy": "0x..." + }, + "signature": "0x..." } - ``` +} +``` +
ERC2335 - The keys are stored in a ERC-2335 style keystore, along with a password. This way, you can safely share the keys directory as without the password they are useless. +The keys are stored in a ERC-2335 style keystore, along with a password. This way, you can safely share the keys directory as without the password they are useless. - #### File structure +#### File structure - ``` - ├── - │ └── - │ └── - │ ├── bls/ - │ │ ├── .json - │ │ ├── .sig - │ │ ├── .json - │ │ └── .sig - │ └── ecdsa/ - │ ├── .json - │ └── .sig - └── - └── - └── - ├── bls/ - │ ├── - │ └── - └── ecdsa - └── - ``` +``` +├── +│ └── +│ └── +│ ├── bls/ +│ │ ├── .json +│ │ ├── .sig +│ │ ├── .json +│ │ └── .sig +│ └── ecdsa/ +│ ├── .json +│ └── .sig +└── + └── + └── + ├── bls/ + │ ├── + │ └── + └── ecdsa + └── +``` - #### Configuration +#### Configuration - ```toml - [signer.local.store] - keys_path = "path/to/keys" - secrets_path = "path/to/secrets" - ``` +```toml +[signer.local.store] +keys_path = "path/to/keys" +secrets_path = "path/to/secrets" +``` + +Where the `.json` files contain ERC-2335 keystore, the `.sig` files contain the signature of the delegation, and `` files contain the password to decrypt the keystores. - Where the `.json` files contain ERC-2335 keystore, the `.sig` files contain the signature of the delegation, and `` files contain the password to decrypt the keystores.
### Remote signer @@ -342,17 +358,21 @@ Delegation signatures will be stored in files with the format `/deleg A full example of a config file with Dirk can be found [here](https://github.com/Commit-Boost/commit-boost-client/blob/main/examples/configs/dirk_signer.toml). ## Custom module + We currently provide a test module that needs to be built locally. To build the module run: + ```bash just docker-build-test-modules ``` + :::note We use `just` as command runner. If you don't have it installed, either install it from https://github.com/casey/just or run the commands manually from the `justfile` at the root of the repo. ::: -This will create a Docker image called `test_da_commit` that periodically requests signatures from the validator, and a `test_builder_log` module that logs BuilderAPI events. +This will create a Docker image called `test_da_commit` that periodically requests signatures from the validator. The `cb-config.toml` file needs to be updated as follows: + ```toml [pbs] port = 18550 @@ -376,32 +396,32 @@ id = "DA_COMMIT" type = "commit" docker_image = "test_da_commit" sleep_secs = 5 - -[[modules]] -id = "BUILDER_LOG" -type = "events" -docker_image = "test_builder_log" ``` A few things to note: + - We now added a `signer` section which will be used to create the Signer module. - There is now a `[[modules]]` section which at a minimum needs to specify the module `id`, `type` and `docker_image`. Additional parameters needed for the business logic of the module will also be here, To learn more about developing modules, check out [here](/category/developing). ## Vouch + [Vouch](https://github.com/attestantio/vouch) is a multi-node validator client built by [Attestant](https://www.attestant.io/). Vouch is particular in that it also integrates an MEV-Boost client to interact with relays. The Commit-Boost PBS module is compatible with the Vouch `blockrelay` since it implements the same Builder-API as relays. For example, depending on your setup and preference, you may want to fetch headers from a given relay using Commit-Boost vs using the built-in Vouch `blockrelay`. ### Configuration + Get familiar on how to set up Vouch [here](https://github.com/attestantio/vouch/blob/master/docs/getting_started.md). You can setup Commit-Boost with Vouch in two ways. For simplicity, assume that in Vouch `blockrelay.listen-address: 127.0.0.0:19550` and in Commit-Boost `pbs.port = 18550`. #### Beacon Node to Vouch + In this setup, the BN Builder-API endpoint will be pointing to the Vouch `blockrelay` (e.g. for Lighthouse you will need the flag `--builder=http://127.0.0.0:19550`). Modify the `blockrelay.config` file to add Commit-Boost: + ```json "relays": { "http://127.0.0.0:18550": {} @@ -409,6 +429,7 @@ Modify the `blockrelay.config` file to add Commit-Boost: ``` #### Beacon Node to Commit-Boost + In this setup, the BN Builder-API endpoint will be pointing to the PBS module (e.g. for Lighthouse you will need the flag `--builder=http://127.0.0.0:18550`). This will bypass the `blockrelay` entirely so make sure all relays are properly configured in the `[[relays]]` section. @@ -418,6 +439,7 @@ This approach could also work if you have a multi-beacon-node setup, where some ::: ### Notes + - It's up to you to decide which relays will be connected via Commit-Boost (`[[relays]]` section in the `toml` config) and which via Vouch (additional entries in the `relays` field). Remember that any rate-limit will be shared across the two sidecars, if running on the same machine. - You may occasionally see a `timeout` error during registrations, especially if you're running a large number of validators in the same instance. This can resolve itself as registrations will be cleared later in the epoch when relays are less busy processing other registrations. Alternatively you can also adjust the `builderclient.timeout` option in `.vouch.yml`. diff --git a/docs/docs/get_started/running/binary.md b/docs/docs/get_started/running/binary.md index 385e7a0c..10815d6e 100644 --- a/docs/docs/get_started/running/binary.md +++ b/docs/docs/get_started/running/binary.md @@ -8,24 +8,26 @@ description: Run Commit-Boost modules natively Running the modules natively means you opt out of the security guarantees made by Docker and it's up to you how to setup and ensure the modules run safely. ::: - ## Setup + Get the binary of the module either by compiling from source or by downloading a [published release](https://github.com/Commit-Boost/commit-boost-client/releases). Modules need some environment variables to work correctly. ### Common + - `CB_CONFIG`: required, path to the `.toml` config file. - `CHAIN_SPEC_ENV`: optional, path to a chain spec file. This will override the `[chain]` field in the `.toml` config. - `CB_METRICS_PORT`: optional, port where to expose the `/metrics` endpoint for Prometheus. - `CB_LOGS_DIR`: optional, directory to store logs. This will override the directory in the `.toml` config. ### PBS Module -- `CB_BUILDER_URLS`: optional, comma-separated list of urls to `events` modules where to post builder events. + - `CB_PBS_ENDPOINT`: optional, override to specify the `IP:port` endpoint where the PBS module will open the port for the beacon node. - `CB_MUX_PATH_{ID}`: optional, override where to load mux validator keys for mux with `id=\{ID\}`. ### Signer Module + - `CB_SIGNER_ENDPOINT`: optional, override to specify the `IP:port` endpoint to bind the signer server to. - For loading keys we currently support: - `CB_SIGNER_LOADER_FILE`: path to a `.json` with plaintext keys (for testing purposes only). @@ -40,15 +42,14 @@ Modules need some environment variables to work correctly. - `CB_SIGNER_DIRK_CA_CERT_FILE`: optional, path to the CA certificate file. ### Modules + - `CB_MODULE_ID`: required, unique id of the module. #### Commit modules + - `CB_SIGNER_URL`: required, url to the signer module server. - `CB_SIGNER_JWT`: required, jwt to use for signature requests. -#### Events modules -- `CB_BUILDER_PORT`: required, port to open to receive builder events from the PBS module. - Modules might also have additional envs required, which should be detailed by the maintainers. ## Start @@ -60,4 +61,5 @@ CB_CONFIG=./cb-config.toml commit-boost-pbs ``` ## Security + Running the modules natively means you opt out of the security guarantees made by Docker and it's up to you how to setup and ensure the modules run safely. diff --git a/examples/builder_log/Cargo.toml b/examples/builder_log/Cargo.toml deleted file mode 100644 index 64173a5f..00000000 --- a/examples/builder_log/Cargo.toml +++ /dev/null @@ -1,12 +0,0 @@ -[package] -edition.workspace = true -name = "builder_log" -rust-version.workspace = true -version.workspace = true - -[dependencies] -async-trait.workspace = true -commit-boost = { path = "../../bin" } -eyre.workspace = true -tokio.workspace = true -tracing.workspace = true diff --git a/examples/builder_log/Dockerfile b/examples/builder_log/Dockerfile deleted file mode 100644 index c0fd69b4..00000000 --- a/examples/builder_log/Dockerfile +++ /dev/null @@ -1,29 +0,0 @@ -FROM lukemathwalker/cargo-chef:latest-rust-1 AS chef -WORKDIR /app - -FROM chef AS planner -COPY . . -RUN cargo chef prepare --recipe-path recipe.json - -FROM chef AS builder -COPY --from=planner /app/recipe.json recipe.json - -RUN cargo chef cook --release --recipe-path recipe.json - -RUN apt-get update && apt-get install -y protobuf-compiler - -COPY . . -RUN cargo build --release --bin builder_log - - -FROM ubuntu AS runtime -WORKDIR /app - -RUN apt-get update -RUN apt-get install -y openssl ca-certificates libssl3 libssl-dev - -COPY --from=builder /app/target/release/builder_log /usr/local/bin -ENTRYPOINT ["/usr/local/bin/builder_log"] - - - diff --git a/examples/builder_log/src/main.rs b/examples/builder_log/src/main.rs deleted file mode 100644 index a40df63d..00000000 --- a/examples/builder_log/src/main.rs +++ /dev/null @@ -1,35 +0,0 @@ -use async_trait::async_trait; -use commit_boost::prelude::*; -use tracing::{error, info}; - -#[derive(Debug, Clone)] -struct LogProcessor; - -#[async_trait] -impl OnBuilderApiEvent for LogProcessor { - async fn on_builder_api_event(&self, event: BuilderEvent) { - info!(?event, "Received builder event"); - } -} - -#[tokio::main] -async fn main() -> eyre::Result<()> { - match load_builder_module_config::<()>() { - Ok(config) => { - let _guard = initialize_tracing_log(&config.id, LogsSettings::from_env_config()?); - - info!(module_id = %config.id, "Starting module"); - - let client = BuilderEventClient::new(config.server_port, LogProcessor); - - if let Err(err) = client.run().await { - error!(%err, "Service failed"); - } - } - Err(err) => { - eprintln!("Failed to load module config: {err:?}"); - } - } - - Ok(()) -} diff --git a/justfile b/justfile index 5263aaa1..cc864823 100644 --- a/justfile +++ b/justfile @@ -184,7 +184,6 @@ install-protoc: docker-build-test-modules: docker build -t test_da_commit . -f examples/da_commit/Dockerfile - docker build -t test_builder_log . -f examples/builder_log/Dockerfile docker build -t test_status_api . -f examples/status_api/Dockerfile # Cleans the build directory, removing all built binaries. diff --git a/tests/src/utils.rs b/tests/src/utils.rs index 2ea202a8..5b5b95c8 100644 --- a/tests/src/utils.rs +++ b/tests/src/utils.rs @@ -94,7 +94,6 @@ pub fn to_pbs_config( endpoint: SocketAddr::new(pbs_config.host.into(), pbs_config.port), pbs_config: Arc::new(pbs_config), signer_client: None, - event_publisher: None, all_relays: relays.clone(), relays, muxes: None,