From e83b79ea2a723138b685848239861f648870ea41 Mon Sep 17 00:00:00 2001 From: David Petrov Date: Wed, 26 Jun 2024 10:53:40 +0300 Subject: [PATCH 1/3] refactor(BuilderApi): rename to `extra_routes` --- crates/pbs/src/boost.rs | 2 +- crates/pbs/src/routes/router.rs | 2 +- examples/custom_boost.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/pbs/src/boost.rs b/crates/pbs/src/boost.rs index a0c1b34e..6e515d2e 100644 --- a/crates/pbs/src/boost.rs +++ b/crates/pbs/src/boost.rs @@ -14,7 +14,7 @@ use crate::{ #[async_trait] pub trait BuilderApi: 'static { /// Use to extend the BuilderApi - fn routes() -> Option>> { + fn extra_routes() -> Option>> { None } diff --git a/crates/pbs/src/routes/router.rs b/crates/pbs/src/routes/router.rs index 3f37e4cb..e8a7af3a 100644 --- a/crates/pbs/src/routes/router.rs +++ b/crates/pbs/src/routes/router.rs @@ -25,7 +25,7 @@ pub fn create_app_router>(state: BuilderSta let builder_api = Router::new().nest(BULDER_API_PATH, builder_routes); - let app = if let Some(extra_routes) = T::routes() { + let app = if let Some(extra_routes) = T::extra_routes() { builder_api.merge(extra_routes) } else { builder_api diff --git a/examples/custom_boost.rs b/examples/custom_boost.rs index 153f611c..e5fa7e18 100644 --- a/examples/custom_boost.rs +++ b/examples/custom_boost.rs @@ -42,7 +42,7 @@ impl BuilderApi for MyBuilderApi { Ok(()) } - fn routes() -> Option>> { + fn extra_routes() -> Option>> { let router = Router::new().route("/custom/stats", get(handle_stats)); Some(router) } From 79e4c9edfd8c85d888214f8e9324bd9585459990 Mon Sep 17 00:00:00 2001 From: David Petrov Date: Wed, 26 Jun 2024 14:39:12 +0300 Subject: [PATCH 2/3] feat: launch module from docker image --- config.example.toml | 7 +++++- crates/cli/Cargo.toml | 2 ++ crates/cli/src/lib.rs | 49 +++++++++++++++++++++++++++++-------- crates/common/src/config.rs | 46 +++++++++++++++++++++++++++++++++- 4 files changed, 92 insertions(+), 12 deletions(-) diff --git a/config.example.toml b/config.example.toml index 5afa0f10..d552f45b 100644 --- a/config.example.toml +++ b/config.example.toml @@ -17,6 +17,11 @@ address = "127.0.0.1:33950" key_path = "keys.example.json" [[modules]] -id = "DA_COMMIT" +id = "DA_COMMIT_RAW" path = "target/debug/da_commit" sleep_secs = 5 + +[[modules]] +id = "DA_COMMIT" +docker_image="da_commit" +sleep_secs = 5 \ No newline at end of file diff --git a/crates/cli/Cargo.toml b/crates/cli/Cargo.toml index 689017ec..c407fa6f 100644 --- a/crates/cli/Cargo.toml +++ b/crates/cli/Cargo.toml @@ -23,3 +23,5 @@ eyre.workspace = true tree_hash.workspace = true tree_hash_derive.workspace = true + +bollard = "0.16.1" \ No newline at end of file diff --git a/crates/cli/src/lib.rs b/crates/cli/src/lib.rs index e9400082..c4833a23 100644 --- a/crates/cli/src/lib.rs +++ b/crates/cli/src/lib.rs @@ -1,7 +1,7 @@ use std::process::Stdio; use cb_common::{ - config::{CommitBoostConfig, CONFIG_PATH_ENV, MODULE_ID_ENV}, + config::{CommitBoostConfig, ModuleSource, CONFIG_PATH_ENV, MODULE_ID_ENV}, utils::print_logo, }; use cb_crypto::service::SigningService; @@ -69,24 +69,53 @@ impl Args { Command::Start { config: config_path } => { let config = CommitBoostConfig::from_file(&config_path); + // Initialize Docker client + let docker = bollard::Docker::connect_with_local_defaults().expect("Failed to connect to Docker"); + if let Some(modules) = config.modules { let signer_config = config.signer.expect("missing signer config with modules"); + // start signing server + tokio::spawn(SigningService::run(config.chain, signer_config)); // this mocks the commit boost client starting containers, processes etc let mut child_handles = Vec::with_capacity(modules.len()); for module in modules { - let child = std::process::Command::new(module.path) - .env(MODULE_ID_ENV, module.id) - .env(CONFIG_PATH_ENV, &config_path) - .spawn() - .expect("failed to start process"); + match module.source { + ModuleSource::DockerImageId(docker_image) => { + let config = bollard::container::Config { + image: Some(docker_image.clone()), + host_config: Some(bollard::secret::HostConfig { + binds: { + let full_config_path = std::fs::canonicalize(&config_path).unwrap().to_string_lossy().to_string(); + Some(vec![format!("{}:{}", full_config_path, "/config.toml")]) + }, + network_mode: Some(String::from("host")), // Use the host network + ..Default::default() + }), + env: Some(vec![ + format!("{}={}", MODULE_ID_ENV, module.id), + format!("{}={}", CONFIG_PATH_ENV, "/config.toml"), + ]), + ..Default::default() + }; - child_handles.push(child); - } + let container = docker.create_container::<&str, String>(None, config).await?; + let container_id = container.id; + docker.start_container::(&container_id, None).await?; + println!("Started container: {} from image {}", container_id, &docker_image); + }, + ModuleSource::Path(path) => { + let child = std::process::Command::new(path) + .env(MODULE_ID_ENV, module.id) + .env(CONFIG_PATH_ENV, &config_path) + .spawn() + .expect("failed to start process"); - // start signing server - tokio::spawn(SigningService::run(config.chain, signer_config)); + child_handles.push(child); + }, + } + } } // start pbs server diff --git a/crates/common/src/config.rs b/crates/common/src/config.rs index 8d0b6b28..b59ec0c5 100644 --- a/crates/common/src/config.rs +++ b/crates/common/src/config.rs @@ -113,13 +113,57 @@ const fn default_u256() -> U256 { } #[derive(Debug, Deserialize, Serialize)] +pub enum ModuleSource { + #[serde(rename = "path")] + Path(String), + #[serde(rename = "docker_image")] + DockerImageId(String), +} + +#[derive(Debug, Serialize)] +#[serde(deny_unknown_fields)] pub struct ModuleConfig { pub id: String, - pub path: String, + #[serde(flatten)] + pub source: ModuleSource, #[serde(flatten)] pub extra: T, } +impl<'de, T> Deserialize<'de> for ModuleConfig +where + T: Deserialize<'de>, +{ + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + #[derive(Deserialize)] + struct InnerModuleConfig { + id: String, + path: Option, + docker_image: Option, + #[serde(flatten)] + extra: T, + } + + let inner = InnerModuleConfig::deserialize(deserializer)?; + + let source = match (inner.path, inner.docker_image) { + (Some(path), None) => ModuleSource::Path(path), + (None, Some(docker_image)) => ModuleSource::DockerImageId(docker_image), + (Some(_), Some(_)) => return Err(de::Error::custom("Cannot have both `path` and `docker_image`")), + (None, None) => return Err(de::Error::custom("Must have either `path` or `docker_image`")), + }; + + Ok(ModuleConfig { + id: inner.id, + source, + extra: inner.extra, + }) + } +} + #[derive(Debug, Deserialize, Serialize)] pub struct StartModuleConfig { pub chain: Chain, From f4b91ffd49f6eef045e3a7325b9c0cfb4b7cf4be Mon Sep 17 00:00:00 2001 From: David Petrov Date: Wed, 26 Jun 2024 18:38:50 +0300 Subject: [PATCH 3/3] chore!: remove binary module sourcing --- config.example.toml | 5 ---- crates/cli/src/lib.rs | 57 ++++++++++++++----------------------- crates/common/src/config.rs | 46 +----------------------------- 3 files changed, 22 insertions(+), 86 deletions(-) diff --git a/config.example.toml b/config.example.toml index d552f45b..3dad10b9 100644 --- a/config.example.toml +++ b/config.example.toml @@ -16,11 +16,6 @@ address = "127.0.0.1:33950" [signer.loader] key_path = "keys.example.json" -[[modules]] -id = "DA_COMMIT_RAW" -path = "target/debug/da_commit" -sleep_secs = 5 - [[modules]] id = "DA_COMMIT" docker_image="da_commit" diff --git a/crates/cli/src/lib.rs b/crates/cli/src/lib.rs index c4833a23..b2c7413e 100644 --- a/crates/cli/src/lib.rs +++ b/crates/cli/src/lib.rs @@ -1,7 +1,7 @@ use std::process::Stdio; use cb_common::{ - config::{CommitBoostConfig, ModuleSource, CONFIG_PATH_ENV, MODULE_ID_ENV}, + config::{CommitBoostConfig, CONFIG_PATH_ENV, MODULE_ID_ENV}, utils::print_logo, }; use cb_crypto::service::SigningService; @@ -77,44 +77,29 @@ impl Args { // start signing server tokio::spawn(SigningService::run(config.chain, signer_config)); - // this mocks the commit boost client starting containers, processes etc - let mut child_handles = Vec::with_capacity(modules.len()); - for module in modules { - match module.source { - ModuleSource::DockerImageId(docker_image) => { - let config = bollard::container::Config { - image: Some(docker_image.clone()), - host_config: Some(bollard::secret::HostConfig { - binds: { - let full_config_path = std::fs::canonicalize(&config_path).unwrap().to_string_lossy().to_string(); - Some(vec![format!("{}:{}", full_config_path, "/config.toml")]) - }, - network_mode: Some(String::from("host")), // Use the host network - ..Default::default() - }), - env: Some(vec![ - format!("{}={}", MODULE_ID_ENV, module.id), - format!("{}={}", CONFIG_PATH_ENV, "/config.toml"), - ]), - ..Default::default() - }; + let config = bollard::container::Config { + image: Some(module.docker_image.clone()), + host_config: Some(bollard::secret::HostConfig { + binds: { + let full_config_path = std::fs::canonicalize(&config_path).unwrap().to_string_lossy().to_string(); + Some(vec![format!("{}:{}", full_config_path, "/config.toml")]) + }, + network_mode: Some(String::from("host")), // Use the host network + ..Default::default() + }), + env: Some(vec![ + format!("{}={}", MODULE_ID_ENV, module.id), + format!("{}={}", CONFIG_PATH_ENV, "/config.toml"), + ]), + ..Default::default() + }; - let container = docker.create_container::<&str, String>(None, config).await?; - let container_id = container.id; - docker.start_container::(&container_id, None).await?; - println!("Started container: {} from image {}", container_id, &docker_image); - }, - ModuleSource::Path(path) => { - let child = std::process::Command::new(path) - .env(MODULE_ID_ENV, module.id) - .env(CONFIG_PATH_ENV, &config_path) - .spawn() - .expect("failed to start process"); + let container = docker.create_container::<&str, String>(None, config).await?; + let container_id = container.id; + docker.start_container::(&container_id, None).await?; - child_handles.push(child); - }, - } + println!("Started container: {} from image {}", container_id, module.docker_image); } } diff --git a/crates/common/src/config.rs b/crates/common/src/config.rs index b59ec0c5..f54018e2 100644 --- a/crates/common/src/config.rs +++ b/crates/common/src/config.rs @@ -113,57 +113,13 @@ const fn default_u256() -> U256 { } #[derive(Debug, Deserialize, Serialize)] -pub enum ModuleSource { - #[serde(rename = "path")] - Path(String), - #[serde(rename = "docker_image")] - DockerImageId(String), -} - -#[derive(Debug, Serialize)] -#[serde(deny_unknown_fields)] pub struct ModuleConfig { pub id: String, - #[serde(flatten)] - pub source: ModuleSource, + pub docker_image: String, #[serde(flatten)] pub extra: T, } -impl<'de, T> Deserialize<'de> for ModuleConfig -where - T: Deserialize<'de>, -{ - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - #[derive(Deserialize)] - struct InnerModuleConfig { - id: String, - path: Option, - docker_image: Option, - #[serde(flatten)] - extra: T, - } - - let inner = InnerModuleConfig::deserialize(deserializer)?; - - let source = match (inner.path, inner.docker_image) { - (Some(path), None) => ModuleSource::Path(path), - (None, Some(docker_image)) => ModuleSource::DockerImageId(docker_image), - (Some(_), Some(_)) => return Err(de::Error::custom("Cannot have both `path` and `docker_image`")), - (None, None) => return Err(de::Error::custom("Must have either `path` or `docker_image`")), - }; - - Ok(ModuleConfig { - id: inner.id, - source, - extra: inner.extra, - }) - } -} - #[derive(Debug, Deserialize, Serialize)] pub struct StartModuleConfig { pub chain: Chain,