Skip to content

Implement signable and artifact builders for Cardano Stake Distribution #1847

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

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
6c99591
feat: extend `ProtocolMessagePartKey` with `CardanoStakeDistributionE…
dlachaume Jul 16, 2024
fb246c0
feat: implement `CardanoStakeDistributionSignableBuilder`
dlachaume Jul 16, 2024
fefbc89
feat: handle `CardanoStakeDistribution` signed entity type in `Signab…
dlachaume Jul 17, 2024
8d230f3
feat: implement `StakeDistributionRetriever` for `StakeStore` in the …
dlachaume Jul 17, 2024
e044bc2
feat: implement `StakeDistributionRetriever` for `StakePoolStore` in …
dlachaume Jul 17, 2024
7550e0c
feat: create `CardanoStakeDistribution` entity
dlachaume Jul 17, 2024
6aa2545
feat: implement `CardanoStakeDistributionArtifactBuilder`
dlachaume Jul 19, 2024
c72c20e
feat: implement `compute_hash` for `CardanoStakeDistribution`
dlachaume Jul 19, 2024
5876347
feat: wire `CardanoStakeDistributionArtifactBuilder` with Signed enti…
dlachaume Jul 19, 2024
d3d52f9
test: activate `CardanoStakeDistribution` in E2E
dlachaume Jul 19, 2024
375cc29
feat: `StakeDistributionRetriever` as dependency for `CardanoStakeDis…
dlachaume Jul 22, 2024
cd6edb5
fix: typo and clarify formulations
dlachaume Jul 22, 2024
ab5a2ad
feat: introduced new type representing a stake distribution entry tha…
dlachaume Jul 22, 2024
89f3407
feat: apply epoch offset when retrieving the stake distribution for S…
dlachaume Jul 25, 2024
0071868
feat: apply epoch offset when creating a `SignedEntityType` from a `T…
dlachaume Jul 25, 2024
37b9d4d
feat: create dedicated function to get the epoch when the signed enti…
dlachaume Jul 26, 2024
7a98039
docs: reference the feature in the `CHANGELOG`
dlachaume Jul 19, 2024
54f5e3e
fix: minor changes from PR review comments
dlachaume Jul 29, 2024
f8b1f0e
feat: move epoch offset responsibility when retrieving a stake distri…
dlachaume Jul 29, 2024
4829708
chore: bump crates versions
dlachaume Jul 29, 2024
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
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ As a minor extension, we have adopted a slightly different versioning convention

## Mithril Distribution [XXXX] - UNRELEASED

- **UNSTABLE** Cardano stake distribution certification:

- Implement the signable and artifact builders for the signed entity type `CardanoStakeDistribution`

- Crates versions:

| Crate | Version |
Expand Down
10 changes: 5 additions & 5 deletions Cargo.lock

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

2 changes: 1 addition & 1 deletion internal/mithril-persistence/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "mithril-persistence"
version = "0.2.21"
version = "0.2.22"
description = "Common types, interfaces, and utilities to persist data for Mithril nodes."
authors = { workspace = true }
edition = { workspace = true }
Expand Down
34 changes: 34 additions & 0 deletions internal/mithril-persistence/src/store/stake_store.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use async_trait::async_trait;
use mithril_common::entities::{Epoch, StakeDistribution};
use mithril_common::signable_builder::StakeDistributionRetriever;
use mithril_common::StdResult;
use tokio::sync::RwLock;

Expand Down Expand Up @@ -79,6 +80,15 @@ impl StakeStorer for StakeStore {
}
}

#[async_trait]
impl StakeDistributionRetriever for StakeStore {
async fn retrieve(&self, epoch: Epoch) -> StdResult<Option<StakeDistribution>> {
let stake_distribution = self.get_stakes(epoch).await?;

Ok(stake_distribution)
}
}

#[cfg(test)]
mod tests {
use super::super::adapter::MemoryAdapter;
Expand Down Expand Up @@ -167,4 +177,28 @@ mod tests {
.unwrap();
assert!(store.get_stakes(Epoch(1)).await.unwrap().is_none());
}

#[tokio::test]
async fn retrieve_with_no_stakes_returns_none() {
let store = init_store(0, 0, None);

let result = store.retrieve(Epoch(1)).await.unwrap();

assert!(result.is_none());
}

#[tokio::test]
async fn retrieve_returns_stake_distribution() {
let stake_distribution_to_retrieve =
StakeDistribution::from([("pool-123".to_string(), 123)]);
let store = init_store(0, 0, None);
store
.save_stakes(Epoch(1), stake_distribution_to_retrieve.clone())
.await
.unwrap();

let stake_distribution = store.retrieve(Epoch(1)).await.unwrap();

assert_eq!(stake_distribution, Some(stake_distribution_to_retrieve));
}
}
2 changes: 1 addition & 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.5.50"
version = "0.5.51"
description = "A Mithril Aggregator server"
authors = { workspace = true }
edition = { workspace = true }
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
use anyhow::anyhow;
use async_trait::async_trait;
use std::sync::Arc;

