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

Use Artifact Builder Service in aggregator #906

Merged
merged 11 commits into from
May 9, 2023
5 changes: 3 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion mithril-aggregator/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "mithril-aggregator"
version = "0.3.14"
version = "0.3.15"
description = "A Mithril Aggregator server"
authors = { workspace = true }
edition = { workspace = true }
Expand All @@ -23,6 +23,7 @@ semver = "1.0.16"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
serde_yaml = "0.9.10"
sha2 = "0.10.2"
slog = { version = "2.7.0", features = ["max_level_trace", "release_max_level_debug"] }
slog-async = "2.7.0"
slog-bunyan = "2.4.0"
Expand Down
59 changes: 49 additions & 10 deletions mithril-aggregator/src/artifact_builder/artifact_builder_service.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use async_trait::async_trait;
use chrono::Utc;

use std::sync::Arc;

Expand All @@ -8,7 +9,10 @@ use mithril_common::{
StdResult,
};

use crate::artifact_builder::ArtifactBuilder;
use crate::{
artifact_builder::ArtifactBuilder,
database::provider::{SignedEntityRecord, SignedEntityStorer},
};

use super::MithrilStakeDistribution;

Expand All @@ -19,40 +23,39 @@ use mockall::automock;
#[cfg_attr(test, automock)]
#[async_trait]
pub trait ArtifactBuilderService: Send + Sync {
/// Compute artifact from signed entity type
async fn compute_artifact(
/// Create artifact for a signed entity type and a certificate
async fn create_artifact(
&self,
signed_entity_type: SignedEntityType,
certificate: &Certificate,
) -> StdResult<Arc<dyn Artifact>>;
) -> StdResult<()>;
}

/// Mithril ArtifactBuilder Service
pub struct MithrilArtifactBuilderService {
signed_entity_storer: Arc<dyn SignedEntityStorer>,
mithril_stake_distribution_artifact_builder:
Arc<dyn ArtifactBuilder<Epoch, MithrilStakeDistribution>>,
cardano_immutable_files_full_artifact_builder: Arc<dyn ArtifactBuilder<Beacon, Snapshot>>,
}

impl MithrilArtifactBuilderService {
/// MithrilArtifactBuilderService factory
#[allow(dead_code)]
pub fn new(
signed_entity_storer: Arc<dyn SignedEntityStorer>,
mithril_stake_distribution_artifact_builder: Arc<
dyn ArtifactBuilder<Epoch, MithrilStakeDistribution>,
>,
cardano_immutable_files_full_artifact_builder: Arc<dyn ArtifactBuilder<Beacon, Snapshot>>,
) -> Self {
Self {
signed_entity_storer,
mithril_stake_distribution_artifact_builder,
cardano_immutable_files_full_artifact_builder,
}
}
}

