Skip to content

Commit 5fb8826

Browse files
authored
Merge pull request #2378 from input-output-hk/jpraynaud/2361-e2e-test-slave-aggregator
Feat(e2e): support multiple aggregators in the e2e tests
2 parents 1c1024b + e442474 commit 5fb8826

40 files changed

+1763
-721
lines changed

.github/workflows/ci.yml

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -303,14 +303,22 @@ jobs:
303303
extra_args: [""]
304304

305305
include:
306-
# Include a test for the P2P mode
307-
- mode: "p2p"
306+
# Include a test for partial decentralization with master/slave signer registration and P2P signature registration
307+
- mode: "master-slave"
308308
era: ${{ fromJSON(needs.build-ubuntu-X64.outputs.eras)[0] }}
309309
next_era: [""]
310310
cardano_node_version: "10.2.1"
311311
hard_fork_latest_era_at_epoch: 0
312312
run_id: "#1"
313-
extra_args: "--use-p2p-network"
313+
extra_args: "--number-of-aggregators=2 --use-relays --relay-signer-registration-mode=passthrough --relay-signature-registration-mode=p2p"
314+
# Include a test for full dedentralization P2P signer registration and P2P signature registration
315+
- mode: "decentralized"
316+
era: ${{ fromJSON(needs.build-ubuntu-X64.outputs.eras)[0] }}
317+
next_era: ""
318+
cardano_node_version: "10.1.4"
319+
hard_fork_latest_era_at_epoch: 0
320+
run_id: "#1"
321+
extra_args: "--number-of-aggregators=2 --use-relays --relay-signer-registration-mode=p2p --relay-signature-registration-mode=p2p"
314322
# Include a test for the era switch without regenesis
315323
- mode: "std"
316324
era: ${{ fromJSON(needs.build-ubuntu-X64.outputs.eras)[0] }}

Cargo.lock

Lines changed: 30 additions & 7 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

mithril-aggregator/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "mithril-aggregator"
3-
version = "0.7.25"
3+
version = "0.7.26"
44
description = "A Mithril Aggregator server"
55
authors = { workspace = true }
66
edition = { workspace = true }

