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
7 changes: 7 additions & 0 deletions config.example.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,11 @@ docker_image = "ghcr.io/commit-boost/pbs:latest"
# Whether to enable the PBS module to request signatures from the Signer module (not used in the default PBS image)
# OPTIONAL, DEFAULT: false
with_signer = false
# Host to receive BuilderAPI calls from beacon node
# OPTIONAL, DEFAULT: 127.0.0.1
host = "127.0.0.1"
# Port to receive BuilderAPI calls from beacon node
# OPTIONAL, DEFAULT: 18550
port = 18550
# Whether to forward `status` calls to relays or skip and return 200
# OPTIONAL, DEFAULT: true
Expand Down Expand Up @@ -137,6 +141,9 @@ SOME_ENV_VAR = "some_value"
# Configuration for how metrics should be collected and scraped
# OPTIONAL, skip metrics collection if missing
[metrics]
# Host for prometheus, grafana, and cadvisor
# OPTIONAL, DEFAULT: 127.0.0.1
host = "127.0.0.1"
# Path to a `prometheus.yml` file to use in Prometheus. If using a custom config file, be sure to add a
# file discovery section as follows:
# ```yml
Expand Down
47 changes: 29 additions & 18 deletions crates/cli/src/docker_init.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
use std::{path::Path, vec};
use std::{
net::{Ipv4Addr, SocketAddr},
path::Path,
vec,
};

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_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,
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,
},
signer::{ProxyStore, SignerLoader},
types::ModuleId,
Expand Down Expand Up @@ -233,6 +237,19 @@ pub fn handle_docker_init(config_path: String, output_dir: String) -> Result<()>
pbs_envs.insert(k, v);
}

// ports
let host_endpoint =
SocketAddr::from((cb_config.pbs.pbs_config.host, cb_config.pbs.pbs_config.port));
let ports = Ports::Short(vec![format!("{}:{}", host_endpoint, cb_config.pbs.pbs_config.port)]);
exposed_ports_warn
.push(format!("pbs has an exported port on {}", cb_config.pbs.pbs_config.port));

// inside the container expose on 0.0.0.0
let container_endpoint =
SocketAddr::from((Ipv4Addr::UNSPECIFIED, cb_config.pbs.pbs_config.port));
let (key, val) = get_env_val(PBS_ENDPOINT_ENV, &container_endpoint.to_string());
pbs_envs.insert(key, val);

// volumes
let mut pbs_volumes = vec![config_volume.clone()];
pbs_volumes.extend(chain_spec_volume.clone());
Expand All @@ -245,16 +262,10 @@ pub fn handle_docker_init(config_path: String, output_dir: String) -> Result<()>
Networks::default()
};

exposed_ports_warn
.push(format!("pbs has an exported port on {}", cb_config.pbs.pbs_config.port));

