Skip to content

Commit 571ccb9

Browse files
committed
Add a integration test on the prover in mithril-aggregator
1 parent 3167a20 commit 571ccb9

File tree

4 files changed

+192
-15
lines changed

4 files changed

+192
-15
lines changed
Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
use mithril_aggregator::Configuration;
2+
use mithril_common::{
3+
entities::{
4+
CardanoDbBeacon, CardanoTransactionsSigningConfig, ChainPoint, Epoch,
5+
ProtocolMessagePartKey, ProtocolParameters, SignedEntityType,
6+
SignedEntityTypeDiscriminants, TimePoint,
7+
},
8+
test_utils::MithrilFixtureBuilder,
9+
};
10+
use test_extensions::{utilities::get_test_dir, ExpectedCertificate, RuntimeTester};
11+
12+
use crate::test_extensions::utilities::tx_hash;
13+
14+
mod test_extensions;
15+
16+
#[tokio::test(flavor = "multi_thread")]
17+
async fn prove_transactions() {
18+
let protocol_parameters = ProtocolParameters {
19+
k: 5,
20+
m: 150,
21+
phi_f: 0.95,
22+
};
23+
let configuration = Configuration {
24+
protocol_parameters: protocol_parameters.clone(),
25+
signed_entity_types: Some(SignedEntityTypeDiscriminants::CardanoTransactions.to_string()),
26+
data_stores_directory: get_test_dir("prove_transactions"),
27+
cardano_transactions_signing_config: CardanoTransactionsSigningConfig {
28+
security_parameter: 0,
29+
step: 30,
30+
},
31+
..Configuration::new_sample()
32+
};
33+
let mut tester = RuntimeTester::build(
34+
TimePoint {
35+
epoch: Epoch(1),
36+
immutable_file_number: 1,
37+
chain_point: ChainPoint {
38+
slot_number: 10,
39+
block_number: 100,
40+
block_hash: "block_hash-100".to_string(),
41+
},
42+
},
43+
configuration,
44+
)
45+
.await;
46+
let observer = tester.observer.clone();
47+
let prover = tester.dependencies.prover_service.clone();
48+
49+
comment!("create signers & declare stake distribution");
50+
let fixture = MithrilFixtureBuilder::default()
51+
.with_signers(10)
52+
.with_protocol_parameters(protocol_parameters.clone())
53+
.build();
54+
let signers = &fixture.signers_fixture();
55+
56+
tester.init_state_from_fixture(&fixture).await.unwrap();
57+
58+
comment!("Boostrap the genesis certificate");
59+
tester.register_genesis_certificate(&fixture).await.unwrap();
60+
61+
assert_last_certificate_eq!(
62+
tester,
63+
ExpectedCertificate::new_genesis(
64+
CardanoDbBeacon::new("devnet", 1, 1),
65+
fixture.compute_and_encode_avk()
66+
)
67+
);
68+
69+
// Lock all signed entity types except CardanoTransactions to limit the scope of the test
70+
for entity in SignedEntityTypeDiscriminants::all()
71+
.into_iter()
72+
.filter(|e| e != &SignedEntityTypeDiscriminants::CardanoTransactions)
73+
{
74+
tester
75+
.dependencies
76+
.signed_entity_type_lock
77+
.lock(entity)
78+
.await;
79+
}
80+
81+
comment!("register signers");
82+
cycle!(tester, "ready");
83+
tester
84+
.register_signers(&fixture.signers_fixture())
85+
.await
86+
.unwrap();
87+
88+
comment!(
89+
"Increase cardano chain block number to 185,
90+
the state machine should be signing CardanoTransactions up to block 179 included"
91+
);
92+
tester.increase_block_number(85, 185).await.unwrap();
93+
cycle!(tester, "signing");
94+
tester
95+
.send_single_signatures(SignedEntityTypeDiscriminants::CardanoTransactions, signers)
96+
.await
97+
.unwrap();
98+
99+
comment!("The state machine should issue a certificate for the CardanoTransactions");
100+
cycle!(tester, "ready");
101+
assert_last_certificate_eq!(
102+
tester,
103+
ExpectedCertificate::new(
104+
CardanoDbBeacon::new("devnet", 1, 1),
105+
&signers
106+
.iter()
107+
.map(|s| s.signer_with_stake.clone().into())
108+
.collect::<Vec<_>>(),
109+
fixture.compute_and_encode_avk(),
110+
SignedEntityType::CardanoTransactions(Epoch(1), 179),
111+
ExpectedCertificate::genesis_identifier(&CardanoDbBeacon::new("devnet", 1, 1)),
112+
)
113+
);
114+
115+
cycle!(tester, "ready");
116+
117+
comment!("Get the proof for the last transaction, BlockNumber(179), and verify it");
118+
let last_transaction_hash = tx_hash(179, 1);
119+
let last_tx_snapshot = observer
120+
.get_last_cardano_transactions_snapshot()
121+
.await
122+
.unwrap();
123+
let proof_for_last_transaction = prover
124+
.compute_transactions_proofs(
125+
last_tx_snapshot.artifact.block_number,
126+
&[last_transaction_hash.clone()],
127+
)
128+
.await
129+
.unwrap()
130+
.pop()
131+
.unwrap();
132+
assert!(proof_for_last_transaction
133+
.transactions_hashes()
134+
.contains(&last_transaction_hash));
135+
136+
proof_for_last_transaction.verify().unwrap();
137+
138+
comment!("Get the certificate associated with the last transaction and check that it matches the proof");
139+
let proof_merkle_root = proof_for_last_transaction.merkle_root();
140+
let proof_certificate = observer.get_last_certificate().await.unwrap();
141+
assert_eq!(&last_tx_snapshot.certificate_id, &proof_certificate.hash);
142+
assert_eq!(
143+
proof_certificate
144+
.protocol_message
145+
.get_message_part(&ProtocolMessagePartKey::CardanoTransactionsMerkleRoot),
146+
Some(&proof_merkle_root),
147+
"The proof merkle root should match the one in the certificate"
148+
);
149+
}

