Skip to content

Commit 2fa4b82

Browse files
authored
Merge pull request #46 from Commit-Boost/ltitanb/builder-events
builder events module
2 parents 90cafdf + 43ced3d commit 2fa4b82

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

52 files changed

+930
-551
lines changed

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ members = [
99
"crates/metrics",
1010

1111
"tests",
12-
"examples/da_commit",
12+
"examples/*",
1313
]
1414
resolver = "2"
1515

bin/src/lib.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@ pub mod prelude {
22
pub use cb_common::{
33
commit,
44
commit::request::SignRequest,
5-
config::{load_module_config, StartModuleConfig},
5+
config::{load_builder_module_config, load_commit_module_config, StartCommitModuleConfig},
6+
pbs::{BuilderEvent, BuilderEventClient, OnBuilderApiEvent},
67
utils::{initialize_tracing_log, utcnow_ms, utcnow_ns, utcnow_sec, utcnow_us},
78
};
89
pub use cb_metrics::provider::MetricsProvider;

config.example.toml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,5 +31,11 @@ use_grafana = true
3131

3232
[[modules]]
3333
id = "DA_COMMIT"
34+
type = "commit"
3435
docker_image = "test_da_commit"
3536
sleep_secs = 5
37+
38+
[[modules]]
39+
id = "BUILDER_LOG"
40+
type = "events"
41+
docker_image = "test_builder_log"

crates/cli/src/docker_init.rs

Lines changed: 135 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,10 @@ use std::{path::Path, vec};
22

33
use cb_common::{
44
config::{
5-
CommitBoostConfig, CB_CONFIG_ENV, CB_CONFIG_NAME, JWTS_ENV, METRICS_SERVER_ENV,
6-
MODULE_ID_ENV, MODULE_JWT_ENV, SIGNER_DIR_KEYS, SIGNER_DIR_KEYS_ENV, SIGNER_DIR_SECRETS,
7-
SIGNER_DIR_SECRETS_ENV, SIGNER_KEYS, SIGNER_KEYS_ENV, SIGNER_SERVER_ENV,
5+
CommitBoostConfig, ModuleKind, BUILDER_SERVER_ENV, CB_CONFIG_ENV, CB_CONFIG_NAME, JWTS_ENV,
6+
METRICS_SERVER_ENV, MODULE_ID_ENV, MODULE_JWT_ENV, SIGNER_DIR_KEYS, SIGNER_DIR_KEYS_ENV,
7+
SIGNER_DIR_SECRETS, SIGNER_DIR_SECRETS_ENV, SIGNER_KEYS, SIGNER_KEYS_ENV,
8+
SIGNER_SERVER_ENV,
89
},
910
loader::SignerLoader,
1011
utils::random_jwt,
@@ -51,17 +52,101 @@ pub fn handle_docker_init(config_path: String, output_dir: String) -> Result<()>
5152
let signer_port = 20000;
5253
let signer_server = format!("cb_signer:{signer_port}");
5354

55+
let builder_events_port = 30000;
56+
let mut builder_events_modules = Vec::new();
57+
5458
// setup pbs service
5559
targets.push(PrometheusTargetConfig {
5660
targets: vec![format!("cb_pbs:{metrics_port}")],
5761
labels: PrometheusLabelsConfig { job: "pbs".to_owned() },
5862
});
5963

60-
let pbs_envs = IndexMap::from([
64+
let mut pbs_envs = IndexMap::from([
6165
get_env_same(CB_CONFIG_ENV),
6266
get_env_val(METRICS_SERVER_ENV, &metrics_port.to_string()),
6367
]);
6468

69+
let mut needs_signer_module = cb_config.pbs.with_signer;
70+
71+
// setup modules
72+
if let Some(modules_config) = cb_config.modules {
73+
for module in modules_config {
74+
// TODO: support modules volumes and network
75+
let module_cid = format!("cb_{}", module.id.to_lowercase());
76+
77+
targets.push(PrometheusTargetConfig {
78+
targets: vec![format!("{module_cid}:{metrics_port}")],
79+
labels: PrometheusLabelsConfig { job: module_cid.clone() },
80+
});
81+
82+
let module_service = match module.kind {
83+
// a commit module needs a JWT and access to the signer network
84+
ModuleKind::Commit => {
85+
needs_signer_module = true;
86+
87+
let jwt = random_jwt();
88+
let jwt_name = format!("CB_JWT_{}", module.id.to_uppercase());
89+
90+
// module ids are assumed unique, so envs dont override each other
91+
let module_envs = IndexMap::from([
92+
get_env_val(MODULE_ID_ENV, &module.id),
93+
get_env_same(CB_CONFIG_ENV),
94+
get_env_interp(MODULE_JWT_ENV, &jwt_name),
95+
get_env_val(METRICS_SERVER_ENV, &metrics_port.to_string()),
96+
get_env_val(SIGNER_SERVER_ENV, &signer_server),
97+
]);
98+
99+
envs.insert(jwt_name.clone(), jwt.clone());
100+
jwts.insert(module.id.clone(), jwt);
101+
102+
Service {
103+
container_name: Some(module_cid.clone()),
104+
image: Some(module.docker_image),
105+
// TODO: allow service to open ports here
106+
networks: Networks::Simple(vec![
107+
METRICS_NETWORK.to_owned(),
108+
SIGNER_NETWORK.to_owned(),
109+
]),
110+
volumes: vec![config_volume.clone()],
111+
environment: Environment::KvPair(module_envs),
112+
depends_on: DependsOnOptions::Simple(vec!["cb_signer".to_owned()]),
113+
..Service::default()
114+
}
115+
}
116+
// an event module just needs a port to listen on
117+
ModuleKind::Events => {
118+
// module ids are assumed unique, so envs dont override each other
119+
let module_envs = IndexMap::from([
120+
get_env_val(MODULE_ID_ENV, &module.id),
121+
get_env_same(CB_CONFIG_ENV),
122+
get_env_val(METRICS_SERVER_ENV, &metrics_port.to_string()),
123+
get_env_val(BUILDER_SERVER_ENV, &builder_events_port.to_string()),
124+
]);
125+
126+
builder_events_modules.push(format!("{module_cid}:{builder_events_port}"));
127+
128+
Service {
129+
container_name: Some(module_cid.clone()),
130+
image: Some(module.docker_image),
131+
networks: Networks::Simple(vec![METRICS_NETWORK.to_owned()]),
132+
volumes: vec![config_volume.clone()],
133+
environment: Environment::KvPair(module_envs),
134+
depends_on: DependsOnOptions::Simple(vec!["cb_pbs".to_owned()]),
135+
..Service::default()
136+
}
137+
}
138+
};
139+
140+
services.insert(module_cid, Some(module_service));
141+
}
142+
};
143+
144+
if !builder_events_modules.is_empty() {
145+
let env = builder_events_modules.join(",");
146+
let (k, v) = get_env_val(BUILDER_SERVER_ENV, &env);
147+
pbs_envs.insert(k, v);
148+
}
149+
65150
let pbs_service = Service {
66151
container_name: Some("cb_pbs".to_owned()),
67152
image: Some(cb_config.pbs.docker_image),
@@ -77,102 +162,68 @@ pub fn handle_docker_init(config_path: String, output_dir: String) -> Result<()>
77162

78163
services.insert("cb_pbs".to_owned(), Some(pbs_service));
79164

80-
// setup modules
81-
if let Some(modules_config) = cb_config.modules {
82-
for module in modules_config {
83-
// TODO: support modules volumes and network
84-
let module_cid = format!("cb_{}", module.id.to_lowercase());
165+
// TODO: validate if we have signer modules but not signer config
166+
167+
// setup signer service
168+
169+
if let Some(signer_config) = cb_config.signer {
170+
if needs_signer_module {
171+
let mut volumes = vec![config_volume.clone()];
85172

86173
targets.push(PrometheusTargetConfig {
87-
targets: vec![format!("{module_cid}:{metrics_port}")],
88-
labels: PrometheusLabelsConfig { job: module_cid.clone() },
174+
targets: vec![format!("cb_signer:{metrics_port}")],
175+
labels: PrometheusLabelsConfig { job: "signer".into() },
89176
});
90177

91-
let jwt = random_jwt();
92-
let jwt_name = format!("CB_JWT_{}", module.id.to_uppercase());
93-
94-
// module ids are assumed unique, so envs dont override each other
95-
let module_envs = IndexMap::from([
96-
get_env_val(MODULE_ID_ENV, &module.id),
178+
let mut signer_envs = IndexMap::from([
97179
get_env_same(CB_CONFIG_ENV),
98-
get_env_interp(MODULE_JWT_ENV, &jwt_name),
180+
get_env_same(JWTS_ENV),
99181
get_env_val(METRICS_SERVER_ENV, &metrics_port.to_string()),
100-
get_env_val(SIGNER_SERVER_ENV, &signer_server),
182+
get_env_val(SIGNER_SERVER_ENV, &signer_port.to_string()),
101183
]);
102184

103-
envs.insert(jwt_name.clone(), jwt.clone());
104-
jwts.insert(module.id.clone(), jwt);
185+
// TODO: generalize this, different loaders may not need volumes but eg ports
186+
match signer_config.loader {
187+
SignerLoader::File { key_path } => {
188+
volumes.push(Volumes::Simple(format!("./{}:{}:ro", key_path, SIGNER_KEYS)));
189+
let (k, v) = get_env_val(SIGNER_KEYS_ENV, SIGNER_KEYS);
190+
signer_envs.insert(k, v);
191+
}
192+
SignerLoader::ValidatorsDir { keys_path, secrets_path } => {
193+
volumes.push(Volumes::Simple(format!("{}:{}:ro", keys_path, SIGNER_DIR_KEYS)));
194+
let (k, v) = get_env_val(SIGNER_DIR_KEYS_ENV, SIGNER_DIR_KEYS);
195+
signer_envs.insert(k, v);
196+
197+
volumes.push(Volumes::Simple(format!(
198+
"{}:{}:ro",
199+
secrets_path, SIGNER_DIR_SECRETS
200+
)));
201+
let (k, v) = get_env_val(SIGNER_DIR_SECRETS_ENV, SIGNER_DIR_SECRETS);
202+
signer_envs.insert(k, v);
203+
}
204+
};
205+
206+
// write jwts to env
207+
let jwts_json = serde_json::to_string(&jwts).unwrap().clone();
208+
envs.insert(JWTS_ENV.into(), format!("{jwts_json:?}"));
105209

106-
let module_service = Service {
107-
container_name: Some(module_cid.clone()),
108-
image: Some(module.docker_image),
109-
// TODO: allow service to open ports here
210+
let signer_service = Service {
211+
container_name: Some("cb_signer".to_owned()),
212+
image: Some(signer_config.docker_image),
110213
networks: Networks::Simple(vec![
111214
METRICS_NETWORK.to_owned(),
112215
SIGNER_NETWORK.to_owned(),
113216
]),
114-
volumes: vec![config_volume.clone()],
115-
environment: Environment::KvPair(module_envs),
116-
depends_on: DependsOnOptions::Simple(vec!["cb_signer".to_owned()]),
217+
volumes,
218+
environment: Environment::KvPair(signer_envs),
117219
..Service::default()
118220
};
119221

120-
services.insert(module_cid, Some(module_service));
222+
services.insert("cb_signer".to_owned(), Some(signer_service));
121223
}
122-
};
123-
124-
// TODO: validate if we have signer modules but not signer config
125-
126-
// setup signer service
127-
if let Some(signer_config) = cb_config.signer {
128-
let mut volumes = vec![config_volume.clone()];
129-
130-
targets.push(PrometheusTargetConfig {
131-
targets: vec![format!("cb_signer:{metrics_port}")],
132-
labels: PrometheusLabelsConfig { job: "signer".into() },
133-
});
134-
135-
let mut signer_envs = IndexMap::from([
136-
get_env_same(CB_CONFIG_ENV),
137-
get_env_same(JWTS_ENV),
138-
get_env_val(METRICS_SERVER_ENV, &metrics_port.to_string()),
139-
get_env_val(SIGNER_SERVER_ENV, &signer_port.to_string()),
140-
]);
141-
142-
// TODO: generalize this, different loaders may not need volumes but eg ports
143-
match signer_config.loader {
144-
SignerLoader::File { key_path } => {
145-
volumes.push(Volumes::Simple(format!("./{}:{}:ro", key_path, SIGNER_KEYS)));
146-
let (k, v) = get_env_val(SIGNER_KEYS_ENV, SIGNER_KEYS);
147-
signer_envs.insert(k, v);
148-
}
149-
SignerLoader::ValidatorsDir { keys_path, secrets_path } => {
150-
volumes.push(Volumes::Simple(format!("{}:{}:ro", keys_path, SIGNER_DIR_KEYS)));
151-
let (k, v) = get_env_val(SIGNER_DIR_KEYS_ENV, SIGNER_DIR_KEYS);
152-
signer_envs.insert(k, v);
153-
154-
volumes
155-
.push(Volumes::Simple(format!("{}:{}:ro", secrets_path, SIGNER_DIR_SECRETS)));
156-
let (k, v) = get_env_val(SIGNER_DIR_SECRETS_ENV, SIGNER_DIR_SECRETS);
157-
signer_envs.insert(k, v);
158-
}
159-
};
160-
161-
// write jwts to env
162-
let jwts_json = serde_json::to_string(&jwts)?.clone();
163-
envs.insert(JWTS_ENV.into(), format!("{jwts_json:?}"));
164-
165-
let signer_service = Service {
166-
container_name: Some("cb_signer".to_owned()),
167-
image: Some(signer_config.docker_image),
168-
networks: Networks::Simple(vec![METRICS_NETWORK.to_owned(), SIGNER_NETWORK.to_owned()]),
169-
volumes,
170-
environment: Environment::KvPair(signer_envs),
171-
..Service::default()
172-
};
173-
174-
services.insert("cb_signer".to_owned(), Some(signer_service));
175-
};
224+
} else if needs_signer_module {
225+
panic!("Signer module required but no signer config provided");
226+
}
176227

177228
// setup metrics services
178229
// TODO: make this metrics optional?
@@ -274,6 +325,7 @@ fn get_env_interp(k: &str, v: &str) -> (String, Option<SingleValue>) {
274325
get_env_val(k, &format!("${{{v}}}"))
275326
}
276327

328+
// FOO=bar
277329
fn get_env_val(k: &str, v: &str) -> (String, Option<SingleValue>) {
278330
(k.into(), Some(SingleValue::String(v.into())))
279331
}

crates/common/Cargo.toml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,18 @@ rust-version.workspace = true
88
# ethereum
99
alloy = { workspace = true, features = ["ssz"] }
1010
ethereum_ssz.workspace = true
11+
ssz_types.workspace = true
1112
ethereum_ssz_derive.workspace = true
13+
ethereum_serde_utils.workspace = true
14+
ethereum-types.workspace = true
1215

1316
# networking
17+
axum.workspace = true
1418
reqwest.workspace = true
1519

20+
# async / threads
21+
tokio.workspace = true
22+
1623
# serialization
1724
toml.workspace = true
1825
serde.workspace = true

0 commit comments

Comments
 (0)