use crate::{
dkg::session::{Backlog, Session},
ed25519::{self, Keypair},
section::{ElderCandidatesUtils, SectionAuthorityProviderUtils, SectionKeyShare},
supermajority,
};
use bls_dkg::key_gen::{message::Message as DkgMessage, KeyGen};
use sn_messaging::{
node::{DkgFailureSigned, DkgFailureSignedSet, DkgKey, ElderCandidates},
SectionAuthorityProvider,
};
use std::collections::{BTreeSet, HashMap};
use xor_name::XorName;
use super::commands::DkgCommand;
pub(crate) struct DkgVoter {
sessions: HashMap<DkgKey, Session>,
backlog: Backlog,
}
impl Default for DkgVoter {
fn default() -> Self {
Self {
sessions: HashMap::default(),
backlog: Backlog::new(),
}
}
}
impl DkgVoter {
pub fn start(
&mut self,
keypair: &Keypair,
dkg_key: DkgKey,
elder_candidates: ElderCandidates,
) -> Vec<DkgCommand> {
if self.sessions.contains_key(&dkg_key) {
trace!("DKG for {:?} already in progress", elder_candidates);
return vec![];
}
let name = ed25519::name(&keypair.public);
let participant_index = if let Some(index) = elder_candidates.position(&name) {
index
} else {
error!(
"DKG for {:?} failed to start: {} is not a participant",
elder_candidates, name
);
return vec![];
};
if elder_candidates.elders.len() == 1 {
let secret_key_set = bls::SecretKeySet::random(0, &mut rand::thread_rng());
let section_auth = SectionAuthorityProvider::from_elder_candidates(
elder_candidates,
secret_key_set.public_keys(),
);
return vec![DkgCommand::HandleOutcome {
section_auth,
outcome: SectionKeyShare {
public_key_set: secret_key_set.public_keys(),
index: participant_index,
secret_key_share: secret_key_set.secret_key_share(0),
},
}];
}
let threshold = supermajority(elder_candidates.elders.len()) - 1;
let participants = elder_candidates.elders.keys().copied().collect();
match KeyGen::initialize(name, threshold, participants) {
Ok((key_gen, message)) => {
trace!("DKG for {:?} starting", elder_candidates);
let mut session = Session {
key_gen,
elder_candidates,
participant_index,
timer_token: 0,
failures: DkgFailureSignedSet::default(),
complete: false,
};
let mut commands = vec![];
commands.extend(session.broadcast(&dkg_key, keypair, message));
commands.extend(
self.backlog
.take(&dkg_key)
.into_iter()
.flat_map(|message| session.process_message(&dkg_key, keypair, message)),
);
let _ = self.sessions.insert(dkg_key, session);
self.sessions.retain(|existing_dkg_key, _| {
existing_dkg_key.generation >= dkg_key.generation
});
self.backlog.prune(&dkg_key);
commands
}
Err(error) => {
error!("DKG for {:?} failed to start: {}", elder_candidates, error);
vec![]
}
}
}
pub fn handle_timeout(&mut self, keypair: &Keypair, timer_token: u64) -> Vec<DkgCommand> {
if let Some((dkg_key, session)) = self
.sessions
.iter_mut()
.find(|(_, session)| session.timer_token() == timer_token)
{
session.handle_timeout(dkg_key, keypair)
} else {
vec![]
}
}
pub fn process_message(
&mut self,
keypair: &Keypair,
dkg_key: &DkgKey,
message: DkgMessage,
) -> Vec<DkgCommand> {
if let Some(session) = self.sessions.get_mut(dkg_key) {
session.process_message(dkg_key, keypair, message)
} else {
self.backlog.push(*dkg_key, message);
vec![]
}
}
pub fn process_failure(
&mut self,
dkg_key: &DkgKey,
non_participants: &BTreeSet<XorName>,
signed: DkgFailureSigned,
) -> Option<DkgCommand> {
self.sessions
.get_mut(dkg_key)?
.process_failure(dkg_key, non_participants, signed)
}
}