diff --git a/Cargo.lock b/Cargo.lock index 47d6710..f4f46bf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1686,7 +1686,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" dependencies = [ "once_cell", - "toml_edit", + "toml_edit 0.19.15", ] [[package]] @@ -2066,6 +2066,15 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_spanned" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79e674e01f999af37c49f70a6ede167a8a60b2503e56c5599532a65baa5969a0" +dependencies = [ + "serde", +] + [[package]] name = "serde_with" version = "2.3.3" @@ -2210,6 +2219,7 @@ dependencies = [ "serde_with 3.8.1", "sha256", "tokio", + "toml", "websockets", ] @@ -2507,11 +2517,26 @@ dependencies = [ "tungstenite", ] +[[package]] +name = "toml" +version = "0.8.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f49eb2ab21d2f26bd6db7bf383edc527a7ebaee412d17af4d40fdccd442f335" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit 0.22.14", +] + [[package]] name = "toml_datetime" version = "0.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4badfd56924ae69bcc9039335b2e017639ce3f9b001c393c1b2d1ef846ce2cbf" +dependencies = [ + "serde", +] [[package]] name = "toml_edit" @@ -2521,7 +2546,20 @@ checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" dependencies = [ "indexmap 2.2.6", "toml_datetime", - "winnow", + "winnow 0.5.40", +] + +[[package]] +name = "toml_edit" +version = "0.22.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f21c7aaf97f1bd9ca9d4f9e73b0a6c74bd5afef56f2bc931943a6e1c37e04e38" +dependencies = [ + "indexmap 2.2.6", + "serde", + "serde_spanned", + "toml_datetime", + "winnow 0.6.12", ] [[package]] @@ -2882,6 +2920,15 @@ dependencies = [ "memchr", ] +[[package]] +name = "winnow" +version = "0.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41ff33f391015ecab21cd092389215eb265ef9496a9a07b6bee7d3529831deda" +dependencies = [ + "memchr", +] + [[package]] name = "zerocopy" version = "0.7.34" diff --git a/side-node/Cargo.toml b/side-node/Cargo.toml index 3df9144..afbec9a 100644 --- a/side-node/Cargo.toml +++ b/side-node/Cargo.toml @@ -19,6 +19,7 @@ sha256 = "1.5.0" tokio = { version = "1.37.0", features = ["full"] } websockets = "0.3.0" pem = "3.0.4" +toml = "0.8.14" [features] default = ["bft", "logging-list", "logging-json"] diff --git a/side-node/src/init/config.rs b/side-node/src/init/config.rs new file mode 100644 index 0000000..ffab09a --- /dev/null +++ b/side-node/src/init/config.rs @@ -0,0 +1,21 @@ +use serde::Serialize; +use std::fs::File; +use std::io::Write; +use std::path::PathBuf; +use toml::to_string; + +/// Our node config. For now, it just has a name, but it'll expand as we add more features. +#[derive(Serialize)] +pub(crate) struct SideNodeConfig { + pub(crate) name: String, +} + +pub(crate) fn write_config_to_file( + config: &SideNodeConfig, + file_path: &PathBuf, +) -> Result<(), Box> { + let toml_string = to_string(config)?; + let mut file = File::create(file_path)?; + file.write_all(toml_string.as_bytes())?; + Ok(()) +} diff --git a/side-node/src/init/keys.rs b/side-node/src/init/keys.rs new file mode 100644 index 0000000..3ad0e0c --- /dev/null +++ b/side-node/src/init/keys.rs @@ -0,0 +1,21 @@ +use std::{fs::File, io::Write, path::PathBuf}; + +use bft_json_crdt::keypair::{make_keypair, KeyPair}; +use pem::Pem; + +/// Makes an Ed25519 keypair and returns the public and private keys as a PEM-encoded string. +pub(crate) fn setup() -> String { + let keys = make_keypair(); + + let public_pem = Pem::new("PUBLIC", keys.public().to_string()); + let private_pem = Pem::new("PRIVATE", keys.private().to_string()); + pem::encode_many(&[public_pem, private_pem]) +} + +/// Writes a PEM-encoded string to a file at key_path. +pub(crate) fn write_pem(key_path: PathBuf, pem: String) -> Result<(), std::io::Error> { + println!("Writing key to: {:?}", key_path); + let mut file = File::create(key_path)?; + file.write(pem.to_string().as_bytes())?; + Ok(()) +} diff --git a/side-node/src/init.rs b/side-node/src/init/mod.rs similarity index 61% rename from side-node/src/init.rs rename to side-node/src/init/mod.rs index 7961ed4..d5175da 100644 --- a/side-node/src/init.rs +++ b/side-node/src/init/mod.rs @@ -1,26 +1,21 @@ -use std::{ - fs::File, - io::Write, - path::{Path, PathBuf}, -}; +use std::path::PathBuf; -use pem::Pem; +use config::SideNodeConfig; -use bft_json_crdt::keypair::{make_keypair, KeyPair}; +pub(crate) mod config; +mod keys; const KEY_FILE: &str = "keys.pem"; const CONFIG_FILE: &str = "config.toml"; -pub(crate) fn init(home: PathBuf) -> Result<(), std::io::Error> { +pub(crate) fn init(home: PathBuf, config: SideNodeConfig) -> Result<(), std::io::Error> { ensure_side_directory_exists(&home)?; + let (key_path, config_path) = side_paths(home.clone()); - let (key_path, config_path) = side_path(home.clone()); - - let pem = create_pem(); - write_pem(key_path, pem)?; - - let mut file = File::create(config_path)?; + let pem = keys::setup(); + keys::write_pem(key_path, pem)?; + config::write_config_to_file(&config, &config_path).expect("unable to write config file"); Ok(()) } @@ -34,25 +29,8 @@ fn ensure_side_directory_exists(side_dir: &PathBuf) -> Result<(), std::io::Error std::fs::create_dir_all(side_dir) } -/// Writes a PEM-encoded string to a file at key_path. -fn write_pem(key_path: PathBuf, pem: String) -> Result<(), std::io::Error> { - println!("Writing key to: {:?}", key_path); - let mut file = File::create(key_path)?; - file.write(pem.to_string().as_bytes())?; - Ok(()) -} - -/// Makes an Ed25519 keypair and returns the public and private keys as a PEM-encoded string. -fn create_pem() -> String { - let keys = make_keypair(); - - let public_pem = Pem::new("PUBLIC", keys.public().to_string()); - let private_pem = Pem::new("PRIVATE", keys.private().to_string()); - pem::encode_many(&[public_pem, private_pem]) -} - /// Returns the path to the key file for this host OS. -fn side_path(prefix: PathBuf) -> (PathBuf, PathBuf) { +fn side_paths(prefix: PathBuf) -> (PathBuf, PathBuf) { let mut key_path = prefix.clone(); key_path.push(KEY_FILE); @@ -64,10 +42,16 @@ fn side_path(prefix: PathBuf) -> (PathBuf, PathBuf) { #[cfg(test)] mod tests { - use std::fs; + use std::{fs, path::Path}; use super::*; + fn default_side_node_config() -> SideNodeConfig { + SideNodeConfig { + name: "alice".to_string(), + } + } + #[test] fn creates_side_node_directory() { let mut test_home = PathBuf::new(); @@ -78,7 +62,7 @@ mod tests { test_home.push(side_dir); let node_dir = Path::new(&test_home).parent().unwrap().to_str().unwrap(); - let _ = init(test_home.clone()); + let _ = init(test_home.clone(), default_side_node_config()); assert!(std::path::Path::new(node_dir).exists()); } @@ -89,7 +73,7 @@ mod tests { let side_dir = file_path.clone(); file_path.push(KEY_FILE); - let _ = init(side_dir.clone()); + let _ = init(side_dir.clone(), default_side_node_config()); assert!(file_path.exists()); // check that the pem is readable @@ -104,7 +88,7 @@ mod tests { let side_dir = file_path.clone(); file_path.push(CONFIG_FILE); - let _ = init(side_dir.clone()); + let _ = init(side_dir.clone(), default_side_node_config()); assert!(file_path.exists()); } } diff --git a/side-node/src/main.rs b/side-node/src/main.rs index 14e43f1..876f168 100644 --- a/side-node/src/main.rs +++ b/side-node/src/main.rs @@ -11,7 +11,11 @@ async fn main() { match &args.command { Some(Commands::Init {}) => { - let _ = init::init(home()); + let config = init::config::SideNodeConfig { + name: "alice".to_string(), + }; + + let _ = init::init(home(), config); } Some(Commands::Run {}) => { let (mut bft_crdt, keys) = list_transaction_crdt::new();