use crate::node::{dkg::SigShare, Result};
use sn_interface::messaging::system::{Proposal as ProposalMsg, SectionAuth};
use sn_interface::network_knowledge::{NodeState, SectionAuthorityProvider};
#[allow(clippy::large_enum_variant)]
#[derive(Clone, Debug, PartialEq)]
pub(crate) enum Proposal {
Offline(NodeState),
SectionInfo(SectionAuthorityProvider),
NewElders(SectionAuth<SectionAuthorityProvider>),
JoinsAllowed(bool),
}
impl Proposal {
pub(crate) fn sign_with_key_share(
&self,
public_key_set: bls::PublicKeySet,
index: usize,
secret_key_share: &bls::SecretKeyShare,
) -> Result<SigShare> {
Ok(SigShare::new(
public_key_set,
index,
secret_key_share,
&self.as_signable_bytes()?,
))
}
pub(crate) fn as_signable_bytes(&self) -> Result<Vec<u8>> {
Ok(match self {
Self::Offline(node_state) => bincode::serialize(node_state),
Self::SectionInfo(info) => bincode::serialize(info),
Self::NewElders(info) => bincode::serialize(&info.sig.public_key),
Self::JoinsAllowed(joins_allowed) => bincode::serialize(&joins_allowed),
}?)
}
pub(crate) fn into_msg(self) -> ProposalMsg {
match self {
Self::Offline(node_state) => ProposalMsg::Offline(node_state.to_msg()),
Self::SectionInfo(sap) => ProposalMsg::SectionInfo(sap.to_msg()),
Self::NewElders(sap) => ProposalMsg::NewElders(sap.into_authed_msg()),
Self::JoinsAllowed(allowed) => ProposalMsg::JoinsAllowed(allowed),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use eyre::Result;
use serde::Serialize;
use std::fmt::Debug;
use xor_name::Prefix;
#[cfg(feature = "test-utils")]
use sn_interface::network_knowledge::test_utils::gen_section_authority_provider;
#[test]
fn serialize_for_signing() -> Result<()> {
let (section_auth, _, _) = gen_section_authority_provider(Prefix::default(), 4);
let proposal = Proposal::SectionInfo(section_auth.clone());
verify_serialize_for_signing(&proposal, §ion_auth)?;
let new_sk = bls::SecretKey::random();
let new_pk = new_sk.public_key();
let section_signed_auth =
sn_interface::network_knowledge::test_utils::section_signed(&new_sk, section_auth)?;
let proposal = Proposal::NewElders(section_signed_auth);
verify_serialize_for_signing(&proposal, &new_pk)?;
Ok(())
}
fn verify_serialize_for_signing<T>(proposal: &Proposal, should_serialize_as: &T) -> Result<()>
where
T: Serialize + Debug,
{
let actual = proposal.as_signable_bytes()?;
let expected = bincode::serialize(should_serialize_as)?;
assert_eq!(
actual, expected,
"expected SignableView({:?}) to serialize same as {:?}, but didn't",
proposal, should_serialize_as
);
Ok(())
}
}