mithril-aggregator/src/dependency_injection/builder/protocol/certificates.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,7 @@ impl DependenciesBuilder {
161161
&mut self,
162162
) -> Result<Arc<MithrilSignerRegistrationSlave>> {
163163
let registerer = MithrilSignerRegistrationSlave::new(
164+
self.get_epoch_service().await?,
164165
self.get_verification_key_store().await?,
165166
self.get_signer_store().await?,
166167
self.get_signer_registration_verifier().await?,

mithril-aggregator/src/runtime/state_machine.rs

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,6 @@ impl AggregatorRuntime {
143143
info!(self.logger, "→ Trying to transition to READY"; "last_time_point" => ?last_time_point);
144144

145145
let can_try_transition_from_idle_to_ready = if self.config.is_slave {
146-
println!("Checking if slave aggregator is at the same epoch as master");
147146
self.runner
148147
.is_slave_aggregator_at_same_epoch_as_master(&last_time_point)
149148
.await?
@@ -265,18 +264,17 @@ impl AggregatorRuntime {
265264
self.runner
266265
.update_stake_distribution(&new_time_point)
267266
.await?;
268-
if self.config.is_slave {
269-
self.runner
270-
.synchronize_slave_aggregator_signer_registration()
271-
.await?;
272-
}
273267
self.runner.inform_new_epoch(new_time_point.epoch).await?;
274-
275268
self.runner.upkeep(new_time_point.epoch).await?;
276269
self.runner
277270
.open_signer_registration_round(&new_time_point)
278271
.await?;
279272
self.runner.update_epoch_settings().await?;
273+
if self.config.is_slave {
274+
self.runner
275+
.synchronize_slave_aggregator_signer_registration()
276+
.await?;
277+
}
280278
self.runner.precompute_epoch_data().await?;
281279
}
282280

mithril-aggregator/src/services/epoch_service.rs

Lines changed: 78 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,9 @@ pub trait EpochService: Sync + Send {
4949
/// Note: must be called after `inform_epoch`.
5050
async fn update_epoch_settings(&mut self) -> StdResult<()>;
5151

52+
/// Update the next signers with stake for the next epoch.
53+
async fn update_next_signers_with_stake(&mut self) -> StdResult<()>;
54+
5255
/// Inform the service that it can precompute data for its current epoch.
5356
///
5457
/// Note: must be called after `inform_epoch`.
@@ -383,6 +386,27 @@ impl EpochService for MithrilEpochService {
383386
self.insert_future_epoch_settings(data.epoch).await
384387
}
385388

389+
async fn update_next_signers_with_stake(&mut self) -> StdResult<()> {
390+
debug!(self.logger, ">> update_next_signers_with_stake");
391+
392+
let data = self.unwrap_data().with_context(|| {
393+
"can't update next signers with stake if inform_epoch has not been called first"
394+
})?;
395+
396+
let next_signer_retrieval_epoch = data.epoch.offset_to_next_signer_retrieval_epoch();
397+
let next_signers_with_stake = self
398+
.get_signers_with_stake_at_epoch(next_signer_retrieval_epoch)
399+
.await?;
400+
401+
self.epoch_data.as_mut().unwrap().next_signers_with_stake = next_signers_with_stake;
402+
403+
self.precompute_epoch_data()
404+
.await
405+
.with_context(|| "Epoch service failed to precompute epoch data")?;
406+
407+
Ok(())
408+
}
409+
386410
async fn precompute_epoch_data(&mut self) -> StdResult<()> {
387411
debug!(self.logger, ">> precompute_epoch_data");
388412

@@ -523,6 +547,7 @@ pub(crate) struct FakeEpochService {
523547
inform_epoch_error: bool,
524548
update_epoch_settings_error: bool,
525549
precompute_epoch_data_error: bool,
550+
update_next_signers_with_stake_error: bool,
526551
}
527552

528553
#[cfg(test)]
@@ -615,6 +640,7 @@ impl FakeEpochServiceBuilder {
615640
inform_epoch_error: false,
616641
update_epoch_settings_error: false,
617642
precompute_epoch_data_error: false,
643+
update_next_signers_with_stake_error: false,
618644
}
619645
}
620646
}
@@ -660,19 +686,21 @@ impl FakeEpochService {
660686
inform_epoch_error: false,
661687
update_epoch_settings_error: false,
662688
precompute_epoch_data_error: false,
689+
update_next_signers_with_stake_error: false,
663690
}
664691
}
665692

666-
#[allow(dead_code)]
667693
pub fn toggle_errors(
668694
&mut self,
669695
inform_epoch: bool,
670696
update_protocol_parameters: bool,
671697
precompute_epoch: bool,
698+
update_next_signers_with_stake: bool,
672699
) {
673700
self.inform_epoch_error = inform_epoch;
674701
self.update_epoch_settings_error = update_protocol_parameters;
675702
self.precompute_epoch_data_error = precompute_epoch;
703+
self.update_next_signers_with_stake_error = update_next_signers_with_stake;
676704
}
677705

678706
fn unwrap_data(&self) -> Result<&EpochData, EpochServiceError> {
@@ -714,6 +742,13 @@ impl EpochService for FakeEpochService {
714742
Ok(())
715743
}
716744

745+
async fn update_next_signers_with_stake(&mut self) -> StdResult<()> {
746+
if self.update_next_signers_with_stake_error {
747+
anyhow::bail!("update_next_signers_with_stake fake error");
748+
}
749+
Ok(())
750+
}
751+
717752
fn cardano_era(&self) -> StdResult<CardanoEra> {
718753
Ok(self.unwrap_data()?.cardano_era.clone())
719754
}
@@ -1213,6 +1248,48 @@ mod tests {
12131248
assert!(service.computed_epoch_data.is_none());
12141249
}
12151250

1251+
#[tokio::test]
1252+
async fn update_next_signers_with_stake_succeeds() {
1253+
let fixture = MithrilFixtureBuilder::default().with_signers(3).build();
1254+
let next_fixture = MithrilFixtureBuilder::default().with_signers(5).build();
1255+
let next_avk = next_fixture.compute_avk();
1256+
let epoch = Epoch(4);
1257+
let mut service = EpochServiceBuilder {
1258+
next_signers_with_stake: next_fixture.signers_with_stake().clone(),
1259+
..EpochServiceBuilder::new(epoch, fixture.clone())
1260+
}
1261+
.build()
1262+
.await;
1263+
service
1264+
.inform_epoch(epoch)
1265+
.await
1266+
.expect("inform_epoch should not fail");
1267+
service.epoch_data = Some(EpochData {
1268+
next_signers_with_stake: vec![],
1269+
..service.epoch_data.unwrap()
1270+
});
1271+
service.computed_epoch_data = None;
1272+
1273+
service
1274+
.update_next_signers_with_stake()
1275+
.await
1276+
.expect("update_next_signers_with_stake should not fail");
1277+
1278+
let expected_next_signers_with_stake = next_fixture.signers_with_stake();
1279+
assert_eq!(
1280+
expected_next_signers_with_stake,
1281+
service.epoch_data.unwrap().next_signers_with_stake
1282+
);
1283+
1284+
assert_eq!(
1285+
next_avk,
1286+
service
1287+
.computed_epoch_data
1288+
.unwrap()
1289+
.next_aggregate_verification_key
1290+
);
1291+
}
1292+
12161293
#[tokio::test]
12171294
async fn update_epoch_settings_insert_future_epoch_settings_in_the_store() {
12181295
let future_protocol_parameters = ProtocolParameters::new(6, 89, 0.124);

mithril-aggregator/src/services/signer_registration/error.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,13 @@ pub enum SignerRegistrationError {
3131
#[error("signer already registered")]
3232
ExistingSigner(Box<SignerWithStake>),
3333

34-
/// Store error.
34+
/// Store.
3535
#[error("store error")]
36-
StoreError(#[source] StdError),
36+
Store(#[source] StdError),
37+
38+
/// Epoch service.
39+
#[error("epoch service error")]
40+
EpochService(#[source] StdError),
3741

3842
/// Signer registration failed.
3943
#[error("signer registration failed")]

mithril-aggregator/src/services/signer_registration/master.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ impl SignerRegisterer for MithrilSignerRegistrationMaster {
147147
registration_round.epoch
148148
)
149149
})
150-
.map_err(|e| SignerRegistrationError::StoreError(anyhow!(e)))?
150+
.map_err(|e| SignerRegistrationError::Store(anyhow!(e)))?
151151
{
152152
Some(_) => Err(SignerRegistrationError::ExistingSigner(Box::new(
153153
signer_save,

0 commit comments

Comments
 (0)