mithril-aggregator/tests/test_extensions/aggregator_observer.rs

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
use anyhow::{anyhow, Context};
2+
use mithril_aggregator::services::SignedEntityService;
23
use mithril_aggregator::{
34
dependency_injection::DependenciesBuilder, entities::OpenMessage, services::CertifierService,
45
};
6+
use mithril_common::entities::{CardanoTransactionsSnapshot, Certificate, SignedEntity};
57
use mithril_common::{
68
entities::{
79
Epoch, SignedEntityConfig, SignedEntityType, SignedEntityTypeDiscriminants, TimePoint,
@@ -14,6 +16,7 @@ use std::sync::Arc;
1416
pub struct AggregatorObserver {
1517
network: CardanoNetwork,
1618
certifier_service: Arc<dyn CertifierService>,
19+
signed_entity_service: Arc<dyn SignedEntityService>,
1720
ticker_service: Arc<dyn TickerService>,
1821
signed_entity_config: SignedEntityConfig,
1922
}
@@ -24,6 +27,7 @@ impl AggregatorObserver {
2427
Self {
2528
network: deps_builder.configuration.get_network().unwrap(),
2629
certifier_service: deps_builder.get_certifier_service().await.unwrap(),
30+
signed_entity_service: deps_builder.get_signed_entity_service().await.unwrap(),
2731
ticker_service: deps_builder.get_ticker_service().await.unwrap(),
2832
signed_entity_config: deps_builder.get_signed_entity_config().unwrap(),
2933
}
@@ -52,7 +56,7 @@ impl AggregatorObserver {
5256
.with_context(|| "Requesting current open message of type CardanoImmutableFilesFull should be not fail")
5357
}
5458

55-
// Get the [entity type][SignedEntityType::CardanoImmutableFilesFull] of the current current open message
59+
/// Get the [entity type][SignedEntityType::CardanoImmutableFilesFull] of the current current open message
5660
pub async fn get_current_signed_entity_type(
5761
&self,
5862
discriminant: SignedEntityTypeDiscriminants,
@@ -65,6 +69,35 @@ impl AggregatorObserver {
6569
}
6670
}
6771

72+
/// Get the last certificate produced by the aggregator
73+
pub async fn get_last_certificate(&self) -> StdResult<Certificate> {
74+
let certificate = self
75+
.certifier_service
76+
.get_latest_certificates(1)
77+
.await
78+
.with_context(|| "Querying last certificate should not fail")?
79+
.pop()
80+
.ok_or(anyhow!(
81+
"No certificate have been produced by the aggregator"
82+
))?;
83+
Ok(certificate)
84+
}
85+
86+
/// Get the last cardano transactions snapshot produced by the aggregator
87+
pub async fn get_last_cardano_transactions_snapshot(
88+
&self,
89+
) -> StdResult<SignedEntity<CardanoTransactionsSnapshot>> {
90+
let last_tx_snapshot = self
91+
.signed_entity_service
92+
.get_last_cardano_transaction_snapshot()
93+
.await
94+
.with_context(|| "Querying last cardano transactions snapshot should not fail")?
95+
.ok_or(anyhow!(
96+
"No cardano transactions snapshot have been produced by the aggregator"
97+
))?;
98+
Ok(last_tx_snapshot)
99+
}
100+
68101
async fn build_current_signed_entity_type(
69102
&self,
70103
discriminant: SignedEntityTypeDiscriminants,

mithril-aggregator/tests/test_extensions/runtime_tester.rs

Lines changed: 4 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use crate::test_extensions::utilities::tx_hash;
2+
use crate::test_extensions::{AggregatorObserver, ExpectedCertificate};
13
use anyhow::{anyhow, Context};
24
use chrono::Utc;
35
use mithril_aggregator::{
@@ -28,8 +30,6 @@ use std::sync::Arc;
2830
use std::time::Duration;
2931
use tokio::sync::mpsc::UnboundedReceiver;
3032

31-
use crate::test_extensions::{AggregatorObserver, ExpectedCertificate};
32-
3333
#[macro_export]
3434
macro_rules! cycle {
3535
( $tester:expr, $expected_state:expr ) => {{
@@ -276,7 +276,7 @@ impl RuntimeTester {
276276
block_number,
277277
slot_number,
278278
current_immutable,
279-
vec![format!("tx_hash-{block_number}-1")],
279+
vec![tx_hash(block_number, 1)],
280280
)
281281
})
282282
.collect();
@@ -485,17 +485,7 @@ impl RuntimeTester {
485485
pub async fn get_last_certificate_with_signed_entity(
486486
&mut self,
487487
) -> StdResult<(Certificate, Option<SignedEntityRecord>)> {
488-
let certificate = self
489-
.dependencies
490-
.certifier_service
491-
.get_latest_certificates(1)
492-
.await
493-
.with_context(|| "Querying last certificate should not fail")?
494-
.first()
495-
.ok_or(anyhow!(
496-
"No certificate have been produced by the aggregator"
497-
))?
498-
.clone();
488+
let certificate = self.observer.get_last_certificate().await?;
499489

500490
let signed_entity = match &certificate.signature {
501491
CertificateSignature::GenesisSignature(..) => None,

mithril-aggregator/tests/test_extensions/utilities.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use mithril_common::entities::BlockNumber;
12
use mithril_common::test_utils::TempDir;
23
use slog_scope::debug;
34
use std::{
@@ -19,6 +20,10 @@ pub fn comment(comment: String) {
1920
debug!("COMMENT {:02} 💬 {}", old_count + 1, comment);
2021
}
2122

23+
pub fn tx_hash(block_number: BlockNumber, tx_index: u64) -> String {
24+
format!("tx_hash-{block_number}-{tx_index}")
25+
}
26+
2227
#[macro_export]
2328
macro_rules! comment {
2429
( $($comment:tt)* ) => {{

0 commit comments

Comments
 (0)