diff --git a/crates/prism/src/main.rs b/crates/prism/src/main.rs index 67db55a..c2923b7 100644 --- a/crates/prism/src/main.rs +++ b/crates/prism/src/main.rs @@ -8,6 +8,7 @@ mod webserver; use cfg::{initialize_da_layer, load_config}; use clap::Parser; +use ed25519_dalek::VerifyingKey; use keystore_rs::{KeyChain, KeyStore, KeyStoreType}; use crate::cfg::{CommandLineArgs, Commands}; @@ -15,6 +16,8 @@ use node_types::{lightclient::LightClient, sequencer::Sequencer, NodeType}; use std::sync::Arc; use storage::RedisConnection; +use base64::{engine::general_purpose::STANDARD as engine, Engine as _}; + #[macro_use] extern crate log; @@ -39,7 +42,26 @@ async fn main() -> std::io::Result<()> { "celestia configuration not found", ) })?; - Arc::new(LightClient::new(da, celestia_config, config.verifying_key)) + + let sequencer_pubkey = config.verifying_key.and_then(|s| { + engine + .decode(&s) + .map_err(|e| error!("Failed to decode base64 string: {}", e)) + .ok() + .and_then(|bytes| { + bytes + .try_into() + .map_err(|e| error!("Failed to convert bytes into [u8; 32]: {:?}", e)) + .ok() + }) + .and_then(|array| { + VerifyingKey::from_bytes(&array) + .map_err(|e| error!("Failed to create VerifyingKey: {}", e)) + .ok() + }) + }); + + Arc::new(LightClient::new(da, celestia_config, sequencer_pubkey)) } Commands::Sequencer {} => { let redis_config = config.clone().redis_config.ok_or_else(|| { diff --git a/crates/prism/src/node_types/lightclient.rs b/crates/prism/src/node_types/lightclient.rs index e3a718a..cc04c23 100644 --- a/crates/prism/src/node_types/lightclient.rs +++ b/crates/prism/src/node_types/lightclient.rs @@ -41,16 +41,11 @@ impl LightClient { pub fn new( da: Arc, cfg: CelestiaConfig, - sequencer_pubkey: Option, + sequencer_pubkey: Option, ) -> LightClient { let client = ProverClient::new(); let (_, verifying_key) = client.setup(PRISM_ELF); - let sequencer_pubkey = sequencer_pubkey.map(|s| { - // TODO: Graceful error handling - VerifyingKey::from_bytes(&hex::decode(s).unwrap().try_into().unwrap()).unwrap() - }); - LightClient { da, verifying_key, diff --git a/crates/prism/src/node_types/sequencer.rs b/crates/prism/src/node_types/sequencer.rs index a9c260c..ef3b1f5 100644 --- a/crates/prism/src/node_types/sequencer.rs +++ b/crates/prism/src/node_types/sequencer.rs @@ -22,7 +22,7 @@ use prism_common::{ hash, Batch, Digest, Hasher, KeyDirectoryTree, NonMembershipProof, Proof, SnarkableTree, }, }; -use prism_errors::{DataAvailabilityError, DatabaseError, GeneralError}; +use prism_errors::DataAvailabilityError; pub const PRISM_ELF: &[u8] = include_bytes!("../../../../elf/riscv32im-succinct-zkvm-elf"); diff --git a/crates/prism/tests/integration_tests.rs b/crates/prism/tests/integration_tests.rs index 299f9a1..809a2ea 100644 --- a/crates/prism/tests/integration_tests.rs +++ b/crates/prism/tests/integration_tests.rs @@ -4,20 +4,56 @@ extern crate log; use anyhow::Result; -use ed25519_dalek::{Signer, SigningKey}; +use ed25519_dalek::SigningKey; use keystore_rs::create_signing_key; -use prism_common::operation::{AccountSource, Operation}; +use prism_common::operation::{ + CreateAccountArgs, KeyOperationArgs, Operation, PublicKey, ServiceChallengeInput, + SignatureBundle, +}; use prism_main::{ cfg::{CelestiaConfig, Config, RedisConfig}, da::{celestia::CelestiaConnection, DataAvailabilityLayer}, node_types::{lightclient::LightClient, sequencer::Sequencer, NodeType}, storage::{Database, RedisConnection}, - webserver::OperationInput, }; use rand::{rngs::StdRng, Rng, SeedableRng}; -use std::sync::Arc; +use std::{collections::HashMap, sync::Arc}; use tokio::{spawn, time::Duration}; +fn create_random_user(id: &str, signing_key: SigningKey) -> Operation { + let mut op = Operation::CreateAccount(CreateAccountArgs { + id: id.to_string(), + value: PublicKey::Ed25519(signing_key.verifying_key().to_bytes().to_vec()), + service_id: "test_service".to_string(), + signature: Vec::new(), + challenge: ServiceChallengeInput::Signed(vec![]), + }); + + op.insert_signature(&signing_key) + .expect("Inserting signature into operation should succeed"); + op +} + +fn add_key(id: &str, key_idx: u64, new_key: PublicKey, signing_key: SigningKey) -> Operation { + let mut op = Operation::AddKey(KeyOperationArgs { + id: id.to_string(), + value: new_key.clone(), + signature: SignatureBundle { + key_idx, + signature: Vec::new(), + }, + }); + + op.insert_signature(&signing_key) + .expect("Inserting signature into operation should succeed"); + op +} + +fn setup_db() -> Arc> { + let redis_connection = RedisConnection::new(&RedisConfig::default()).unwrap(); + Arc::new(Box::new(redis_connection) as Box) +} + #[tokio::test] async fn test_light_client_sequencer_talking() -> Result<()> { std::env::set_var( @@ -40,7 +76,7 @@ async fn test_light_client_sequencer_talking() -> Result<()> { let db = setup_db(); let cfg = Config::default(); let signing_key = create_signing_key(); - let pubkey = engine.encode(signing_key.verifying_key().to_bytes()); + let pubkey = signing_key.verifying_key(); let sequencer = Arc::new(Sequencer::new( db.clone(), @@ -67,29 +103,66 @@ async fn test_light_client_sequencer_talking() -> Result<()> { lc_clone.start().await.unwrap(); }); - loop { - // Create 1 to 10 new accounts - let num_new_accounts = rng.gen_range(1..=3); - for _ in 0..num_new_accounts { - let new_acc = create_new_account_operation( - format!("{}@gmail.com", i), - format!("key_{}", i), - &signing_key, - ); - sequencer - .clone() - .validate_and_queue_update(&new_acc) - .await - .unwrap(); - accounts.push(format!("{}@gmail.com", i)); - i += 1; - } - let mut rx = lc_da_layer.clone().subscribe_to_heights(); - while let Ok(height) = rx.recv().await { - debug!("received height {}", height); - if height == 100 { - break; + spawn(async move { + let mut rng = StdRng::from_entropy(); + let mut accounts: HashMap> = HashMap::new(); + let mut i = 0; + + loop { + // Create 1 to 3 new accounts + let num_new_accounts = rng.gen_range(1..=3); + for _ in 0..num_new_accounts { + let new_key = create_signing_key(); + let new_acc = + create_random_user(format!("{}@gmail.com", i).as_str(), new_key.clone()); + sequencer + .clone() + .validate_and_queue_update(&new_acc) + .await + .unwrap(); + accounts + .insert(format!("{}@gmail.com", i), vec![new_key]) + .unwrap(); + i += 1; + } + + // Update 5 random existing accounts (if we have at least 5) + if accounts.len() >= 5 { + for _ in 0..5 { + let account_id = accounts + .keys() + .nth(rng.gen_range(0..accounts.len())) + .unwrap(); + let signing_keys = accounts.get(account_id).unwrap(); + let signing_key = signing_keys.last().unwrap(); + let new_key = create_signing_key(); + let new_public_key = + PublicKey::Ed25519(new_key.verifying_key().to_bytes().to_vec()); + let update_op = add_key( + account_id, + (signing_keys.len() - 1) as u64, + new_public_key, + signing_key.clone(), + ); + sequencer + .clone() + .validate_and_queue_update(&update_op) + .await + .unwrap(); + } } + + tokio::time::sleep(Duration::from_millis(5000)).await; + } + }); + + let mut rx = lc_da_layer.clone().subscribe_to_heights(); + while let Ok(height) = rx.recv().await { + debug!("received height {}", height); + if height == 100 { + break; } } + + Ok(()) }