From 5c98b369cf6280ebc541751754f6c5bb50c4e8c6 Mon Sep 17 00:00:00 2001 From: redshiftzero Date: Thu, 12 Oct 2023 14:29:41 -0400 Subject: [PATCH] wip: write and load phase 1 from a file --- crates/crypto/proof-setup/src/all.rs | 36 ++++++++++------- tools/summonerd/src/main.rs | 60 +++++++++++++++++++++++++--- tools/summonerd/src/storage.rs | 27 +------------ 3 files changed, 78 insertions(+), 45 deletions(-) diff --git a/crates/crypto/proof-setup/src/all.rs b/crates/crypto/proof-setup/src/all.rs index 0710824024..ad48ce480c 100644 --- a/crates/crypto/proof-setup/src/all.rs +++ b/crates/crypto/proof-setup/src/all.rs @@ -29,6 +29,12 @@ fn to_bytes(t: &T) -> Result> { Ok(out) } +fn to_bytes_uncompressed(t: &T) -> Result> { + let mut out = Vec::new(); + t.serialize_uncompressed(&mut out)?; + Ok(out) +} + pub const NUM_CIRCUITS: usize = 7; /// Generate all of the circuits as matrices. @@ -472,13 +478,13 @@ impl TryInto for Phase1RawCeremonyCRS { fn try_into(self) -> Result { Ok(pb::CeremonyCrs { - spend: to_bytes(&self.0[0])?, - output: to_bytes(&self.0[1])?, - delegator_vote: to_bytes(&self.0[2])?, - undelegate_claim: to_bytes(&self.0[3])?, - swap: to_bytes(&self.0[4])?, - swap_claim: to_bytes(&self.0[5])?, - nullifer_derivation_crs: to_bytes(&self.0[6])?, + spend: to_bytes_uncompressed(&self.0[0])?, + output: to_bytes_uncompressed(&self.0[1])?, + delegator_vote: to_bytes_uncompressed(&self.0[2])?, + undelegate_claim: to_bytes_uncompressed(&self.0[3])?, + swap: to_bytes_uncompressed(&self.0[4])?, + swap_claim: to_bytes_uncompressed(&self.0[5])?, + nullifer_derivation_crs: to_bytes_uncompressed(&self.0[6])?, }) } } @@ -488,13 +494,15 @@ impl TryFrom for Phase1RawCeremonyCRS { fn try_from(value: pb::CeremonyCrs) -> std::result::Result { Ok(Self([ - Phase1RawCRSElements::deserialize_compressed(value.spend.as_slice())?, - Phase1RawCRSElements::deserialize_compressed(value.output.as_slice())?, - Phase1RawCRSElements::deserialize_compressed(value.delegator_vote.as_slice())?, - Phase1RawCRSElements::deserialize_compressed(value.undelegate_claim.as_slice())?, - Phase1RawCRSElements::deserialize_compressed(value.swap.as_slice())?, - Phase1RawCRSElements::deserialize_compressed(value.swap_claim.as_slice())?, - Phase1RawCRSElements::deserialize_compressed(value.nullifer_derivation_crs.as_slice())?, + Phase1RawCRSElements::deserialize_uncompressed(value.spend.as_slice())?, + Phase1RawCRSElements::deserialize_uncompressed(value.output.as_slice())?, + Phase1RawCRSElements::deserialize_uncompressed(value.delegator_vote.as_slice())?, + Phase1RawCRSElements::deserialize_uncompressed(value.undelegate_claim.as_slice())?, + Phase1RawCRSElements::deserialize_uncompressed(value.swap.as_slice())?, + Phase1RawCRSElements::deserialize_uncompressed(value.swap_claim.as_slice())?, + Phase1RawCRSElements::deserialize_uncompressed( + value.nullifer_derivation_crs.as_slice(), + )?, ])) } } diff --git a/tools/summonerd/src/main.rs b/tools/summonerd/src/main.rs index e2f9db3f10..87da36353e 100644 --- a/tools/summonerd/src/main.rs +++ b/tools/summonerd/src/main.rs @@ -12,6 +12,11 @@ use coordinator::Coordinator; use metrics_tracing_context::MetricsLayer; use penumbra_keys::FullViewingKey; use penumbra_proto::tools::summoning::v1alpha1::ceremony_coordinator_service_server::CeremonyCoordinatorServiceServer; +use penumbra_proto::tools::summoning::v1alpha1::CeremonyCrs; +use penumbra_proto::Message; +use std::fs::File; +use std::io::BufReader; +use std::io::Read; use std::net::SocketAddr; use storage::Storage; use tonic::transport::Server; @@ -19,7 +24,7 @@ use tracing_subscriber::{prelude::*, EnvFilter}; use url::Url; use crate::{penumbra_knower::PenumbraKnower, server::CoordinatorService}; -use penumbra_proof_setup::all::Phase1CeremonyCRS; +use penumbra_proof_setup::all::{Phase1CeremonyCRS, Phase1RawCeremonyCRS}; /// 100 MIB const MAX_MESSAGE_SIZE: usize = 100 * 1024 * 1024; @@ -41,6 +46,18 @@ struct Opt { #[derive(Debug, clap::Subcommand)] enum Command { + /// Generate a phase 1 root (for testing purposes). + GeneratePhase1 { + #[clap(long, display_order = 100)] + output: Utf8PathBuf, + }, + /// Initialize the coordinator. + Init { + #[clap(long, display_order = 100)] + storage_dir: Utf8PathBuf, + #[clap(long, display_order = 200)] + phase1_root: Utf8PathBuf, + }, /// Start the coordinator. Start { #[clap(long, display_order = 700)] @@ -63,11 +80,7 @@ impl Opt { node, listen, } => { - // TODO: Later we will load the phase 1 root from a file passed in via a command line argument above. - let phase_1_root = Phase1CeremonyCRS::root()?; - let storage = - Storage::load_or_initialize(storage_dir.join("ceremony.db"), phase_1_root) - .await?; + let storage = Storage::load(storage_dir.join("ceremony.db")).await?; let knower = PenumbraKnower::load_or_initialize(storage_dir.join("penumbra.db"), &fvk, node) .await?; @@ -92,6 +105,41 @@ impl Opt { }; Ok(()) } + Command::Init { + storage_dir, + phase1_root, + } => { + let file = File::open(phase1_root)?; + let mut reader = BufReader::new(file); + + let mut phase_1_bytes = Vec::new(); + let mut buffer = [0; 4096 * 10]; // 40 KB chunks + + loop { + let bytes_read = reader.read(&mut buffer)?; + if bytes_read == 0 { + break; + } + phase_1_bytes.extend_from_slice(&buffer[..bytes_read]); + } + dbg!("loaded the file"); + + let phase_1_raw_root = + Phase1RawCeremonyCRS::try_from(CeremonyCrs::decode(&phase_1_bytes[..])?)?; + + dbg!("got phase 1 root"); + // This is assumed to be valid as it's the starting point for the ceremony. + let phase_1_root = phase_1_raw_root.assume_valid(); + + Storage::initialize(storage_dir.join("ceremony.db"), phase_1_root).await?; + Ok(()) + } + Command::GeneratePhase1 { output } => { + let phase_1_root = Phase1CeremonyCRS::root()?; + let proto_encoded_phase_1_root: CeremonyCrs = phase_1_root.try_into()?; + std::fs::write(output, proto_encoded_phase_1_root.encode_to_vec())?; + Ok(()) + } } } } diff --git a/tools/summonerd/src/storage.rs b/tools/summonerd/src/storage.rs index 9882a0d424..43e6d38f50 100644 --- a/tools/summonerd/src/storage.rs +++ b/tools/summonerd/src/storage.rs @@ -38,18 +38,6 @@ pub struct Storage { } impl Storage { - /// If the database at `storage_path` exists, [`Self::load`] it, otherwise, [`Self::initialize`] it. - pub async fn load_or_initialize( - storage_path: impl AsRef, - phase_1_root: Phase1CeremonyCRS, - ) -> anyhow::Result { - if storage_path.as_ref().exists() { - return Self::load(storage_path, phase_1_root).await; - } - - Self::initialize(storage_path, phase_1_root).await - } - pub async fn initialize( storage_path: impl AsRef, phase_1_root: Phase1CeremonyCRS, @@ -100,23 +88,11 @@ impl Storage { Ok(r2d2::Pool::new(manager)?) } - pub async fn load( - path: impl AsRef, - phase_1_root: Phase1CeremonyCRS, - ) -> anyhow::Result { + pub async fn load(path: impl AsRef) -> anyhow::Result { let storage = Self { pool: Self::connect(path)?, }; - let current_phase_1_root = storage.phase_1_root().await?; - if current_phase_1_root != phase_1_root { - anyhow::bail!( - "Phase 1 root in database ({:?}) does not match expected root ({:?})", - current_phase_1_root, - phase_1_root - ); - } - Ok(storage) } @@ -238,6 +214,7 @@ impl Storage { } /// Get Phase 1 root. + #[allow(dead_code)] pub async fn phase_1_root(&self) -> Result { let mut conn = self.pool.get()?; let tx = conn.transaction()?;