let pbs_service = Service {
container_name: Some("cb_pbs".to_owned()),
image: Some(cb_config.pbs.docker_image),
ports: Ports::Short(vec![format!(
"{}:{}",
cb_config.pbs.pbs_config.port, cb_config.pbs.pbs_config.port
)]),
ports,
networks: pbs_networs,
volumes: pbs_volumes,
environment: Environment::KvPair(pbs_envs),
Expand Down Expand Up @@ -408,7 +419,7 @@ pub fn handle_docker_init(config_path: String, output_dir: String) -> Result<()>
image: Some("prom/prometheus:latest".to_owned()),
volumes: vec![prom_volume, targets_volume, data_volume],
// to inspect prometheus from localhost
ports: Ports::Short(vec!["9090:9090".to_owned()]),
ports: Ports::Short(vec![format!("{}:9090", metrics_config.host)]),
networks: Networks::Simple(vec![METRICS_NETWORK.to_owned()]),
..Service::default()
};
Expand All @@ -435,7 +446,7 @@ pub fn handle_docker_init(config_path: String, output_dir: String) -> Result<()>
let grafana_service = Service {
container_name: Some("cb_grafana".to_owned()),
image: Some("grafana/grafana:latest".to_owned()),
ports: Ports::Short(vec!["3000:3000".to_owned()]),
ports: Ports::Short(vec![format!("{}:3000", metrics_config.host)]),
networks: Networks::Simple(vec![METRICS_NETWORK.to_owned()]),
depends_on: DependsOnOptions::Simple(vec!["cb_prometheus".to_owned()]),
environment: Environment::List(vec!["GF_SECURITY_ADMIN_PASSWORD=admin".to_owned()]),
Expand Down Expand Up @@ -475,7 +486,7 @@ pub fn handle_docker_init(config_path: String, output_dir: String) -> Result<()>
Some(Service {
container_name: Some("cb_cadvisor".to_owned()),
image: Some("gcr.io/cadvisor/cadvisor".to_owned()),
ports: Ports::Short(vec![format!("{cadvisor_port}:8080")]),
ports: Ports::Short(vec![format!("{}:8080", metrics_config.host)]),
networks: Networks::Simple(vec![METRICS_NETWORK.to_owned()]),
volumes: vec![
Volumes::Simple("/var/run/docker.sock:/var/run/docker.sock:ro".to_owned()),
Expand Down Expand Up @@ -540,17 +551,17 @@ pub fn handle_docker_init(config_path: String, output_dir: String) -> Result<()>
Ok(())
}

// FOO=${FOO}
/// FOO=${FOO}
fn get_env_same(k: &str) -> (String, Option<SingleValue>) {
get_env_interp(k, k)
}

// FOO=${BAR}
/// FOO=${BAR}
fn get_env_interp(k: &str, v: &str) -> (String, Option<SingleValue>) {
get_env_val(k, &format!("${{{v}}}"))
}

// FOO=bar
/// FOO=bar
fn get_env_val(k: &str, v: &str) -> (String, Option<SingleValue>) {
(k.into(), Some(SingleValue::String(v.into())))
}
Expand Down
3 changes: 3 additions & 0 deletions crates/common/src/config/constants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ 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";

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

pub const SIGNER_IMAGE_DEFAULT: &str = "ghcr.io/commit-boost/signer:latest";
Expand Down
7 changes: 6 additions & 1 deletion crates/common/src/config/metrics.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
use std::net::Ipv4Addr;

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

use super::{constants::METRICS_PORT_ENV, load_optional_env_var};
use crate::utils::default_bool;
use crate::utils::{default_bool, default_host};

#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct MetricsConfig {
/// Host for prometheus, grafana, and cadvisor
#[serde(default = "default_host")]
pub host: Ipv4Addr,
/// Path to prometheus config file
pub prometheus_config: String,
/// Whether to start the grafana service
Expand Down
2 changes: 1 addition & 1 deletion crates/common/src/config/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ impl CommitBoostConfig {
// When loading the config from the environment, it's important that every path
// is replaced with the correct value if the config is loaded inside a container
pub fn from_env_path() -> Result<Self> {
let config = if let Ok(path) = std::env::var(CHAIN_SPEC_ENV) {
let config = if let Some(path) = load_optional_env_var(CHAIN_SPEC_ENV) {
// if the chain spec file is set, load it separately
let chain: Chain = load_chain_from_file(path.parse()?)?;
let rest_config: HelperConfig = load_file_from_env(CONFIG_ENV)?;
Expand Down
44 changes: 40 additions & 4 deletions crates/common/src/config/pbs.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,30 @@
//! Configuration for the PBS module

use std::{collections::HashMap, sync::Arc};
use std::{
collections::HashMap,
net::{Ipv4Addr, SocketAddr},
sync::Arc,
};

use alloy::primitives::{utils::format_ether, U256};
use eyre::{ensure, Result};
use serde::{de::DeserializeOwned, Deserialize, Serialize};
use url::Url;

use super::{constants::PBS_IMAGE_DEFAULT, CommitBoostConfig};
use super::{
constants::PBS_IMAGE_DEFAULT, load_optional_env_var, CommitBoostConfig, PBS_ENDPOINT_ENV,
};
use crate::{
commit::client::SignerClient,
config::{load_env_var, load_file_from_env, CONFIG_ENV, MODULE_JWT_ENV, SIGNER_URL_ENV},
pbs::{BuilderEventPublisher, DefaultTimeout, RelayClient, RelayEntry, LATE_IN_SLOT_TIME_MS},
pbs::{
BuilderEventPublisher, DefaultTimeout, RelayClient, RelayEntry, DEFAULT_PBS_PORT,
LATE_IN_SLOT_TIME_MS,
},
types::Chain,
utils::{as_eth_str, default_bool, default_u256, default_u64, WEI_PER_ETH},
utils::{
as_eth_str, default_bool, default_host, default_u16, default_u256, default_u64, WEI_PER_ETH,
},
};

#[derive(Debug, Clone, Deserialize, Serialize)]
Expand All @@ -36,7 +47,11 @@ pub struct RelayConfig {

#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct PbsConfig {
/// Host to receive BuilderAPI calls from beacon node
#[serde(default = "default_host")]
pub host: Ipv4Addr,
/// Port to receive BuilderAPI calls from beacon node
#[serde(default = "default_u16::<DEFAULT_PBS_PORT>")]
pub port: u16,
/// Whether to forward `get_status` to relays or skip it
#[serde(default = "default_bool::<true>")]
Expand Down Expand Up @@ -112,6 +127,8 @@ pub struct StaticPbsConfig {
pub struct PbsModuleConfig {
/// Chain spec
pub chain: Chain,
/// Endpoint to receive BuilderAPI calls from beacon node
pub endpoint: SocketAddr,
/// Pbs default config
pub pbs_config: Arc<PbsConfig>,
/// List of relays
Expand All @@ -130,12 +147,20 @@ fn default_pbs() -> String {
pub fn load_pbs_config() -> Result<PbsModuleConfig> {
let config = CommitBoostConfig::from_env_path()?;

// use endpoint from env if set, otherwise use default host and port
let endpoint = if let Some(endpoint) = load_optional_env_var(PBS_ENDPOINT_ENV) {
endpoint.parse()?
} else {
SocketAddr::from((config.pbs.pbs_config.host, config.pbs.pbs_config.port))
};

let relay_clients =
config.relays.into_iter().map(RelayClient::new).collect::<Result<Vec<_>>>()?;
let maybe_publiher = BuilderEventPublisher::new_from_env()?;

Ok(PbsModuleConfig {
chain: config.chain,
endpoint,
pbs_config: Arc::new(config.pbs.pbs_config),
relays: relay_clients,
signer_client: None,
Expand Down Expand Up @@ -164,6 +189,16 @@ pub fn load_pbs_custom_config<T: DeserializeOwned>() -> Result<(PbsModuleConfig,
let cb_config: StubConfig<T> = load_file_from_env(CONFIG_ENV)?;
cb_config.pbs.static_config.pbs_config.validate()?;

// use endpoint from env if set, otherwise use default host and port
let endpoint = if let Some(endpoint) = load_optional_env_var(PBS_ENDPOINT_ENV) {
endpoint.parse()?
} else {
SocketAddr::from((
cb_config.pbs.static_config.pbs_config.host,
cb_config.pbs.static_config.pbs_config.port,
))
};

let relay_clients =
cb_config.relays.into_iter().map(RelayClient::new).collect::<Result<Vec<_>>>()?;
let maybe_publiher = BuilderEventPublisher::new_from_env()?;
Expand All @@ -180,6 +215,7 @@ pub fn load_pbs_custom_config<T: DeserializeOwned>() -> Result<(PbsModuleConfig,
Ok((
PbsModuleConfig {
chain: cb_config.chain,
endpoint,
pbs_config: Arc::new(cb_config.pbs.static_config.pbs_config),
relays: relay_clients,
signer_client,
Expand Down
2 changes: 2 additions & 0 deletions crates/common/src/pbs/constants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ pub const HEADER_START_TIME_UNIX_MS: &str = "X-MEVBoost-StartTimeUnixMS";
pub const BUILDER_EVENTS_PATH: &str = "/builder_events";
pub const DEFAULT_PBS_JWT_KEY: &str = "DEFAULT_PBS";

pub const DEFAULT_PBS_PORT: u16 = 18550;

#[non_exhaustive]
pub struct DefaultTimeout;
impl DefaultTimeout {
Expand Down
13 changes: 12 additions & 1 deletion crates/common/src/utils.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
use std::time::{SystemTime, UNIX_EPOCH};
use std::{
net::Ipv4Addr,
time::{SystemTime, UNIX_EPOCH},
};

use alloy::{
primitives::U256,
Expand Down Expand Up @@ -122,10 +125,18 @@ pub const fn default_u64<const U: u64>() -> u64 {
U
}

pub const fn default_u16<const U: u16>() -> u16 {
U
}

pub const fn default_bool<const U: bool>() -> bool {
U
}

pub const fn default_host() -> Ipv4Addr {
Ipv4Addr::LOCALHOST
}

pub const fn default_u256() -> U256 {
U256::ZERO
}
Expand Down
4 changes: 1 addition & 3 deletions crates/pbs/src/service.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
use std::net::SocketAddr;

use cb_common::constants::COMMIT_BOOST_VERSION;
use cb_metrics::provider::MetricsProvider;
use eyre::{Context, Result};
Expand All @@ -18,7 +16,7 @@ pub struct PbsService;

impl PbsService {
pub async fn run<S: BuilderApiState, A: BuilderApi<S>>(state: PbsState<S>) -> Result<()> {
let address = SocketAddr::from(([0, 0, 0, 0], state.config.pbs_config.port));
let address = 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, ?address, events_subs, chain =? state.config.chain, "starting PBS service");
Expand Down
9 changes: 8 additions & 1 deletion tests/tests/pbs_integration.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
use std::{sync::Arc, time::Duration, u64};
use std::{
net::{Ipv4Addr, SocketAddr},
sync::Arc,
time::Duration,
u64,
};

use alloy::primitives::U256;
use cb_common::{
Expand All @@ -19,6 +24,7 @@ use tracing::info;

fn get_pbs_static_config(port: u16) -> PbsConfig {
PbsConfig {
host: Ipv4Addr::UNSPECIFIED,
port,
wait_all_registrations: true,
relay_check: true,
Expand All @@ -35,6 +41,7 @@ fn get_pbs_static_config(port: u16) -> PbsConfig {
fn to_pbs_config(chain: Chain, pbs_config: PbsConfig, relays: Vec<RelayClient>) -> PbsModuleConfig {
PbsModuleConfig {
chain,
endpoint: SocketAddr::new(pbs_config.host.into(), pbs_config.port),
pbs_config: Arc::new(pbs_config),
signer_client: None,
event_publisher: None,
Expand Down