#[async_trait]
impl ArtifactBuilderService for MithrilArtifactBuilderService {
#[allow(dead_code)]
/// Compute artifact from signed entity type
async fn compute_artifact(
&self,
signed_entity_type: SignedEntityType,
Expand All @@ -74,20 +77,51 @@ impl ArtifactBuilderService for MithrilArtifactBuilderService {
}
}

#[async_trait]
impl ArtifactBuilderService for MithrilArtifactBuilderService {
async fn create_artifact(
&self,
signed_entity_type: SignedEntityType,
certificate: &Certificate,
) -> StdResult<()> {
let artifact = self
.compute_artifact(signed_entity_type.clone(), certificate)
.await?;
let signed_entity = SignedEntityRecord {
signed_entity_id: artifact.get_id(),
signed_entity_type,
certificate_id: certificate.hash.clone(),
artifact: serde_json::to_string(&artifact)?,
created_at: format!("{:?}", Utc::now()),
};

self.signed_entity_storer
.store_signed_entity(&signed_entity)
.await?;

Ok(())
}
}

#[cfg(test)]
mod tests {
use mithril_common::{entities::Epoch, test_utils::fake_data};

use super::*;

use crate::artifact_builder::MockArtifactBuilder;
use crate::{
artifact_builder::MockArtifactBuilder, database::provider::MockSignedEntityStorer,
};

#[tokio::test]
async fn build_mithril_stake_distribution_artifact_when_given_mithril_stake_distribution_entity_type(
) {
let signers_with_stake = fake_data::signers_with_stakes(5);
let mithril_stake_distribution_expected = MithrilStakeDistribution::new(signers_with_stake);
let mithril_stake_distribution_clone = mithril_stake_distribution_expected.clone();

let mock_signed_entity_storer = MockSignedEntityStorer::new();

let mut mock_mithril_stake_distribution_artifact_builder =
MockArtifactBuilder::<Epoch, MithrilStakeDistribution>::new();
mock_mithril_stake_distribution_artifact_builder
Expand All @@ -99,6 +133,7 @@ mod tests {
MockArtifactBuilder::<Beacon, Snapshot>::new();

let artifact_builder_service = MithrilArtifactBuilderService::new(
Arc::new(mock_signed_entity_storer),
Arc::new(mock_mithril_stake_distribution_artifact_builder),
Arc::new(mock_cardano_immutable_files_full_artifact_builder),
);
Expand All @@ -121,6 +156,9 @@ mod tests {
async fn build_snapshot_artifact_when_given_cardano_immutable_files_full_entity_type() {
let snapshot_expected = fake_data::snapshots(1).first().unwrap().to_owned();
let snapshot_expected_clone = snapshot_expected.clone();

let mock_signed_entity_storer = MockSignedEntityStorer::new();

let mock_mithril_stake_distribution_artifact_builder =
MockArtifactBuilder::<Epoch, MithrilStakeDistribution>::new();

Expand All @@ -132,6 +170,7 @@ mod tests {
.return_once(move |_, _| Ok(snapshot_expected_clone));

let artifact_builder_service = MithrilArtifactBuilderService::new(
Arc::new(mock_signed_entity_storer),
Arc::new(mock_mithril_stake_distribution_artifact_builder),
Arc::new(mock_cardano_immutable_files_full_artifact_builder),
);
Expand Down
58 changes: 0 additions & 58 deletions mithril-aggregator/src/artifact_builder/dummy_artifact.rs

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use async_trait::async_trait;
use serde::{Deserialize, Serialize};
use sha2::{Digest, Sha256};
use std::sync::Arc;
use tokio::sync::RwLock;

Expand All @@ -15,17 +16,37 @@ use mithril_common::{
#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
pub struct MithrilStakeDistribution {
signers_with_stake: Vec<SignerWithStake>,
hash: String,
}

impl MithrilStakeDistribution {
/// MithrilStakeDistribution artifact factory
pub fn new(signers_with_stake: Vec<SignerWithStake>) -> Self {
Self { signers_with_stake }
let mut signers_with_stake_sorted = signers_with_stake;
signers_with_stake_sorted.sort();
let mut mithril_stake_distribution = Self {
signers_with_stake: signers_with_stake_sorted,
hash: "".to_string(),
};
mithril_stake_distribution.hash = mithril_stake_distribution.compute_hash();
mithril_stake_distribution
}

fn compute_hash(&self) -> String {
let mut hasher = Sha256::new();
for signer_with_stake in &self.signers_with_stake {
hasher.update(signer_with_stake.compute_hash().as_bytes());
}
hex::encode(hasher.finalize())
}
}

#[typetag::serde]
impl Artifact for MithrilStakeDistribution {}
impl Artifact for MithrilStakeDistribution {
fn get_id(&self) -> String {
self.hash.clone()
}
}

/// A [MithrilStakeDistributionArtifact] builder
pub struct MithrilStakeDistributionArtifactBuilder {
Expand Down Expand Up @@ -79,4 +100,24 @@ mod tests {
let artifact_expected = MithrilStakeDistribution::new(signers_with_stake);
assert_eq!(artifact_expected, artifact);
}

#[test]
fn sort_given_signers_when_created() {
let signers_with_stake = fake_data::signers_with_stakes(5);

assert_eq!(
MithrilStakeDistribution::new(signers_with_stake.clone()),
MithrilStakeDistribution::new(signers_with_stake.into_iter().rev().collect())
);
}

#[test]
fn hash_value_doesnt_change_if_signers_order_change() {
let signers_with_stake = fake_data::signers_with_stakes(5);

let sd = MithrilStakeDistribution::new(signers_with_stake.clone());
let sd2 = MithrilStakeDistribution::new(signers_with_stake.into_iter().rev().collect());

assert_eq!(sd.hash, sd2.hash);
}
}
2 changes: 0 additions & 2 deletions mithril-aggregator/src/artifact_builder/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,10 @@
mod artifact_builder_service;
mod cardano_immutable_files_full;
mod dummy_artifact;
mod interface;
mod mithril_stake_distribution;

pub use artifact_builder_service::*;
pub use cardano_immutable_files_full::*;
pub use dummy_artifact::*;
pub use interface::*;
pub use mithril_stake_distribution::*;
10 changes: 10 additions & 0 deletions mithril-aggregator/src/database/migration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,16 @@ drop table single_signature_legacy;
alter table open_message drop column message;
alter table open_message add column protocol_message json not null;
alter table open_message add column is_certified bool not null default false;
"#,
),
// Migration 11
// Alter `signed_entity` table
SqlMigration::new(
11,
r#"
alter table signed_entity add column artifact json not null;
update signed_entity set artifact = entity;
alter table signed_entity drop column entity;
"#,
),
]
Expand Down
1 change: 0 additions & 1 deletion mithril-aggregator/src/database/provider/open_message.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ type StdResult<T> = Result<T, StdError>;
/// An open message is a message open for signatures. Every signer may send a
/// single signature for this message from which a multi signature will be
/// generated if possible.
#[allow(dead_code)]
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct OpenMessageRecord {
/// OpenMessage unique identifier
Expand Down
Loading