diff --git a/crates/jstzd/src/config.rs b/crates/jstzd/src/config.rs index 8648892c2..2371a2015 100644 --- a/crates/jstzd/src/config.rs +++ b/crates/jstzd/src/config.rs @@ -1,13 +1,21 @@ #![allow(dead_code)] - +use crate::task::jstzd::JstzdConfig; use anyhow::{Context, Result}; -use octez::r#async::{ - baker::OctezBakerConfigBuilder, client::OctezClientConfigBuilder, - node_config::OctezNodeConfigBuilder, protocol::ProtocolParameterBuilder, +use octez::{ + r#async::{ + baker::{BakerBinaryPath, OctezBakerConfig, OctezBakerConfigBuilder}, + client::{OctezClientConfig, OctezClientConfigBuilder}, + node_config::{OctezNodeConfig, OctezNodeConfigBuilder}, + protocol::{BootstrapAccount, Protocol, ProtocolParameterBuilder}, + }, + unused_port, }; use serde::Deserialize; use tokio::io::AsyncReadExt; +const ACTIVATOR_PUBLIC_KEY: &str = + "edpkuSLWfVU1Vq7Jg9FucPyKmma6otcMHac9zG4oU1KMHSTBpJuGQ2"; + #[derive(Deserialize, Default)] struct Config { server_port: Option, @@ -31,9 +39,75 @@ async fn parse_config(path: &str) -> Result { Ok(serde_json::from_str::(&s)?) } +async fn build_config( + config_path: &Option, +) -> anyhow::Result<(u16, JstzdConfig)> { + let mut config = match config_path { + Some(p) => parse_config(p).await?, + None => default_config(), + }; + let octez_node_config = config.octez_node.build()?; + let octez_client_config = match config.octez_client { + Some(v) => v, + None => OctezClientConfigBuilder::new(octez_node_config.rpc_endpoint.clone()), + } + .build()?; + let baker_config = populate_baker_config( + config.octez_baker, + &octez_node_config, + &octez_client_config, + )?; + + let protocol_params = config.protocol.build()?; + let server_port = config.server_port.unwrap_or(unused_port()); + Ok(( + server_port, + JstzdConfig::new( + octez_node_config, + baker_config, + octez_client_config, + protocol_params, + ), + )) +} + +fn default_config() -> Config { + let mut config = Config::default(); + config + .protocol + .set_bootstrap_accounts([BootstrapAccount::new( + // add activator to bootstrap accounts in default config so that + // at least baker has an account to run with + ACTIVATOR_PUBLIC_KEY, + 40_000_000_000, + ) + .unwrap()]); + config +} + +fn populate_baker_config( + mut config_builder: OctezBakerConfigBuilder, + octez_node_config: &OctezNodeConfig, + octez_client_config: &OctezClientConfig, +) -> anyhow::Result { + if config_builder.binary_path().is_none() { + config_builder = + config_builder.set_binary_path(BakerBinaryPath::Env(Protocol::Alpha)); + } + if config_builder.octez_client_base_dir().is_none() { + config_builder = config_builder + .set_octez_client_base_dir(&octez_client_config.base_dir().to_string()); + } + if config_builder.octez_node_endpoint().is_none() { + config_builder = + config_builder.set_octez_node_endpoint(&octez_node_config.rpc_endpoint); + } + config_builder.build() +} + #[cfg(test)] mod tests { - use std::{io::Write, path::PathBuf, str::FromStr}; + use std::{io::Read, io::Write, path::PathBuf, str::FromStr}; use http::Uri; use octez::r#async::{ @@ -48,7 +122,7 @@ mod tests { ProtocolConstants, ProtocolParameterBuilder, SmartRollupPvmKind, }, }; - use tempfile::NamedTempFile; + use tempfile::{tempdir, NamedTempFile}; use super::Config; @@ -204,4 +278,117 @@ mod tests { .unwrap(); assert_eq!(config.server_port, Some(5678)); } + + #[test] + fn populate_baker_config() { + let tmp_dir = tempdir().unwrap(); + let node_config = OctezNodeConfigBuilder::new() + .set_rpc_endpoint(&Endpoint::localhost(5678)) + .build() + .unwrap(); + let client_config = OctezClientConfigBuilder::new(Endpoint::localhost(5678)) + .set_base_dir(tmp_dir.path().to_path_buf()) + .build() + .unwrap(); + let baker_builder = OctezBakerConfigBuilder::new(); + let baker_config = + super::populate_baker_config(baker_builder, &node_config, &client_config) + .unwrap(); + assert_eq!( + baker_config, + OctezBakerConfigBuilder::new() + .set_binary_path(BakerBinaryPath::Env(Protocol::Alpha)) + .set_octez_client_base_dir(tmp_dir.path().to_str().unwrap()) + .set_octez_node_endpoint(&Endpoint::localhost(5678)) + .build() + .unwrap() + ); + } + + #[test] + fn default_config() { + let config = super::default_config(); + let accounts = config.protocol.bootstrap_accounts(); + assert_eq!(accounts.len(), 1); + assert_eq!( + **accounts.first().unwrap(), + BootstrapAccount::new(super::ACTIVATOR_PUBLIC_KEY, 40_000_000_000).unwrap() + ); + } + + #[tokio::test] + async fn build_config() { + let mut tmp_file = NamedTempFile::new().unwrap(); + let content = serde_json::to_string(&serde_json::json!({ + "octez_node": { + "rpc_endpoint": "localhost:8888", + }, + "octez_client": { + "octez_node_endpoint": "localhost:9999", + }, + "protocol": { + "bootstrap_accounts": [["edpktkhoky4f5kqm2EVwYrMBq5rY9sLYdpFgXixQDWifuBHjhuVuNN", "6000000000"]] + } + })) + .unwrap(); + tmp_file.write_all(content.as_bytes()).unwrap(); + let (_, config) = + super::build_config(&Some(tmp_file.path().to_str().unwrap().to_owned())) + .await + .unwrap(); + assert_eq!( + config.octez_client_config().octez_node_endpoint(), + &Endpoint::localhost(9999) + ); + } + + #[tokio::test] + async fn build_config_with_default_config() { + let (_, config) = super::build_config(&None).await.unwrap(); + let mut buf = String::new(); + config + .protocol_params() + .parameter_file() + .read_to_string(&mut buf) + .unwrap(); + let params = serde_json::from_str::(&buf).unwrap(); + + // one bootstrap account should have been inserted: the activator account + let accounts = params + .as_object() + .unwrap() + .get("bootstrap_accounts") + .unwrap() + .as_array() + .unwrap(); + assert_eq!(accounts.len(), 1); + assert_eq!( + serde_json::from_value::(accounts.first().unwrap().clone()) + .unwrap(), + BootstrapAccount::new(super::ACTIVATOR_PUBLIC_KEY, 40_000_000_000).unwrap() + ); + } + + #[tokio::test] + async fn build_config_without_octez_client() { + let mut tmp_file = NamedTempFile::new().unwrap(); + let content = serde_json::to_string(&serde_json::json!({ + "octez_node": { + "rpc_endpoint": "localhost:8888", + }, + "protocol": { + "bootstrap_accounts": [["edpktkhoky4f5kqm2EVwYrMBq5rY9sLYdpFgXixQDWifuBHjhuVuNN", "6000000000"]] + } + })) + .unwrap(); + tmp_file.write_all(content.as_bytes()).unwrap(); + let (_, config) = + super::build_config(&Some(tmp_file.path().to_str().unwrap().to_owned())) + .await + .unwrap(); + assert_eq!( + config.octez_client_config().octez_node_endpoint(), + &Endpoint::localhost(8888) + ); + } } diff --git a/crates/jstzd/src/task/jstzd.rs b/crates/jstzd/src/task/jstzd.rs index 2d4e3be8c..7d01aa1d0 100644 --- a/crates/jstzd/src/task/jstzd.rs +++ b/crates/jstzd/src/task/jstzd.rs @@ -61,6 +61,10 @@ impl JstzdConfig { pub fn baker_config(&self) -> &OctezBakerConfig { &self.baker_config } + + pub fn protocol_params(&self) -> &ProtocolParameter { + &self.protocol_params + } } #[async_trait] diff --git a/crates/octez/src/async/baker.rs b/crates/octez/src/async/baker.rs index 5bdc3871e..eaa0520a6 100644 --- a/crates/octez/src/async/baker.rs +++ b/crates/octez/src/async/baker.rs @@ -40,7 +40,7 @@ impl Display for BakerBinaryPath { } } -#[derive(Clone, Serialize)] +#[derive(Clone, Serialize, Debug, PartialEq)] pub struct OctezBakerConfig { binary_path: BakerBinaryPath, octez_client_base_dir: PathBuf, @@ -64,16 +64,28 @@ impl OctezBakerConfigBuilder { self } + pub fn binary_path(&self) -> &Option { + &self.binary_path + } + pub fn set_octez_client_base_dir(mut self, base_dir: &str) -> Self { self.octez_client_base_dir = Some(PathBuf::from(base_dir)); self } + pub fn octez_client_base_dir(&self) -> &Option { + &self.octez_client_base_dir + } + pub fn set_octez_node_endpoint(mut self, endpoint: &Endpoint) -> Self { self.octez_node_endpoint = Some(endpoint.clone()); self } + pub fn octez_node_endpoint(&self) -> &Option { + &self.octez_node_endpoint + } + pub fn build(self) -> Result { Ok(OctezBakerConfig { binary_path: self.binary_path.ok_or(anyhow!("binary path not set"))?, diff --git a/crates/octez/src/async/client.rs b/crates/octez/src/async/client.rs index efed95a34..59420275c 100644 --- a/crates/octez/src/async/client.rs +++ b/crates/octez/src/async/client.rs @@ -32,6 +32,10 @@ impl OctezClientConfig { pub fn base_dir(&self) -> &Directory { self.base_dir.as_ref() } + + pub fn octez_node_endpoint(&self) -> &Endpoint { + &self.octez_node_endpoint + } } #[derive(Deserialize, Debug, PartialEq)] diff --git a/crates/octez/src/async/protocol.rs b/crates/octez/src/async/protocol.rs index 882c20479..20ce8cd98 100644 --- a/crates/octez/src/async/protocol.rs +++ b/crates/octez/src/async/protocol.rs @@ -170,6 +170,10 @@ impl ProtocolParameterBuilder { self } + pub fn bootstrap_accounts(&self) -> Vec<&BootstrapAccount> { + self.bootstrap_accounts.accounts() + } + pub fn set_bootstrap_contracts( &mut self, contracts: impl IntoIterator,