diff --git a/Cargo.lock b/Cargo.lock index 61d8e913..c0864266 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5677,6 +5677,7 @@ dependencies = [ "ethereum_ssz", "futures", "serde", + "serde_json", "summit-finalizer", "summit-types", "tokio", diff --git a/example_genesis.toml b/example_genesis.toml index aa244bc0..6c747043 100644 --- a/example_genesis.toml +++ b/example_genesis.toml @@ -1,4 +1,4 @@ -eth_genesis_hash = "0x655cc1ecc77fe1eab4b1e62a1f461b7fddc9b06109b5ab3e9dc68c144b30c773" +eth_genesis_hash = "0x93068b65464eeee04a47a3b16b3123d05a5d83882032525bdb5e297d654857f0" leader_timeout_ms = 2000 notarization_timeout_ms = 4000 nullify_timeout_ms = 4000 diff --git a/node/src/args.rs b/node/src/args.rs index 15ddcb70..358573eb 100644 --- a/node/src/args.rs +++ b/node/src/args.rs @@ -192,13 +192,19 @@ impl Command { // use the context async move to spawn a new runtime let genesis_path = flags.genesis_path.clone(); + let key_store_path = flags.key_store_path.clone(); let rpc_port = flags.rpc_port; let _rpc_handle = context .with_label("rpc_genesis") .spawn(move |_context| async move { let genesis_sender = Command::check_sender(genesis_path, genesis_tx); - if let Err(e) = - start_rpc_server_for_genesis(genesis_sender, rpc_port, cloned_token).await + if let Err(e) = start_rpc_server_for_genesis( + genesis_sender, + key_store_path, + rpc_port, + cloned_token, + ) + .await { error!("RPC server failed: {}", e); } @@ -414,12 +420,18 @@ pub fn run_node_local( // use the context async move to spawn a new runtime let rpc_port = flags.rpc_port; let genesis_path = flags.genesis_path.clone(); + let key_store_path = flags.key_store_path.clone(); let _rpc_handle = context .with_label("rpc_genesis") .spawn(move |_context| async move { let genesis_sender = Command::check_sender(genesis_path, genesis_tx); - if let Err(e) = - start_rpc_server_for_genesis(genesis_sender, rpc_port, cloned_token).await + if let Err(e) = start_rpc_server_for_genesis( + genesis_sender, + key_store_path, + rpc_port, + cloned_token, + ) + .await { error!("RPC server failed: {}", e); } diff --git a/node/src/bin/genesis.rs b/node/src/bin/genesis.rs index 4f3b6301..9e3dc48d 100644 --- a/node/src/bin/genesis.rs +++ b/node/src/bin/genesis.rs @@ -1,15 +1,7 @@ use clap::Parser; -use commonware_codec::{DecodeExt, Encode as _}; -use commonware_cryptography::bls12381::{ - dkg::ops, - primitives::{poly, variant::MinPk}, -}; -use commonware_utils::{from_hex, hex, quorum}; -use rand::rngs::OsRng; use serde::{Deserialize, Serialize}; use std::fs; -use std::path::Path; -use summit_types::PublicKey; +use summit_types::GenesisValidator; const DEFAULT_GENESIS_FILE: &str = "./example_genesis.toml"; @@ -23,8 +15,7 @@ pub struct GenesisConfig { skip_timeout_views: u64, max_message_size_bytes: u64, namespace: String, - pub identity: String, - pub validators: Vec, + pub validators: Vec, } impl GenesisConfig { @@ -35,19 +26,6 @@ impl GenesisConfig { } } -#[derive(Debug, Serialize, Deserialize)] -pub struct Validator { - pub public_key: String, - pub ip_address: String, -} - -impl Validator { - pub fn ed25519_pubkey(&self) -> PublicKey { - let pubkey_bytes = from_hex(&self.public_key).unwrap(); - PublicKey::decode(&pubkey_bytes[..]).unwrap() - } -} - #[derive(Parser, Debug)] struct Args { /// input for genesis file @@ -63,14 +41,14 @@ struct Args { fn parse_validators( validators_path: &String, -) -> Result, Box> { +) -> Result, Box> { let rdr = std::fs::File::open(validators_path)?; - let mut validators: Vec = serde_json::from_reader(rdr)?; + let mut validators: Vec = serde_json::from_reader(rdr)?; // NOTE: (important!) // Sort public keys in the same order we do in summit validators.sort_by(|a, b| { - let a_pubkey = a.ed25519_pubkey(); - let b_pubkey = b.ed25519_pubkey(); + let a_pubkey = a.node_pubkey(); + let b_pubkey = b.node_pubkey(); a_pubkey.partial_cmp(&b_pubkey).unwrap() }); Ok(validators) @@ -81,32 +59,10 @@ fn main() -> Result<(), Box> { let validators = parse_validators(&args.validators_path)?; let node_count = validators.len() as u32; - let threshold = quorum(node_count); - let (polynomial, shares) = - ops::generate_shares::<_, MinPk>(&mut OsRng, None, node_count, threshold); - - println!("Network polynomial: {}", hex(&polynomial.encode())); - println!("Network pub key: {}", poly::public::(&polynomial)); - - // Read the genesis config let mut genesis_config = GenesisConfig::load(&args.genesis_in)?; - - // Update the identity with the hex of the polynomial - genesis_config.identity = hex(&polynomial.encode()); genesis_config.validators = validators; - // Write the shares we generated - for (i, _v) in genesis_config.validators.iter().enumerate() { - let node_dir = format!("{}/node{i}", args.out_dir); - fs::create_dir_all(&node_dir)?; - - let share_path = Path::new(&node_dir).join("share.pem"); - let share_hex = hex(&shares[i].encode()); - fs::write(&share_path, share_hex)?; - println!("Node {i}: wrote share to {share_path:?}"); - } - // Write the updated genesis config let updated_genesis = toml::to_string_pretty(&genesis_config)?; fs::write(format!("{}/genesis.toml", args.out_dir), updated_genesis)?; diff --git a/rpc/Cargo.toml b/rpc/Cargo.toml index aa85758b..32b9d189 100644 --- a/rpc/Cargo.toml +++ b/rpc/Cargo.toml @@ -23,4 +23,5 @@ commonware-runtime = { workspace = true } ethereum_ssz.workspace = true dirs = "5.0.1" serde = { workspace = true } +serde_json = { workspace = true } tracing.workspace = true \ No newline at end of file diff --git a/types/src/key_paths.rs b/types/src/key_paths.rs new file mode 100644 index 00000000..f83cee65 --- /dev/null +++ b/types/src/key_paths.rs @@ -0,0 +1,72 @@ +use crate::{PrivateKey, utils::get_expanded_path}; +use anyhow::{Context, Result}; +use commonware_codec::DecodeExt; +use commonware_cryptography::Signer; +use commonware_cryptography::bls12381::PrivateKey as BlsPrivateKey; +use commonware_utils::from_hex_formatted; + +/// Helper struct for managing key paths and loading keys from a key store directory. +/// +/// The key store directory should contain: +/// - `node_key.pem`: ED25519 private key for node identity (node key) +/// - `share.pem`: BLS12-381 DKG share (consensus key) +pub struct KeyPaths(String); + +impl KeyPaths { + /// Create a new KeyPaths instance from a key store path + pub fn new(key_store_path: String) -> Self { + Self(key_store_path) + } + + /// Get the path to the node key file (ED25519) + pub fn node_key_path(&self) -> String { + format!("{}/node_key.pem", self.0) + } + + /// Get the path to the consensus key file (BLS share) + pub fn consensus_key_path(&self) -> String { + format!("{}/share.pem", self.0) + } + + /// Load the node private key (ED25519) from the key store + pub fn node_private_key(&self) -> Result { + self.read_node_key_from_file().map_err(|e| e.to_string()) + } + + /// Load the consensus private key (BLS) from the key store + pub fn consensus_private_key(&self) -> Result { + self.read_bls_key_from_file().map_err(|e| e.to_string()) + } + + /// Get the node public key (ED25519) as a hex string + pub fn node_public_key(&self) -> Result { + let private_key = self.node_private_key()?; + Ok(private_key.public_key().to_string()) + } + + /// Get the consensus public key (BLS) as a hex string + pub fn consensus_public_key(&self) -> Result { + let private_key = self.consensus_private_key()?; + Ok(private_key.public_key().to_string()) + } + + /// Read the node private key from file (using anyhow::Result for compatibility) + pub fn read_node_key_from_file(&self) -> Result { + let path = get_expanded_path(&self.node_key_path())?; + let encoded_pk = std::fs::read_to_string(&path) + .context(format!("Failed to read node key from {:?}", path))?; + let key = from_hex_formatted(&encoded_pk).context("Invalid hex format for node key")?; + let pk = PrivateKey::decode(&*key).context("Unable to decode node private key")?; + Ok(pk) + } + + /// Read the BLS private key from file (using anyhow::Result for compatibility) + pub fn read_bls_key_from_file(&self) -> Result { + let path = get_expanded_path(&self.consensus_key_path())?; + let encoded_pk = std::fs::read_to_string(&path) + .context(format!("Failed to read BLS key from {:?}", path))?; + let key = from_hex_formatted(&encoded_pk).context("Invalid hex format for BLS key")?; + let pk = BlsPrivateKey::decode(&*key).context("Unable to decode BLS private key")?; + Ok(pk) + } +}