use mithril_common::{
entities::{CardanoStakeDistribution, Certificate, Epoch},
signable_builder::StakeDistributionRetriever,
StdResult,
};

use crate::ArtifactBuilder;

/// A [CardanoStakeDistributionArtifact] builder
pub struct CardanoStakeDistributionArtifactBuilder {
stake_distribution_retriever: Arc<dyn StakeDistributionRetriever>,
}

impl CardanoStakeDistributionArtifactBuilder {
/// CardanoStakeDistribution artifact builder factory
pub fn new(stake_distribution_retriever: Arc<dyn StakeDistributionRetriever>) -> Self {
Self {
stake_distribution_retriever,
}
}
}

#[async_trait]
impl ArtifactBuilder<Epoch, CardanoStakeDistribution> for CardanoStakeDistributionArtifactBuilder {
async fn compute_artifact(
&self,
epoch: Epoch,
_certificate: &Certificate,
) -> StdResult<CardanoStakeDistribution> {
let stake_distribution = self
.stake_distribution_retriever
.retrieve(epoch.offset_to_recording_epoch())
.await?
.ok_or_else(|| anyhow!("No stake distribution found for epoch '{}'", epoch))?;

Ok(CardanoStakeDistribution::new(epoch, stake_distribution))
}
}

#[cfg(test)]
mod tests {
use mithril_common::{entities::StakeDistribution, test_utils::fake_data};
use mockall::{mock, predicate::eq};

use super::*;

mock! {
pub StakeDistributionRetrieverImpl {}

#[async_trait]
impl StakeDistributionRetriever for StakeDistributionRetrieverImpl {
async fn retrieve(&self, epoch: Epoch) -> StdResult<Option<StakeDistribution>>;
}
}

#[tokio::test]
async fn compute_artifact_returns_valid_artifact_and_retrieve_with_epoch_offset() {
let epoch = Epoch(1);
let epoch_to_retrieve = Epoch(2);
let certificate = fake_data::certificate("whatever".to_string());
let stake_distribution = StakeDistribution::from([("pool-123".to_string(), 123)]);
let stake_distribution_clone = stake_distribution.clone();
let mut mock_storer = MockStakeDistributionRetrieverImpl::new();
mock_storer
.expect_retrieve()
.with(eq(epoch_to_retrieve))
.return_once(move |_| Ok(Some(stake_distribution_clone)));
let builder = CardanoStakeDistributionArtifactBuilder::new(Arc::new(mock_storer));

let cardano_stake_distribution =
builder.compute_artifact(epoch, &certificate).await.unwrap();

let expected = CardanoStakeDistribution::new(epoch, stake_distribution);
assert_eq!(cardano_stake_distribution, expected);
}

#[tokio::test]
async fn compute_artifact_returns_error_if_no_stakes_found_for_epoch() {
let epoch = Epoch(1);
let epoch_to_retrieve = Epoch(2);
let certificate = fake_data::certificate("whatever".to_string());
let mut mock_storer = MockStakeDistributionRetrieverImpl::new();
mock_storer
.expect_retrieve()
.with(eq(epoch_to_retrieve))
.return_once(move |_| Ok(None));
let builder = CardanoStakeDistributionArtifactBuilder::new(Arc::new(mock_storer));

builder
.compute_artifact(epoch, &certificate)
.await
.expect_err("Should return error");
}
}
2 changes: 2 additions & 0 deletions mithril-aggregator/src/artifact_builder/mod.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
//! The module used for building artifact
mod cardano_immutable_files_full;
mod cardano_stake_distribution;
mod cardano_transactions;
mod interface;
mod mithril_stake_distribution;

pub use cardano_immutable_files_full::*;
pub use cardano_stake_distribution::*;
pub use cardano_transactions::*;
pub use interface::*;
pub use mithril_stake_distribution::*;
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ impl OpenMessageRepository {
) -> StdResult<Option<OpenMessageWithSingleSignaturesRecord>> {
self.connection.fetch_first(
GetOpenMessageWithSingleSignaturesQuery::by_epoch_and_signed_entity_type(
signed_entity_type.get_epoch(),
signed_entity_type.get_epoch_when_signed_entity_type_is_signed(),
signed_entity_type,
)?,
)
Expand Down
36 changes: 36 additions & 0 deletions mithril-aggregator/src/database/repository/stake_pool_store.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use anyhow::Context;
use async_trait::async_trait;

use mithril_common::entities::{Epoch, StakeDistribution};
use mithril_common::signable_builder::StakeDistributionRetriever;
use mithril_common::StdResult;
use mithril_persistence::sqlite::{ConnectionExtensions, SqliteConnection};
use mithril_persistence::store::adapter::AdapterError;
Expand Down Expand Up @@ -87,6 +88,15 @@ impl StakeStorer for StakePoolStore {
}
}

