Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove certificate creation responsability from the multi-signer #639

Merged
merged 6 commits into from
Dec 7, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
115 changes: 115 additions & 0 deletions mithril-aggregator/src/certificate_creator.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
use crate::runtime::WorkingCertificate;
use chrono::Utc;
use mithril_common::{
crypto_helper::{key_encode_hex, ProtocolMultiSignature, PROTOCOL_VERSION},
entities::{self, PartyId},
};
use thiserror::Error;

/// Error type for multi signer service.
#[derive(Error, Debug)]
pub enum CertificateCreationError {
/// Codec error.
#[error("codec error: '{0}'")]
Codec(String),
}

/// Define a way to create a [Certificate]
pub trait CertificateCreator {
/// Create a [Certificate]
fn create_certificate(
working: &WorkingCertificate,
signatures_party_ids: &[PartyId],
multi_signature: ProtocolMultiSignature,
) -> Result<entities::Certificate, CertificateCreationError>;
}

/// Implementation of a [CertificateCreator]
pub struct MithrilCertificateCreator {}

impl CertificateCreator for MithrilCertificateCreator {
/// Creates a certificate from a multi signature
fn create_certificate(
working_certificate: &WorkingCertificate,
signatures_party_ids: &[PartyId],
multi_signature: ProtocolMultiSignature,
) -> Result<entities::Certificate, CertificateCreationError> {
let protocol_version = PROTOCOL_VERSION.to_string();
let initiated_at = format!("{:?}", working_certificate.initiated_at);
let sealed_at = format!("{:?}", Utc::now());
let signers = working_certificate
.signers
.iter()
.filter(|signer| signatures_party_ids.contains(&signer.party_id))
.cloned()
.collect::<Vec<_>>();
let metadata = entities::CertificateMetadata::new(
protocol_version,
working_certificate.protocol_parameters.clone(),
initiated_at,
sealed_at,
signers,
);
let multi_signature =
key_encode_hex(&multi_signature).map_err(CertificateCreationError::Codec)?;
let genesis_signature = "".to_string();

Ok(entities::Certificate::new(
working_certificate.previous_hash.clone(),
working_certificate.beacon.clone(),
metadata,
working_certificate.message.clone(),
working_certificate.aggregate_verification_key.clone(),
multi_signature,
genesis_signature,
))
}
}

#[cfg(test)]
mod tests {
use crate::{
certificate_creator::MithrilCertificateCreator, runtime::WorkingCertificate,
CertificateCreator,
};
use chrono::{DateTime, Utc};
use mithril_common::{
crypto_helper::{key_decode_hex, tests_setup::setup_certificate_chain},
entities::PartyId,
};
use std::str::FromStr;

#[test]
fn test() {
let (certificates, _) = setup_certificate_chain(3, 1);
let expected = &certificates[1];
let working_certicate = WorkingCertificate {
beacon: expected.beacon.clone(),
protocol_parameters: expected.metadata.protocol_parameters.clone(),
signers: expected.metadata.signers.clone(),
message: expected.protocol_message.clone(),
aggregate_verification_key: expected.aggregate_verification_key.clone(),
initiated_at: DateTime::<Utc>::from_str(&expected.metadata.initiated_at).unwrap(),
previous_hash: expected.previous_hash.clone(),
};
let party_ids: Vec<PartyId> = expected
.metadata
.signers
.iter()
.map(|s| s.party_id.clone())
.collect();

let mut certificate = MithrilCertificateCreator::create_certificate(
&working_certicate,
&party_ids,
key_decode_hex(&expected.multi_signature.clone()).unwrap(),
)
.expect("certificate creation should not fail");
// Note: We can't sync the 'sealed_at' property with the expected cert before hand since it's
// computed by create_certificate itself, so we need to do that now :
certificate.metadata.sealed_at = expected.metadata.sealed_at.clone();
certificate.hash = certificate.compute_hash();

assert_eq!(expected, &certificate);
}
}
140 changes: 112 additions & 28 deletions mithril-aggregator/src/dependency.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
use mithril_common::certificate_chain::CertificateVerifier;
use mithril_common::crypto_helper::ProtocolGenesisVerifier;
use std::sync::Arc;
use tokio::sync::RwLock;

use mithril_common::chain_observer::ChainObserver;
use mithril_common::crypto_helper::ProtocolGenesisVerifier;
use mithril_common::digesters::{ImmutableDigester, ImmutableFileObserver};
use mithril_common::entities::{
Epoch, ProtocolParameters, Signer, SignerWithStake, StakeDistribution,
Certificate, Epoch, ProtocolParameters, Signer, SignerWithStake, StakeDistribution,
};
use mithril_common::store::{StakeStore, StakeStorer};
use mithril_common::BeaconProvider;

use std::collections::HashMap;
use std::sync::Arc;
use tokio::sync::RwLock;

use crate::configuration::*;
use crate::multi_signer::MultiSigner;
use crate::snapshot_stores::SnapshotStore;
Expand Down Expand Up @@ -77,6 +78,13 @@ pub struct DependencyManager {
pub genesis_verifier: Arc<ProtocolGenesisVerifier>,
}

