diff --git a/examples/minimal.rs b/examples/minimal.rs index 0407277cf2..228af2461e 100644 --- a/examples/minimal.rs +++ b/examples/minimal.rs @@ -288,12 +288,10 @@ async fn handle_event(index: usize, node: &mut Routing, event: Event) -> bool { remaining, added, removed, - } => { - info!( - "Node #{} adults changed - remaining: {:?}, added: {:?}, removed: {:?}", - index, remaining, added, removed - ) - } + } => info!( + "Node #{} adults changed - remaining: {:?}, added: {:?}, removed: {:?}", + index, remaining, added, removed + ), } true diff --git a/src/agreement/dkg.rs b/src/agreement/dkg.rs index 4dfd56622b..d59f3ddbfa 100644 --- a/src/agreement/dkg.rs +++ b/src/agreement/dkg.rs @@ -12,7 +12,7 @@ use crate::{ messages::{Message, Variant}, node::Node, routing::command::{self, Command}, - section::{SectionAuthorityProvider, SectionKeyShare}, + section::{EldersInfo, SectionAuthorityProvider, SectionKeyShare}, supermajority, }; use bls_dkg::key_gen::{message::Message as DkgMessage, KeyGen}; @@ -43,17 +43,17 @@ pub struct DkgKey { } impl DkgKey { - pub fn new(section_auth: &SectionAuthorityProvider, generation: u64) -> Self { + pub fn new(elders_info: &EldersInfo, generation: u64) -> Self { // Calculate the hash without involving serialization to avoid having to return `Result`. let mut hasher = Sha3::v256(); let mut hash = Digest256::default(); - for peer in section_auth.peers() { + for peer in elders_info.peers() { hasher.update(&peer.name().0); } - hasher.update(§ion_auth.prefix.name().0); - hasher.update(§ion_auth.prefix.bit_count().to_le_bytes()); + hasher.update(&elders_info.prefix.name().0); + hasher.update(&elders_info.prefix.bit_count().to_le_bytes()); hasher.finalize(&mut hash); Self { hash, generation } @@ -106,28 +106,31 @@ impl DkgVoter { &mut self, keypair: &Keypair, dkg_key: DkgKey, - section_auth: SectionAuthorityProvider, + elders_info: EldersInfo, ) -> Vec { if self.sessions.contains_key(&dkg_key) { - trace!("DKG for {} already in progress", section_auth); + trace!("DKG for {:?} already in progress", elders_info); return vec![]; } let name = crypto::name(&keypair.public); - let participant_index = if let Some(index) = section_auth.position(&name) { + let participant_index = if let Some(index) = elders_info.position(&name) { index } else { error!( - "DKG for {} failed to start: {} is not a participant", - section_auth, name + "DKG for {:?} failed to start: {} is not a participant", + elders_info, name ); return vec![]; }; // Special case: only one participant. - if section_auth.elders.len() == 1 { + if elders_info.elders.len() == 1 { let secret_key_set = bls::SecretKeySet::random(0, &mut rand::thread_rng()); - + let section_auth = SectionAuthorityProvider::from_elders_info( + elders_info, + secret_key_set.public_keys(), + ); return vec![DkgCommand::HandleOutcome { section_auth, outcome: SectionKeyShare { @@ -138,16 +141,16 @@ impl DkgVoter { }]; } - let threshold = supermajority(section_auth.elders.len()) - 1; - let participants = section_auth.elders.keys().copied().collect(); + let threshold = supermajority(elders_info.elders.len()) - 1; + let participants = elders_info.elders.keys().copied().collect(); match KeyGen::initialize(name, threshold, participants) { Ok((key_gen, message)) => { - trace!("DKG for {} starting", section_auth); + trace!("DKG for {:?} starting", elders_info); let mut session = Session { key_gen, - section_auth, + elders_info, participant_index, timer_token: 0, failures: DkgFailureProofSet::default(), @@ -175,7 +178,7 @@ impl DkgVoter { } Err(error) => { // TODO: return a separate error here. - error!("DKG for {} failed to start: {}", section_auth, error); + error!("DKG for {:?} failed to start: {}", elders_info, error); vec![] } } @@ -223,7 +226,7 @@ impl DkgVoter { // Data for a DKG participant. struct Session { - section_auth: SectionAuthorityProvider, + elders_info: EldersInfo, participant_index: usize, key_gen: KeyGen, timer_token: u64, @@ -264,7 +267,7 @@ impl Session { } fn recipients(&self) -> Vec { - self.section_auth + self.elders_info .elders .values() .enumerate() @@ -300,7 +303,7 @@ impl Session { return vec![]; } - trace!("DKG for {} progressing", self.section_auth); + trace!("DKG for {:?} progressing", self.elders_info); match self.key_gen.timed_phase_transition(&mut rand::thread_rng()) { Ok(messages) => { @@ -313,7 +316,7 @@ impl Session { commands } Err(error) => { - trace!("DKG for {} failed: {}", self.section_auth, error); + trace!("DKG for {:?} failed: {}", self.elders_info, error); self.report_failure(dkg_key, BTreeSet::new(), keypair) } } @@ -336,15 +339,15 @@ impl Session { }; // Less than 100% participation - if !participants.iter().eq(self.section_auth.elders.keys()) { + if !participants.iter().eq(self.elders_info.elders.keys()) { trace!( - "DKG for {} failed: unexpected participants: {:?}", - self.section_auth, + "DKG for {:?} failed: unexpected participants: {:?}", + self.elders_info, participants.iter().format(", ") ); let non_participants: BTreeSet<_> = self - .section_auth + .elders_info .elders .keys() .filter_map(|elder| { @@ -368,17 +371,21 @@ impl Session { .public_key_share(self.participant_index) != outcome.secret_key_share.public_key_share() { - trace!("DKG for {} failed: corrupted outcome", self.section_auth); + trace!("DKG for {:?} failed: corrupted outcome", self.elders_info); return self.report_failure(dkg_key, BTreeSet::new(), keypair); } trace!( - "DKG for {} complete: {:?}", - self.section_auth, + "DKG for {:?} complete: {:?}", + self.elders_info, outcome.public_key_set.public_key() ); self.complete = true; + let section_auth = SectionAuthorityProvider::from_elders_info( + self.elders_info.clone(), + outcome.public_key_set.clone(), + ); let outcome = SectionKeyShare { public_key_set: outcome.public_key_set, @@ -387,7 +394,7 @@ impl Session { }; vec![DkgCommand::HandleOutcome { - section_auth: self.section_auth.clone(), + section_auth, outcome, }] } @@ -422,7 +429,7 @@ impl Session { proof: DkgFailureProof, ) -> Option { if !self - .section_auth + .elders_info .elders .contains_key(&crypto::name(&proof.public_key)) { @@ -441,7 +448,7 @@ impl Session { } fn check_failure_agreement(&mut self) -> Option { - if self.failures.has_agreement(&self.section_auth) { + if self.failures.has_agreement(&self.elders_info) { self.complete = true; Some(DkgCommand::HandleFailureAgreement(mem::take( @@ -508,27 +515,27 @@ impl DkgFailureProofSet { // Check whether we have enough proofs to reach agreement on the failure. The contained proofs // are assumed valid. - fn has_agreement(&self, section_auth: &SectionAuthorityProvider) -> bool { - has_failure_agreement(section_auth.elders.len(), self.proofs.len()) + fn has_agreement(&self, elders_info: &EldersInfo) -> bool { + has_failure_agreement(elders_info.elders.len(), self.proofs.len()) } - pub fn verify(&self, section_auth: &SectionAuthorityProvider, generation: u64) -> bool { + pub fn verify(&self, elders_info: &EldersInfo, generation: u64) -> bool { let hash = failure_proof_hash( - &DkgKey::new(section_auth, generation), + &DkgKey::new(elders_info, generation), &self.non_participants, ); let votes = self .proofs .iter() .filter(|proof| { - section_auth + elders_info .elders .contains_key(&crypto::name(&proof.public_key)) }) .filter(|proof| proof.public_key.verify(&hash, &proof.signature).is_ok()) .count(); - has_failure_agreement(section_auth.elders.len(), votes) + has_failure_agreement(elders_info.elders.len(), votes) } } @@ -710,11 +717,10 @@ mod tests { crypto::gen_keypair(&Prefix::default().range_inclusive(), MIN_ADULT_AGE), gen_addr(), ); - let section_auth = - SectionAuthorityProvider::new(iter::once(node.peer()), Prefix::default()); - let dkg_key = DkgKey::new(§ion_auth, 0); + let elders_info = EldersInfo::new(iter::once(node.peer()), Prefix::default()); + let dkg_key = DkgKey::new(&elders_info, 0); - let commands = voter.start(&node.keypair, dkg_key, section_auth); + let commands = voter.start(&node.keypair, dkg_key, elders_info); assert_matches!(&commands[..], &[DkgCommand::HandleOutcome { .. }]); } @@ -733,9 +739,8 @@ mod tests { let mut rng = SmallRng::seed_from_u64(seed); let mut messages = Vec::new(); - let section_auth = - SectionAuthorityProvider::new(nodes.iter().map(Node::peer), Prefix::default()); - let dkg_key = DkgKey::new(§ion_auth, 0); + let elders_info = EldersInfo::new(nodes.iter().map(Node::peer), Prefix::default()); + let dkg_key = DkgKey::new(&elders_info, 0); let mut actors: HashMap<_, _> = nodes .into_iter() @@ -745,7 +750,7 @@ mod tests { for actor in actors.values_mut() { let commands = actor .voter - .start(&actor.node.keypair, dkg_key, section_auth.clone()); + .start(&actor.node.keypair, dkg_key, elders_info.clone()); for command in commands { messages.extend(actor.handle(command, &dkg_key)) diff --git a/src/delivery_group.rs b/src/delivery_group.rs index 16a21965b9..ac87f76b08 100644 --- a/src/delivery_group.rs +++ b/src/delivery_group.rs @@ -108,7 +108,7 @@ fn candidates( let sections = iter::once(section.authority_provider()) .chain(network.all()) .sorted_by(|lhs, rhs| lhs.prefix.cmp_distance(&rhs.prefix, target_name)) - .map(|info| (&info.prefix, info.elders.len(), info.peers())); + .map(|info| (&info.prefix, info.elders().len(), info.peers())); // gives at least 1 honest target among recipients. let min_dg_size = 1 + ELDER_SIZE - supermajority(ELDER_SIZE); @@ -181,7 +181,7 @@ mod tests { let dst_name = *section .authority_provider() - .elders + .elders() .keys() .filter(|&&name| name != our_name) .choose(&mut rand::thread_rng()) @@ -272,7 +272,7 @@ mod tests { let expected_recipients = section_auth1 .peers() .sorted_by(|lhs, rhs| dst_name.cmp_distance(lhs.name(), rhs.name())); - assert_eq!(dg_size, section_auth1.elders.len()); + assert_eq!(dg_size, section_auth1.elders().len()); itertools::assert_equal(recipients, expected_recipients); Ok(()) @@ -298,7 +298,8 @@ mod tests { let expected_recipients = elders_info1 .peers() .sorted_by(|lhs, rhs| dst_name.cmp_distance(lhs.name(), rhs.name())); - let min_dg_size = 1 + elders_info1.elders.len() - supermajority(elders_info1.elders.len()); + let min_dg_size = + 1 + elders_info1.elders().len() - supermajority(elders_info1.elders().len()); assert_eq!(dg_size, min_dg_size); itertools::assert_equal(recipients, expected_recipients); @@ -321,7 +322,7 @@ mod tests { let expected_recipients = section_auth1 .peers() .sorted_by(|lhs, rhs| dst_name.cmp_distance(lhs.name(), rhs.name())); - assert_eq!(dg_size, section_auth1.elders.len()); + assert_eq!(dg_size, section_auth1.elders().len()); itertools::assert_equal(recipients, expected_recipients); Ok(()) @@ -344,7 +345,8 @@ mod tests { let (recipients, dg_size) = delivery_targets(&dst, &our_name, §ion, &network)?; // Send to a subset of elders in the intermediary dst section - let min_dg_size = 1 + elders_info1.elders.len() - supermajority(elders_info1.elders.len()); + let min_dg_size = + 1 + elders_info1.elders().len() - supermajority(elders_info1.elders().len()); let expected_recipients = elders_info1 .peers() .sorted_by(|lhs, rhs| dst_name.cmp_distance(lhs.name(), rhs.name())) @@ -365,7 +367,7 @@ mod tests { let (recipients, dg_size) = delivery_targets(&dst, &our_name, §ion, &network)?; // Send to all elders - assert_eq!(dg_size, section.authority_provider().elders.len()); + assert_eq!(dg_size, section.authority_provider().elders().len()); itertools::assert_equal(recipients, section.authority_provider().peers()); Ok(()) @@ -380,7 +382,7 @@ mod tests { let (recipients, dg_size) = delivery_targets(&dst, &our_name, §ion, &network)?; // Send to all elders - assert_eq!(dg_size, section.authority_provider().elders.len()); + assert_eq!(dg_size, section.authority_provider().elders().len()); itertools::assert_equal(recipients, section.authority_provider().peers()); Ok(()) @@ -395,7 +397,7 @@ mod tests { let (recipients, dg_size) = delivery_targets(&dst, &our_name, §ion, &network)?; // Send to all elders - assert_eq!(dg_size, section.authority_provider().elders.len()); + assert_eq!(dg_size, section.authority_provider().elders().len()); itertools::assert_equal(recipients, section.authority_provider().peers()); Ok(()) @@ -412,7 +414,7 @@ mod tests { let (recipients, dg_size) = delivery_targets(&dst, &our_name, §ion, &network)?; // Send to all elders - assert_eq!(dg_size, section.authority_provider().elders.len()); + assert_eq!(dg_size, section.authority_provider().elders().len()); itertools::assert_equal(recipients, section.authority_provider().peers()); Ok(()) @@ -429,7 +431,7 @@ mod tests { let (recipients, dg_size) = delivery_targets(&dst, &our_name, §ion, &network)?; // Send to all elders - assert_eq!(dg_size, section.authority_provider().elders.len()); + assert_eq!(dg_size, section.authority_provider().elders().len()); itertools::assert_equal(recipients, section.authority_provider().peers()); Ok(()) @@ -485,7 +487,7 @@ mod tests { fn choose_elder_name(section_auth: &SectionAuthorityProvider) -> Result { section_auth - .elders + .elders() .keys() .choose(&mut rand::thread_rng()) .copied() diff --git a/src/lib.rs b/src/lib.rs index 41fa860cb2..78023b1677 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -75,8 +75,8 @@ pub use self::{ event::{Event, NodeElderChange, SendStream}, routing::{Config, EventStream, Routing}, section::{ - SectionChain, SectionChainError, FIRST_SECTION_MAX_AGE, FIRST_SECTION_MIN_AGE, - MIN_ADULT_AGE, MIN_AGE, + EldersInfo, SectionAuthorityProvider, SectionChain, SectionChainError, + FIRST_SECTION_MAX_AGE, FIRST_SECTION_MIN_AGE, MIN_ADULT_AGE, MIN_AGE, }, }; pub use qp2p::Config as TransportConfig; diff --git a/src/messages/variant.rs b/src/messages/variant.rs index c2e3c1d026..9450e1ff5a 100644 --- a/src/messages/variant.rs +++ b/src/messages/variant.rs @@ -13,7 +13,7 @@ use crate::{ error::{Error, Result}, network::Network, relocation::{RelocateDetails, RelocatePayload, RelocatePromise}, - section::{MemberInfo, Section, SectionAuthorityProvider, SectionChain}, + section::{EldersInfo, MemberInfo, Section, SectionAuthorityProvider, SectionChain}, }; use bls_dkg::key_gen::message::Message as DkgMessage; use bytes::Bytes; @@ -77,7 +77,7 @@ pub(crate) enum Variant { /// The identifier of the DKG session to start. dkg_key: DkgKey, /// The DKG particpants. - section_auth: SectionAuthorityProvider, + elders_info: EldersInfo, }, /// Message exchanged for DKG process. DkgMessage { @@ -207,11 +207,11 @@ impl Debug for Variant { .finish(), Self::DkgStart { dkg_key, - section_auth, + elders_info, } => f .debug_struct("DkgStart") .field("dkg_key", dkg_key) - .field("section_auth", section_auth) + .field("elders_info", elders_info) .finish(), Self::DkgMessage { dkg_key, message } => f .debug_struct("DkgMessage") diff --git a/src/network/mod.rs b/src/network/mod.rs index b1d286b610..1164854b88 100644 --- a/src/network/mod.rs +++ b/src/network/mod.rs @@ -75,9 +75,13 @@ impl Network { .get_matching(name)? .section_auth .value - .elders + .elders() .get(name) - .map(|addr| Peer::new(*name, *addr)) + .map(|addr| { + let mut peer = Peer::new(*name, *addr); + peer.set_reachable(true); + peer + }) } /// Merge two `Network`s into one. @@ -241,7 +245,7 @@ impl Network { .map(|p| 1.0 / (p.bit_count() as f64).exp2()) .sum(); - let known = our.elders.len() + self.elders().count(); + let known = our.elders().len() + self.elders().count(); let total = known as f64 / network_fraction; (known as u64, total.ceil() as u64, is_exact) diff --git a/src/relocation.rs b/src/relocation.rs index ffd3d686dc..f44797bc8f 100644 --- a/src/relocation.rs +++ b/src/relocation.rs @@ -291,6 +291,7 @@ mod tests { use crate::{ agreement::test_utils::proven, peer::test_utils::arbitrary_unique_peers, + routing::tests::SecretKeySet, section::{SectionAuthorityProvider, SectionChain}, ELDER_SIZE, MIN_AGE, }; @@ -333,7 +334,8 @@ mod tests { ) -> Result<()> { let mut rng = SmallRng::seed_from_u64(seed); - let sk: bls::SecretKey = rng.gen(); + let sk_set = SecretKeySet::random(); + let sk = sk_set.secret_key(); let pk = sk.public_key(); // Create `Section` with `peers` as its members and set the `ELDER_SIZE` oldest peers as @@ -346,14 +348,15 @@ mod tests { .take(ELDER_SIZE) .copied(), Prefix::default(), + sk_set.public_keys(), ); - let section_auth = proven(&sk, section_auth)?; + let section_auth = proven(sk, section_auth)?; let mut section = Section::new(pk, SectionChain::new(pk), section_auth)?; for peer in &peers { let info = MemberInfo::joined(*peer); - let info = proven(&sk, info)?; + let info = proven(sk, info)?; assert!(section.update_member(info)); } diff --git a/src/routing/bootstrap.rs b/src/routing/bootstrap.rs index 9f8c78c6d7..6a9a4f6b7a 100644 --- a/src/routing/bootstrap.rs +++ b/src/routing/bootstrap.rs @@ -347,7 +347,7 @@ impl<'a> State<'a> { continue; } - if section_auth.prefix.matches(&self.node.name()) { + if section_auth.prefix().matches(&self.node.name()) { info!( "Newer Join response for our prefix {:?} from {:?}", section_auth, sender @@ -358,8 +358,8 @@ impl<'a> State<'a> { relocate_payload: relocate_payload.clone(), resource_proof_response: None, }; - let recipients = section_auth.elders.values().copied().collect(); - self.send_join_requests(join_request, recipients).await?; + self.send_join_requests(join_request, section_auth.addrs()) + .await?; } else { warn!( "Newer Join response not for our prefix {:?} from {:?}", @@ -699,7 +699,7 @@ mod tests { let message = assert_matches!(message, MessageType::NodeMessage(NodeMessage(bytes)) => Message::from_bytes(Bytes::from(bytes))?); - itertools::assert_equal(&recipients, section_auth.elders.values()); + itertools::assert_equal(recipients, section_auth.addrs()); assert_matches!(message.variant(), Variant::JoinRequest(request) => { assert_eq!(request.section_key, pk); assert!(request.relocate_payload.is_none()); diff --git a/src/routing/core/connectivity.rs b/src/routing/core/connectivity.rs index c9625da6f3..c140b15c07 100644 --- a/src/routing/core/connectivity.rs +++ b/src/routing/core/connectivity.rs @@ -12,7 +12,7 @@ use crate::{ error::Result, messages::Variant, routing::command::Command, - section::SectionAuthorityProvider, + section::EldersInfo, Error, }; use bls_dkg::key_gen::message::Message as DkgMessage; @@ -24,11 +24,11 @@ impl Core { pub(crate) fn handle_dkg_start( &mut self, dkg_key: DkgKey, - new_section_auth: SectionAuthorityProvider, + new_elders_info: EldersInfo, ) -> Result> { - trace!("Received DkgStart for {}", new_section_auth); + trace!("Received DkgStart for {:?}", new_elders_info); self.dkg_voter - .start(&self.node.keypair, dkg_key, new_section_auth) + .start(&self.node.keypair, dkg_key, new_elders_info) .into_commands(&self.node) } @@ -69,13 +69,13 @@ impl Core { .peer; let generation = self.section.chain().main_branch_len() as u64; - let section_auth = self + let elders_info = self .section .promote_and_demote_elders(&self.node.name()) .into_iter() - .find(|section_auth| proofs.verify(section_auth, generation)); - let section_auth = if let Some(section_auth) = section_auth { - section_auth + .find(|elders_info| proofs.verify(elders_info, generation)); + let elders_info = if let Some(elders_info) = elders_info { + elders_info } else { trace!("Ignore DKG failure agreement with invalid proofs or outdated participants",); return Ok(vec![]); @@ -84,18 +84,18 @@ impl Core { if proofs.non_participants.is_empty() { // The DKG failure is a corrupted one due to lagging. trace!( - "Received DKG failure agreement - restarting: {}", - section_auth + "Received DKG failure agreement - restarting: {:?}", + elders_info ); - self.send_dkg_start_to(section_auth, slice::from_ref(sender)) + self.send_dkg_start_to(elders_info, slice::from_ref(sender)) } else { // The DKG failure is regarding non_participants, i.e. potential unresponsive node. trace!( "Received DKG failure agreement of non_participants {:?} , DKG generation({}) {:?}", proofs.non_participants, generation, - section_auth + elders_info ); self.cast_offline_proposals(&proofs.non_participants) } diff --git a/src/routing/core/messaging/handling/agreement.rs b/src/routing/core/messaging/handling/agreement.rs index 860b06ad7f..fd38f99107 100644 --- a/src/routing/core/messaging/handling/agreement.rs +++ b/src/routing/core/messaging/handling/agreement.rs @@ -181,15 +181,15 @@ impl Core { ) -> Result> { let mut commands = vec![]; - let equal_or_extension = section_auth.prefix == *self.section.prefix() - || section_auth.prefix.is_extension_of(self.section.prefix()); + let equal_or_extension = section_auth.prefix() == *self.section.prefix() + || section_auth.prefix().is_extension_of(self.section.prefix()); let section_auth = Proven::new(section_auth, proof); if equal_or_extension { // Our section of sub-section let infos = self.section.promote_and_demote_elders(&self.node.name()); - if !infos.contains(§ion_auth.value) { + if !infos.contains(§ion_auth.value.elders_info()) { // SectionInfo out of date, ignore. return Ok(commands); } diff --git a/src/routing/core/messaging/handling/decisions.rs b/src/routing/core/messaging/handling/decisions.rs index 7498975ac7..57509de493 100644 --- a/src/routing/core/messaging/handling/decisions.rs +++ b/src/routing/core/messaging/handling/decisions.rs @@ -47,8 +47,8 @@ impl Core { return Ok(MessageStatus::Useless); } } - Variant::DkgStart { section_auth, .. } => { - if !section_auth.elders.contains_key(&self.node.name()) { + Variant::DkgStart { elders_info, .. } => { + if !elders_info.elders.contains_key(&self.node.name()) { return Ok(MessageStatus::Useless); } } @@ -108,7 +108,7 @@ impl Core { // This `SectionInfo` is proposed by the DKG participants and is signed by the new // key created by the DKG so we don't know it yet. We only require the sender of the // proposal to be one of the DKG participants. - if section_auth.elders.contains_key(sender) { + if section_auth.elders().contains_key(sender) { None } else { Some(MessageStatus::Useless) diff --git a/src/routing/core/messaging/handling/mod.rs b/src/routing/core/messaging/handling/mod.rs index 72db21552f..7e4f065d52 100644 --- a/src/routing/core/messaging/handling/mod.rs +++ b/src/routing/core/messaging/handling/mod.rs @@ -96,7 +96,7 @@ impl Core { (self.section.prefix().matches(&name), self.public_key_set()) { GetSectionResponse::Success(SectionInfo { - prefix: self.section.authority_provider().prefix, + prefix: self.section.authority_provider().prefix(), pk_set, elders: self .section @@ -109,12 +109,11 @@ impl Core { } else { // If we are elder, we should know a section that is closer to `name` that us. // Otherwise redirect to our elders. - let section = self + let section_auth = self .network .closest(&name) .unwrap_or_else(|| self.section.authority_provider()); - let addrs = section.elders.values().copied().collect(); - GetSectionResponse::Redirect(addrs) + GetSectionResponse::Redirect(section_auth.addrs()) }; let response = SectionInfoMsg::GetSectionResponse(response); @@ -291,8 +290,8 @@ impl Core { } Variant::DkgStart { dkg_key, - section_auth, - } => self.handle_dkg_start(*dkg_key, section_auth.clone()), + elders_info, + } => self.handle_dkg_start(*dkg_key, elders_info.clone()), Variant::DkgMessage { dkg_key, message } => { self.handle_dkg_message(*dkg_key, message.clone(), msg.src().name()) } diff --git a/src/routing/core/messaging/handling/relocation.rs b/src/routing/core/messaging/handling/relocation.rs index 5d9bb3ba98..973e44fe2c 100644 --- a/src/routing/core/messaging/handling/relocation.rs +++ b/src/routing/core/messaging/handling/relocation.rs @@ -32,7 +32,7 @@ impl Core { let mut commands = vec![]; // Do not carry out relocation when there is not enough elder nodes. - if self.section.authority_provider().elders.len() < ELDER_SIZE { + if self.section.authority_provider().elders().len() < ELDER_SIZE { return Ok(commands); } @@ -120,13 +120,7 @@ impl Core { let (message_tx, message_rx) = mpsc::channel(1); self.relocate_state = Some(RelocateState::InProgress(message_tx)); - let bootstrap_addrs: Vec<_> = self - .section - .authority_provider() - .elders - .values() - .copied() - .collect(); + let bootstrap_addrs = self.section.authority_provider().addrs(); Ok(Some(Command::Relocate { bootstrap_addrs, diff --git a/src/routing/core/messaging/sending.rs b/src/routing/core/messaging/sending.rs index 8a9c2db051..2558f608a0 100644 --- a/src/routing/core/messaging/sending.rs +++ b/src/routing/core/messaging/sending.rs @@ -15,7 +15,7 @@ use crate::{ peer::Peer, relocation::{RelocateDetails, RelocatePromise, RelocateState}, routing::command::Command, - section::{MemberInfo, Section, SectionAuthorityProvider, SectionChain}, + section::{EldersInfo, MemberInfo, Section, SectionChain}, }; use bytes::Bytes; use sn_messaging::DstLocation; @@ -178,34 +178,31 @@ impl Core { } } - pub(crate) fn send_dkg_start( - &self, - section_auth: SectionAuthorityProvider, - ) -> Result> { + pub(crate) fn send_dkg_start(&self, elders_info: EldersInfo) -> Result> { // Send to all participants. - let recipients: Vec<_> = section_auth.peers().collect(); - self.send_dkg_start_to(section_auth, &recipients) + let recipients: Vec<_> = elders_info.peers().collect(); + self.send_dkg_start_to(elders_info, &recipients) } pub(crate) fn send_dkg_start_to( &self, - section_auth: SectionAuthorityProvider, + elders_info: EldersInfo, recipients: &[Peer], ) -> Result> { - let src_prefix = section_auth.prefix; + let src_prefix = elders_info.prefix; let generation = self.section.chain().main_branch_len() as u64; - let dkg_key = DkgKey::new(§ion_auth, generation); + let dkg_key = DkgKey::new(&elders_info, generation); trace!( - "Send DkgStart for {} with {:?} to {:?}", - section_auth, + "Send DkgStart for {:?} with {:?} to {:?}", + elders_info, dkg_key, recipients ); let variant = Variant::DkgStart { dkg_key, - section_auth, + elders_info, }; self.send_message_for_dst_accumulation( @@ -366,13 +363,7 @@ impl Core { // TODO: consider changing this so it sends only to a subset of the elders // (say 1/3 of the ones closest to our name or so) pub(crate) fn send_message_to_our_elders(&self, msg: Bytes) -> Command { - let targets: Vec<_> = self - .section - .authority_provider() - .elders - .values() - .copied() - .collect(); + let targets = self.section.authority_provider().addrs(); Command::send_message_to_nodes(&targets, targets.len(), msg) } } diff --git a/src/routing/core/mod.rs b/src/routing/core/mod.rs index d306a7846c..c3543afcd3 100644 --- a/src/routing/core/mod.rs +++ b/src/routing/core/mod.rs @@ -117,7 +117,7 @@ impl Core { elders: self .section() .authority_provider() - .elders + .elders() .keys() .copied() .collect(), @@ -160,22 +160,10 @@ impl Core { commands.extend(self.send_sync(self.section.clone(), self.network.clone())?); } - let self_status_change = if !old.is_elder && new.is_elder { - info!("Promoted to elder"); - NodeElderChange::Promoted - } else if old.is_elder && !new.is_elder { - info!("Demoted"); - self.network = Network::new(); - self.section_keys_provider = SectionKeysProvider::new(KEY_CACHE_SIZE, None); - NodeElderChange::Demoted - } else { - NodeElderChange::None - }; - let current: BTreeSet<_> = self .section .authority_provider() - .elders + .elders() .keys() .copied() .collect(); @@ -191,24 +179,32 @@ impl Core { removed, }; + let self_status_change = if !old.is_elder && new.is_elder { + info!("Promoted to elder"); + NodeElderChange::Promoted + } else if old.is_elder && !new.is_elder { + info!("Demoted"); + self.network = Network::new(); + self.section_keys_provider = SectionKeysProvider::new(KEY_CACHE_SIZE, None); + NodeElderChange::Demoted + } else { + NodeElderChange::None + }; + let sibling_elders = if new.prefix != old.prefix { - if let Some(sibling_key) = self.section_key(&new.prefix.sibling()) { - self.network.get(&new.prefix.sibling()).map(|info| { - let current: BTreeSet<_> = info.elders.keys().copied().collect(); - let added = current.difference(&old.elders).copied().collect(); - let removed = old.elders.difference(¤t).copied().collect(); - let remaining = old.elders.intersection(¤t).copied().collect(); - Elders { - prefix: new.prefix.sibling(), - key: *sibling_key, - remaining, - added, - removed, - } - }) - } else { - None - } + self.network.get(&new.prefix.sibling()).map(|sec_auth| { + let current: BTreeSet<_> = sec_auth.elders().keys().copied().collect(); + let added = current.difference(&old.elders).copied().collect(); + let removed = old.elders.difference(¤t).copied().collect(); + let remaining = old.elders.intersection(¤t).copied().collect(); + Elders { + prefix: new.prefix.sibling(), + key: sec_auth.section_key(), + remaining, + added, + removed, + } + }) } else { None }; diff --git a/src/routing/mod.rs b/src/routing/mod.rs index be3410d283..2991cce3e7 100644 --- a/src/routing/mod.rs +++ b/src/routing/mod.rs @@ -18,7 +18,7 @@ mod event_stream; mod lazy_messaging; mod split_barrier; #[cfg(test)] -mod tests; +pub(crate) mod tests; pub use self::event_stream::EventStream; use self::{ @@ -120,7 +120,7 @@ impl Routing { remaining: BTreeSet::new(), added: section .authority_provider() - .elders + .elders() .keys() .copied() .collect(), diff --git a/src/routing/tests/mod.rs b/src/routing/tests/mod.rs index 9f5208782c..2fca70467b 100644 --- a/src/routing/tests/mod.rs +++ b/src/routing/tests/mod.rs @@ -92,7 +92,7 @@ async fn receive_mismatching_get_section_request_as_adult() -> Result<()> { let sk_set = SecretKeySet::random(); let (section_auth, _) = gen_section_authority_provider(good_prefix, ELDER_SIZE); - let elders_addrs: Vec<_> = section_auth.elders.values().copied().collect(); + let elders_addrs = section_auth.addrs(); let (section, _) = create_section(&sk_set, §ion_auth)?; let node = create_node(MIN_ADULT_AGE); @@ -459,8 +459,11 @@ async fn handle_agreement_on_online_of_elder_candidate() -> Result<()> { // Creates nodes where everybody has age 6 except one has 5. let mut nodes: Vec<_> = gen_sorted_nodes(&Prefix::default(), ELDER_SIZE, true); - let section_auth = - SectionAuthorityProvider::new(nodes.iter().map(Node::peer), Prefix::default()); + let section_auth = SectionAuthorityProvider::new( + nodes.iter().map(Node::peer), + Prefix::default(), + sk_set.public_keys(), + ); let proven_section_auth = proven(sk_set.secret_key(), section_auth.clone())?; let mut section = Section::new(*chain.root_key(), chain, proven_section_auth)?; @@ -520,11 +523,11 @@ async fn handle_agreement_on_online_of_elder_candidate() -> Result<()> { _ => continue, }; - let actual_section_auth = match message.variant() { - Variant::DkgStart { section_auth, .. } => section_auth, + let actual_elders_info = match message.variant() { + Variant::DkgStart { elders_info, .. } => elders_info, _ => continue, }; - itertools::assert_equal(actual_section_auth.peers(), expected_new_elders.clone()); + itertools::assert_equal(actual_elders_info.peers(), expected_new_elders.clone()); let expected_dkg_start_recipients: Vec<_> = expected_new_elders .iter() @@ -762,8 +765,8 @@ async fn handle_agreement_on_offline_of_elder() -> Result<()> { _ => continue, }; - let actual_section_auth = match message.variant() { - Variant::DkgStart { section_auth, .. } => section_auth, + let actual_elders_info = match message.variant() { + Variant::DkgStart { elders_info, .. } => elders_info, _ => continue, }; @@ -772,7 +775,7 @@ async fn handle_agreement_on_offline_of_elder() -> Result<()> { .filter(|peer| *peer != remove_peer) .chain(iter::once(existing_peer)) .collect(); - itertools::assert_equal(actual_section_auth.peers(), expected_new_elders.clone()); + itertools::assert_equal(actual_elders_info.peers(), expected_new_elders.clone()); let expected_dkg_start_recipients: Vec<_> = expected_new_elders .iter() @@ -798,7 +801,7 @@ async fn handle_agreement_on_offline_of_elder() -> Result<()> { .await .section() .authority_provider() - .elders + .elders() .contains_key(remove_peer.name())); Ok(()) @@ -830,17 +833,13 @@ async fn handle_untrusted_message(source: UntrustedMessageSource) -> Result<()> UntrustedMessageSource::Peer => { // When the untrusted message is sent from a single peer, we should bounce it back to // that peer. - let sender = *section_auth - .elders - .values() - .next() - .expect("section_auth is empty"); + let sender = *section_auth.addrs().get(0).expect("section_auth is empty"); (Some(sender), vec![sender]) } UntrustedMessageSource::Accumulation => { // When the untrusted message is the result of message accumulation, we should bounce // it to our elders. - (None, section_auth.elders.values().copied().collect()) + (None, section_auth.addrs()) } }; @@ -1033,7 +1032,8 @@ async fn handle_sync() -> Result<()> { let dispatcher = Dispatcher::new(state, create_comm().await?); // Create new `Section` as a successor to the previous one. - let sk2 = bls::SecretKey::random(); + let sk2_set = SecretKeySet::random(); + let sk2 = sk2_set.secret_key(); let pk2 = sk2.public_key(); let pk2_signature = sk1_set.secret_key().sign(bincode::serialize(&pk2)?); chain.insert(&pk1, pk2, pk2_signature)?; @@ -1045,12 +1045,13 @@ async fn handle_sync() -> Result<()> { let new_section_auth = SectionAuthorityProvider::new( old_section_auth .peers() - .take(old_section_auth.elders.len() - 1) + .take(old_section_auth.elders().len() - 1) .chain(iter::once(new_peer)), old_section_auth.prefix, + sk2_set.public_keys(), ); - let new_section_elders: BTreeSet<_> = new_section_auth.elders.keys().copied().collect(); - let proven_new_section_auth = proven(&sk2, new_section_auth)?; + let new_section_elders: BTreeSet<_> = new_section_auth.elders().keys().copied().collect(); + let proven_new_section_auth = proven(sk2, new_section_auth)?; let new_section = Section::new(pk0, chain, proven_new_section_auth)?; // Create the `Sync` message containing the new `Section`. @@ -1410,6 +1411,7 @@ async fn handle_elders_update() -> Result<()> { let section_auth0 = SectionAuthorityProvider::new( iter::once(node.peer()).chain(other_elder_peers.clone()), Prefix::default(), + sk_set0.public_keys(), ); let (mut section0, section_key_share) = create_section(&sk_set0, §ion_auth0)?; @@ -1422,6 +1424,8 @@ async fn handle_elders_update() -> Result<()> { let demoted_peer = other_elder_peers.remove(0); + let sk_set1 = SecretKeySet::random(); + let pk1 = sk_set1.secret_key().public_key(); // Create `HandleAgreement` command for an `OurElders` proposal. This will demote one of the // current elders and promote the oldest peer. let section_auth1 = SectionAuthorityProvider::new( @@ -1429,11 +1433,9 @@ async fn handle_elders_update() -> Result<()> { .chain(other_elder_peers.clone()) .chain(iter::once(promoted_peer)), Prefix::default(), + sk_set1.public_keys(), ); - let elder_names1: BTreeSet<_> = section_auth1.elders.keys().copied().collect(); - - let sk_set1 = SecretKeySet::random(); - let pk1 = sk_set1.secret_key().public_key(); + let elder_names1: BTreeSet<_> = section_auth1.elders().keys().copied().collect(); let proven_section_auth1 = proven(sk_set1.secret_key(), section_auth1)?; let proposal = Proposal::OurElders(proven_section_auth1); @@ -1529,6 +1531,7 @@ async fn handle_demote_during_split() -> Result<()> { let section_auth_v0 = SectionAuthorityProvider::new( iter::once(node.peer()).chain(peers_a.iter().copied()), Prefix::default(), + sk_set_v0.public_keys(), ); let (mut section, section_key_share) = create_section(&sk_set_v0, §ion_auth_v0)?; @@ -1562,14 +1565,18 @@ async fn handle_demote_during_split() -> Result<()> { }; // Handle agreement on `OurElders` for prefix-0. - let section_auth = - SectionAuthorityProvider::new(peers_a.iter().copied().chain(iter::once(peer_c)), prefix0); + let section_auth = SectionAuthorityProvider::new( + peers_a.iter().copied().chain(iter::once(peer_c)), + prefix0, + sk_set_v1_p0.public_keys(), + ); let command = create_our_elders_command(sk_set_v1_p0.secret_key(), section_auth)?; let commands = dispatcher.handle_command(command).await?; assert_matches!(&commands[..], &[]); // Handle agreement on `OurElders` for prefix-1. - let section_auth = SectionAuthorityProvider::new(peers_b.iter().copied(), prefix1); + let section_auth = + SectionAuthorityProvider::new(peers_b.iter().copied(), prefix1, sk_set_v1_p1.public_keys()); let command = create_our_elders_command(sk_set_v1_p1.secret_key(), section_auth)?; let commands = dispatcher.handle_command(command).await?; diff --git a/src/section/mod.rs b/src/section/mod.rs index 8e5c7ef402..360e9086d4 100644 --- a/src/section/mod.rs +++ b/src/section/mod.rs @@ -19,7 +19,7 @@ pub use self::{ member_info::{ MemberInfo, PeerState, FIRST_SECTION_MAX_AGE, FIRST_SECTION_MIN_AGE, MIN_ADULT_AGE, MIN_AGE, }, - section_authority_provider::SectionAuthorityProvider, + section_authority_provider::{EldersInfo, SectionAuthorityProvider}, section_chain::{Error as SectionChainError, SectionChain}, section_keys::{SectionKeyShare, SectionKeysProvider}, }; @@ -128,7 +128,7 @@ impl Section { } self.members - .prune_not_matching(&self.section_auth.value.prefix); + .prune_not_matching(&self.section_auth.value.prefix()); Ok(()) } @@ -139,8 +139,11 @@ impl Section { new_section_auth: Proven, new_key_proof: Proof, ) -> bool { - if new_section_auth.value.prefix != *self.prefix() - && !new_section_auth.value.prefix.is_extension_of(self.prefix()) + if new_section_auth.value.prefix() != *self.prefix() + && !new_section_auth + .value + .prefix() + .is_extension_of(self.prefix()) { return false; } @@ -166,7 +169,7 @@ impl Section { } self.members - .prune_not_matching(&self.section_auth.value.prefix); + .prune_not_matching(&self.section_auth.value.prefix()); true } @@ -218,19 +221,20 @@ impl Section { } pub fn is_elder(&self, name: &XorName) -> bool { - self.authority_provider().elders.contains_key(name) + self.authority_provider().elders().contains_key(name) } /// Generate a new section info(s) based on the current set of members. /// Returns a set of candidate SectionAuthorityProviders. - pub fn promote_and_demote_elders(&self, our_name: &XorName) -> Vec { + pub fn promote_and_demote_elders(&self, our_name: &XorName) -> Vec { if let Some((our_info, other_info)) = self.try_split(our_name) { return vec![our_info, other_info]; } let expected_peers = self.elder_candidates(ELDER_SIZE); - let expected_names: BTreeSet<_> = expected_peers.iter().map(Peer::name).collect(); - let current_names: BTreeSet<_> = self.authority_provider().elders.keys().collect(); + let expected_names: BTreeSet<_> = expected_peers.iter().map(Peer::name).cloned().collect(); + let current_names: BTreeSet<_> = + self.authority_provider().elders().keys().cloned().collect(); if expected_names == current_names { vec![] @@ -238,8 +242,7 @@ impl Section { warn!("ignore attempt to reduce the number of elders too much"); vec![] } else { - let new_info = - SectionAuthorityProvider::new(expected_peers, self.authority_provider().prefix); + let new_info = EldersInfo::new(expected_peers, self.authority_provider().prefix()); vec![new_info] } } @@ -291,10 +294,7 @@ impl Section { // Tries to split our section. // If we have enough mature nodes for both subsections, returns the SectionAuthorityProviders // of the two subsections. Otherwise returns `None`. - fn try_split( - &self, - our_name: &XorName, - ) -> Option<(SectionAuthorityProvider, SectionAuthorityProvider)> { + fn try_split(&self, our_name: &XorName) -> Option<(EldersInfo, EldersInfo)> { let next_bit_index = if let Ok(index) = self.prefix().bit_count().try_into() { index } else { @@ -335,8 +335,8 @@ impl Section { self.authority_provider(), ); - let our_info = SectionAuthorityProvider::new(our_elders, our_prefix); - let other_info = SectionAuthorityProvider::new(other_elders, other_prefix); + let our_info = EldersInfo::new(our_elders, our_prefix); + let other_info = EldersInfo::new(other_elders, other_prefix); Some((our_info, other_info)) } @@ -356,7 +356,8 @@ fn create_first_section_authority_provider( mut peer: Peer, ) -> Result> { peer.set_reachable(true); - let section_auth = SectionAuthorityProvider::new(iter::once(peer), Prefix::default()); + let section_auth = + SectionAuthorityProvider::new(iter::once(peer), Prefix::default(), pk_set.clone()); let proof = create_first_proof(pk_set, sk_share, §ion_auth)?; Ok(Proven::new(section_auth, proof)) } diff --git a/src/section/section_authority_provider.rs b/src/section/section_authority_provider.rs index 6af9cdb2ae..bbd4509412 100644 --- a/src/section/section_authority_provider.rs +++ b/src/section/section_authority_provider.rs @@ -7,8 +7,10 @@ // permissions and limitations relating to use of the SAFE Network Software. use crate::{peer::Peer, Prefix, XorName}; +use bls::{PublicKey, PublicKeyShare}; use itertools::Itertools; use serde::{Deserialize, Serialize}; +use sn_data_types::ReplicaPublicKeySet; use std::{ borrow::Borrow, collections::BTreeMap, @@ -16,20 +18,18 @@ use std::{ net::SocketAddr, }; -/// The information about all elders of a section at one point in time. Each elder is always a -/// member of exactly one current section, but a new `SectionAuthorityProvider` is created whenever the elders -/// change, due to an elder being added or removed, or the section splitting or merging. -#[derive(Default, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Serialize, Deserialize)] -pub struct SectionAuthorityProvider { +/// The information about all elders of a section at one point in time. +#[derive(Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Serialize, Deserialize)] +pub struct EldersInfo { /// The section's complete set of elders as a map from their name to their socket address. pub elders: BTreeMap, /// The section prefix. It matches all the members' names. pub prefix: Prefix, } -impl SectionAuthorityProvider { - /// Creates a new `SectionAuthorityProvider` with the given members, prefix and version. - pub fn new(elders: I, prefix: Prefix) -> Self +impl EldersInfo { + /// Creates a new `EldersInfo` with the given members and prefix. + pub(crate) fn new(elders: I, prefix: Prefix) -> Self where I: IntoIterator, { @@ -63,6 +63,94 @@ impl SectionAuthorityProvider { } } +/// A new `SectionAuthorityProvider` is created whenever the elders change, +/// due to an elder being added or removed, or the section splitting or merging. +#[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Serialize, Deserialize)] +pub struct SectionAuthorityProvider { + /// The section prefix. It matches all the members' names. + pub prefix: Prefix, + /// Public key of the section. + section_key: PublicKey, + // The section's complete set of elders as a map from their name to their socket address. + elders: BTreeMap, +} + +impl SectionAuthorityProvider { + /// Creates a new `SectionAuthorityProvider` with the given members, prefix and public keyset. + pub fn new(elders: I, prefix: Prefix, pk_set: ReplicaPublicKeySet) -> Self + where + I: IntoIterator, + { + let elders = elders + .into_iter() + .enumerate() + .map(|(index, peer)| (*peer.name(), (pk_set.public_key_share(index), *peer.addr()))) + .collect(); + Self { + prefix, + section_key: pk_set.public_key(), + elders, + } + } + + /// Creates a new `SectionAuthorityProvider` from EldersInfo and public keyset. + pub fn from_elders_info(elders_info: EldersInfo, pk_set: ReplicaPublicKeySet) -> Self { + let elders = elders_info + .elders + .iter() + .enumerate() + .map(|(index, (name, addr))| (*name, (pk_set.public_key_share(index), *addr))) + .collect(); + Self { + prefix: elders_info.prefix, + section_key: pk_set.public_key(), + elders, + } + } + + /// Returns `EldersInfo`, which doesn't have key related infos. + pub fn elders_info(&self) -> EldersInfo { + EldersInfo { + elders: self.elders(), + prefix: self.prefix, + } + } + + pub(crate) fn peers( + &'_ self, + ) -> impl Iterator + DoubleEndedIterator + ExactSizeIterator + Clone + '_ { + // The `reachable` flag of Peer is defaulted to `false` during the construction. + // As the SectionAuthorityProvider only holds the list of alive elders, it shall be safe + // to set the flag as true here during the mapping. + self.elders.iter().map(|(name, (_, addr))| { + let mut peer = Peer::new(*name, *addr); + peer.set_reachable(true); + peer + }) + } + + /// Returns a map of name to socket_addr. + pub fn elders(&self) -> BTreeMap { + self.elders + .iter() + .map(|(name, (_, addr))| (*name, *addr)) + .collect() + } + + pub(crate) fn addrs(&self) -> Vec { + self.elders.values().map(|(_, addr)| *addr).collect() + } + + pub(crate) fn prefix(&self) -> Prefix { + self.prefix + } + + /// Key of the section. + pub fn section_key(&self) -> PublicKey { + self.section_key + } +} + impl Borrow for SectionAuthorityProvider { fn borrow(&self) -> &Prefix { &self.prefix @@ -73,9 +161,10 @@ impl Debug for SectionAuthorityProvider { fn fmt(&self, formatter: &mut Formatter) -> fmt::Result { write!( formatter, - "SectionAuthorityProvider {{ prefix: ({:b}), elders: {{{:?}}} }}", + "SectionAuthorityProvider {{ prefix: ({:b}), section_key: {:?}, elders: {{{:?}}} }}", self.prefix, - self.elders.values().format(", "), + self.section_key, + self.elders.iter().format(", "), ) } } @@ -93,8 +182,8 @@ impl Display for SectionAuthorityProvider { #[cfg(test)] pub(crate) mod test_utils { - use super::SectionAuthorityProvider; - use crate::{crypto, node::Node, MIN_ADULT_AGE, MIN_AGE}; + use super::*; + use crate::{crypto, node::Node, supermajority, MIN_ADULT_AGE, MIN_AGE}; use itertools::Itertools; use std::{cell::Cell, net::SocketAddr}; use xor_name::Prefix; @@ -145,7 +234,13 @@ pub(crate) mod test_utils { (*peer.name(), *peer.addr()) }) .collect(); - let section_auth = SectionAuthorityProvider { elders, prefix }; + + let threshold = supermajority(count) - 1; + let secret_key_set = bls::SecretKeySet::random(threshold, &mut rand::thread_rng()); + let section_auth = SectionAuthorityProvider::from_elders_info( + EldersInfo { elders, prefix }, + secret_key_set.public_keys(), + ); (section_auth, nodes) } diff --git a/src/section/section_peers.rs b/src/section/section_peers.rs index 4a40689bc9..da1f3d4ffa 100644 --- a/src/section/section_peers.rs +++ b/src/section/section_peers.rs @@ -242,5 +242,5 @@ fn is_active(info: &MemberInfo, current_elders: &SectionAuthorityProvider) -> bo } fn is_elder(info: &MemberInfo, current_elders: &SectionAuthorityProvider) -> bool { - current_elders.elders.contains_key(info.peer.name()) + current_elders.elders().contains_key(info.peer.name()) } diff --git a/tests/utils/mod.rs b/tests/utils/mod.rs index 77ec7b8d0d..73716aedb5 100644 --- a/tests/utils/mod.rs +++ b/tests/utils/mod.rs @@ -134,7 +134,8 @@ pub async fn verify_invariants_for_node(node: &Routing, elder_size: usize) -> Re assert!(node.matches_our_prefix(&our_name).await); let our_prefix = node.our_prefix().await; - let our_section_elders: BTreeSet<_> = node.our_section().await.elders.keys().copied().collect(); + let our_section_elders: BTreeSet<_> = + node.our_section().await.elders().keys().copied().collect(); if !our_prefix.is_empty() { assert!( @@ -181,21 +182,21 @@ pub async fn verify_invariants_for_node(node: &Routing, elder_size: usize) -> Re if let Some(info) = other_sections .iter() - .find(|info| info.elders.len() < elder_size) + .find(|info| info.elders().len() < elder_size) { bail!( "{}({:b}) An other section {:?} is below the minimum size ({}/{}) (other_sections: {:?})", our_name, our_prefix, info.prefix, - info.elders.len(), + info.elders().len(), elder_size, other_sections, ); } for info in &other_sections { - if let Some(name) = info.elders.keys().find(|name| !info.prefix.matches(name)) { + if let Some(name) = info.elders().keys().find(|name| !info.prefix.matches(name)) { bail!( "{}({:b}) A name in a section doesn't match its prefix: {:?}, {:?}", our_name,