#[async_trait]
impl StakeDistributionRetriever for StakePoolStore {
async fn retrieve(&self, epoch: Epoch) -> StdResult<Option<StakeDistribution>> {
let stake_distribution = self.get_stakes(epoch).await?;

Ok(stake_distribution)
}
}

#[cfg(test)]
mod tests {
use crate::database::test_helper::{insert_stake_pool, main_db_connection};
Expand Down Expand Up @@ -120,4 +130,30 @@ mod tests {
"Stakes at epoch 2 should still exist",
);
}

#[tokio::test]
async fn retrieve_with_no_stakes_returns_none() {
let connection = main_db_connection().unwrap();
let store = StakePoolStore::new(Arc::new(connection), None);

let result = store.retrieve(Epoch(1)).await.unwrap();

assert!(result.is_none());
}

#[tokio::test]
async fn retrieve_returns_stake_distribution() {
let stake_distribution_to_retrieve =
StakeDistribution::from([("pool-123".to_string(), 123)]);
let connection = main_db_connection().unwrap();
let store = StakePoolStore::new(Arc::new(connection), None);
store
.save_stakes(Epoch(1), stake_distribution_to_retrieve.clone())
.await
.unwrap();

let stake_distribution = store.retrieve(Epoch(1)).await.unwrap();

assert_eq!(stake_distribution, Some(stake_distribution_to_retrieve));
}
}
18 changes: 13 additions & 5 deletions mithril-aggregator/src/dependency_injection/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,9 @@ use mithril_common::{
EraChecker, EraMarker, EraReader, EraReaderAdapter, SupportedEra,
},
signable_builder::{
CardanoImmutableFilesFullSignableBuilder, CardanoTransactionsSignableBuilder,
MithrilSignableBuilderService, MithrilStakeDistributionSignableBuilder,
SignableBuilderService, TransactionsImporter,
CardanoImmutableFilesFullSignableBuilder, CardanoStakeDistributionSignableBuilder,
CardanoTransactionsSignableBuilder, MithrilSignableBuilderService,
MithrilStakeDistributionSignableBuilder, SignableBuilderService, TransactionsImporter,
},
signed_entity_type_lock::SignedEntityTypeLock,
MithrilTickerService, TickerService,
Expand All @@ -52,8 +52,8 @@ use mithril_persistence::{

use crate::{
artifact_builder::{
CardanoImmutableFilesFullArtifactBuilder, CardanoTransactionsArtifactBuilder,
MithrilStakeDistributionArtifactBuilder,
CardanoImmutableFilesFullArtifactBuilder, CardanoStakeDistributionArtifactBuilder,
CardanoTransactionsArtifactBuilder, MithrilStakeDistributionArtifactBuilder,
},
configuration::ExecutionEnvironment,
database::repository::{
Expand Down Expand Up @@ -1090,10 +1090,14 @@ impl DependenciesBuilder {
block_range_root_retriever,
self.get_logger()?,
));
let cardano_stake_distribution_builder = Arc::new(
CardanoStakeDistributionSignableBuilder::new(self.get_stake_store().await?),
);
let signable_builder_service = Arc::new(MithrilSignableBuilderService::new(
mithril_stake_distribution_builder,
immutable_signable_builder,
cardano_transactions_builder,
cardano_stake_distribution_builder,
));

Ok(signable_builder_service)
Expand Down Expand Up @@ -1130,12 +1134,16 @@ impl DependenciesBuilder {
let cardano_transactions_artifact_builder = Arc::new(
CardanoTransactionsArtifactBuilder::new(prover_service.clone()),
);
let stake_store = self.get_stake_store().await?;
let cardano_stake_distribution_artifact_builder =
Arc::new(CardanoStakeDistributionArtifactBuilder::new(stake_store));
let signed_entity_service = Arc::new(MithrilSignedEntityService::new(
signed_entity_storer,
mithril_stake_distribution_artifact_builder,
cardano_immutable_files_full_artifact_builder,
cardano_transactions_artifact_builder,
self.get_signed_entity_lock().await?,
cardano_stake_distribution_artifact_builder,
));

// Compute the cache pool for prover service
Expand Down
14 changes: 10 additions & 4 deletions mithril-aggregator/src/http_server/routes/signatures_routes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,17 @@ mod handlers {

let signed_entity_type = match message.signed_entity_type.clone() {
Some(signed_entity_type) => Ok(signed_entity_type),
// The '.unwrap()' inside the 'None' branch is safe
// This case does not occur anymore, as there are no signers using the Mithril Signer node
// version that sends a 'RegisterSignatureMessage' without the 'signed_entity_type' field.
// TODO: Make the 'signed_entity_type' field mandatory in the 'RegisterSignatureMessage'.
None => ticker_service.get_current_time_point().await.map(|t| {
signed_entity_config.time_point_to_signed_entity(
SignedEntityTypeDiscriminants::CardanoImmutableFilesFull,
&t,
)
signed_entity_config
.time_point_to_signed_entity(
SignedEntityTypeDiscriminants::CardanoImmutableFilesFull,
&t,
)
.unwrap()
}),
};

Expand Down
Loading
Loading