#[doc(hidden)]
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum SimulateFromChainParams {
/// Will set the multi_signer protocol parameters & beacon to the one in contained in the latest certificate.
SetupMultiSigner,
}

#[doc(hidden)]
impl DependencyManager {
/// Get the first two epochs that will be used by a newly started aggregator
Expand All @@ -97,6 +105,77 @@ impl DependencyManager {
(work_epoch, epoch_to_sign)
}

/// `TEST METHOD ONLY`
///
/// Fill the stores of a [DependencyManager] in a way to simulate an aggregator genesis state
/// using the data from a precomputed certificate_chain.
///
/// Arguments:
pub async fn init_state_from_chain(
&self,
certificate_chain: &[Certificate],
additional_params: Vec<SimulateFromChainParams>,
) {
if certificate_chain.is_empty() {
panic!("The given certificate chain must contains at least one certificate");
}

let mut certificate_chain = certificate_chain.to_vec();
certificate_chain.sort_by(|left, right| {
left.beacon
.partial_cmp(&right.beacon)
.expect("The given certificates should all share the same network")
});
let last_certificate = certificate_chain.last().unwrap().clone();
let last_beacon = last_certificate.beacon.clone();
let last_protocol_parameters = last_certificate.metadata.protocol_parameters.clone();

let mut parameters_per_epoch: HashMap<Epoch, (Vec<SignerWithStake>, ProtocolParameters)> =
HashMap::new();
for certificate in certificate_chain.iter() {
if parameters_per_epoch.contains_key(&certificate.beacon.epoch) {
continue;
}

parameters_per_epoch.insert(
certificate.beacon.epoch,
(
certificate.metadata.signers.clone(),
certificate.metadata.protocol_parameters.clone(),
),
);
}

for (epoch, params) in parameters_per_epoch {
self.fill_verification_key_store(epoch, &params.0).await;
self.fill_stakes_store(epoch, &params.0).await;
self.protocol_parameters_store
.save_protocol_parameters(epoch, params.1)
.await
.expect("save_protocol_parameters should not fail");
}

for certificate in certificate_chain {
self.certificate_store
.save(certificate.to_owned())
.await
.expect("certificate_store::save should not fail");
}

if additional_params.contains(&SimulateFromChainParams::SetupMultiSigner) {
let mut multi_signer = self.multi_signer.write().await;

multi_signer
.update_current_beacon(last_beacon)
.await
.expect("setting the beacon should not fail");
multi_signer
.update_protocol_parameters(&last_protocol_parameters.into())
.await
.expect("updating protocol parameters should not fail");
}
}

/// `TEST METHOD ONLY`
///
/// Fill the stores of a [DependencyManager] in a way to simulate an aggregator genesis state.
Expand All @@ -116,29 +195,8 @@ impl DependencyManager {
(work_epoch, genesis_signers),
(epoch_to_sign, second_epoch_signers),
] {
for signer in signers
.clone()
.into_iter()
.map(|s| s.into())
.collect::<Vec<Signer>>()
{
self.verification_key_store
.save_verification_key(epoch, signer.clone())
.await
.expect("save_verification_key should not fail");
}

self.stake_store
.save_stakes(
epoch,
signers
.clone()
.iter()
.map(|s| s.into())
.collect::<StakeDistribution>(),
)
.await
.expect("save_stakes should not fail");
self.fill_verification_key_store(epoch, &signers).await;
self.fill_stakes_store(epoch, &signers).await;
}

self.init_protocol_parameter_store(genesis_protocol_parameters)
Expand All @@ -157,6 +215,32 @@ impl DependencyManager {
.expect("save_protocol_parameters should not fail");
}
}

async fn fill_verification_key_store(&self, target_epoch: Epoch, signers: &[SignerWithStake]) {
for signer in signers
.iter()
.map(|s| s.to_owned().into())
.collect::<Vec<Signer>>()
{
self.verification_key_store
.save_verification_key(target_epoch, signer.clone())
.await
.expect("save_verification_key should not fail");
}
}

async fn fill_stakes_store(&self, target_epoch: Epoch, signers: &[SignerWithStake]) {
self.stake_store
.save_stakes(
target_epoch,
signers
.iter()
.map(|s| s.into())
.collect::<StakeDistribution>(),
)
.await
.expect("save_stakes should not fail");
}
}

#[cfg(test)]
Expand Down
2 changes: 2 additions & 0 deletions mithril-aggregator/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
//! signed certificates.
//! You can find more information on how it works reading the [documentation website](https://mithril.network/doc/mithril/mithril-network/aggregator).

mod certificate_creator;
mod command_args;
mod configuration;
mod dependency;
Expand All @@ -29,6 +30,7 @@ pub use crate::configuration::{
};
pub use crate::multi_signer::{MultiSigner, MultiSignerImpl, ProtocolError};
pub use crate::snapshot_stores::{LocalSnapshotStore, RemoteSnapshotStore, SnapshotStore};
pub use certificate_creator::{CertificateCreator, MithrilCertificateCreator};
pub use command_args::MainOpts;
pub use dependency::DependencyManager;
pub use http_server::Server;
Expand Down
Loading