mod stats;
use self::stats::NetworkStats;
use crate::messaging::system::SectionAuth;
use crate::routing::{Error, Result, SectionAuthUtils, SectionAuthorityProvider};
use bls::PublicKey as BlsPublicKey;
use dashmap::{self, mapref::multiple::RefMulti, DashMap};
use secured_linked_list::SecuredLinkedList;
use serde::{Deserialize, Serialize};
use std::iter::{self, Iterator};
use std::sync::Arc;
use xor_name::{Prefix, XorName};
#[derive(Debug, Clone, Serialize)]
pub(crate) struct NetworkPrefixMap {
sections: Arc<DashMap<Prefix, SectionAuth<SectionAuthorityProvider>>>,
genesis_pk: BlsPublicKey,
}
impl NetworkPrefixMap {
pub(crate) fn new(genesis_pk: BlsPublicKey) -> Self {
Self {
sections: Arc::new(DashMap::new()),
genesis_pk,
}
}
pub(crate) fn genesis_key(&self) -> BlsPublicKey {
self.genesis_pk
}
fn insert(&self, sap: SectionAuth<SectionAuthorityProvider>) -> bool {
let prefix = sap.prefix();
if self.descendants(&prefix).next().is_some() {
return false;
}
let _prev = self.sections.insert(prefix, sap);
let parent_prefix = prefix.popped();
self.prune(parent_prefix);
true
}
fn closest(
&self,
name: &XorName,
exclude: Option<&Prefix>,
) -> Option<SectionAuth<SectionAuthorityProvider>> {
self.sections
.iter()
.filter(|e| {
if let Some(prefix) = exclude {
e.key() != prefix
} else {
true
}
})
.min_by(|lhs, rhs| lhs.key().cmp_distance(rhs.key(), name))
.map(|e| e.value().clone())
}
pub(crate) fn closest_or_opposite(
&self,
name: &XorName,
exclude: Option<&Prefix>,
) -> Option<SectionAuth<SectionAuthorityProvider>> {
self.closest(name, exclude).or_else(|| {
self.sections
.iter()
.filter(|e| e.key().matches(&name.with_bit(0, !name.bit(0))))
.max_by_key(|e| e.key().bit_count())
.map(|entry| entry.value().clone())
})
}
pub(crate) fn all(&self) -> Vec<SectionAuthorityProvider> {
self.sections
.iter()
.map(|e| e.value().value.clone())
.collect()
}
#[allow(unused)]
pub(crate) fn get(&self, prefix: &Prefix) -> Option<SectionAuthorityProvider> {
self.sections
.get(prefix)
.map(|entry| entry.value().value.clone())
}
pub(crate) fn get_signed(
&self,
prefix: &Prefix,
) -> Option<SectionAuth<SectionAuthorityProvider>> {
self.sections.get(prefix).map(|entry| entry.value().clone())
}
pub(crate) fn update(
&self,
signed_sap: SectionAuth<SectionAuthorityProvider>,
proof_chain: &SecuredLinkedList,
) -> Result<bool> {
let prefix = signed_sap.prefix();
trace!("Attempting to update prefixmap for {:?}", prefix);
let section_key = match self.section_by_prefix(&prefix) {
Ok(sap) => sap.section_key(),
Err(_) => {
trace!("No key found for prefix: {:?}", prefix);
self.genesis_pk
}
};
let res = self.verify_with_chain_and_update(
signed_sap,
proof_chain,
&SecuredLinkedList::new(section_key),
);
for section in self.sections.iter() {
let prefix = section.key();
trace!("Known prefix after update: {:?}", prefix);
}
res
}
pub(crate) fn verify_with_chain_and_update(
&self,
signed_sap: SectionAuth<SectionAuthorityProvider>,
proof_chain: &SecuredLinkedList,
section_chain: &SecuredLinkedList,
) -> Result<bool> {
if !signed_sap.self_verify() {
return Err(Error::UntrustedSectionAuthProvider(format!(
"invalid signature: {:?}",
signed_sap.value
)));
}
if signed_sap.sig.public_key != signed_sap.section_key() {
return Err(Error::UntrustedSectionAuthProvider(format!(
"section key doesn't match signature's key: {:?}",
signed_sap.value
)));
}
match self.sections.get(&signed_sap.prefix()) {
Some(entry) if entry.value() == &signed_sap => {
return Ok(false);
}
Some(entry) => {
if !proof_chain.has_key(&entry.value().section_key()) {
return Err(Error::UntrustedProofChain(format!(
"provided proof_chain doesn't cover the SAP's key we currently know: {:?}",
entry.value().value
)));
}
}
None => {
if !proof_chain.check_trust(section_chain.keys()) {
return Err(Error::UntrustedProofChain(format!(
"none of the keys were found on our section chain: {:?}",
signed_sap.value
)));
}
}
}
if !proof_chain.self_verify() {
return Err(Error::UntrustedProofChain(format!(
"invalid proof chain: {:?}",
proof_chain
)));
}
if proof_chain.last_key() != &signed_sap.section_key() {
return Err(Error::UntrustedSectionAuthProvider(format!(
"section key ({:?}, from prefix {:?}) isn't in the last key in the proof chain provided. (Which ends with ({:?}))",
signed_sap.section_key(),
signed_sap.prefix(),
proof_chain.last_key()
)));
}
let changed = self.insert(signed_sap);
for section in self.sections.iter() {
let prefix = section.key();
trace!("Known prefix: {:?}", prefix);
}
Ok(changed)
}
pub(crate) fn section_keys(&self) -> Vec<bls::PublicKey> {
self.sections
.iter()
.map(|e| e.value().section_key())
.collect()
}
pub(crate) fn section_by_name(&self, name: &XorName) -> Result<SectionAuthorityProvider> {
self.sections
.iter()
.filter(|e| e.key().matches(name))
.max_by_key(|e| e.key().bit_count())
.ok_or(Error::NoMatchingSection)
.map(|entry| entry.value().value.clone())
}
pub(crate) fn section_by_prefix(&self, prefix: &Prefix) -> Result<SectionAuthorityProvider> {
self.section_by_name(&prefix.name())
}
pub(crate) fn known_sections_count(&self) -> usize {
self.sections.len()
}
pub(crate) fn network_stats(&self, our: &SectionAuthorityProvider) -> NetworkStats {
let section_prefixes = self.sections.iter().map(|e| *e.key());
let known_prefixes: Vec<_> = section_prefixes.chain(iter::once(our.prefix())).collect();
let total_elders_exact = Prefix::default().is_covered_by(&known_prefixes);
let network_fraction: f64 = known_prefixes
.iter()
.map(|p| 1.0 / (p.bit_count() as f64).exp2())
.sum();
let network_elders_count: usize =
self.sections.iter().map(|e| e.value().elder_count()).sum();
let total = network_elders_count as f64 / network_fraction;
NetworkStats {
known_elders: network_elders_count as u64,
total_elders: total.ceil() as u64,
total_elders_exact,
}
}
fn descendants<'a>(
&'a self,
prefix: &'a Prefix,
) -> impl Iterator<Item = RefMulti<'a, Prefix, SectionAuth<SectionAuthorityProvider>>> + 'a
{
self.sections
.iter()
.filter(move |e| e.key().is_extension_of(prefix))
}
fn prune(&self, mut prefix: Prefix) {
loop {
let is_covered = {
let descendants: Vec<_> = self.descendants(&prefix).collect();
let descendant_prefixes: Vec<&Prefix> =
descendants.iter().map(|item| item.key()).collect();
prefix.is_covered_by(descendant_prefixes)
};
if is_covered {
let _prev = self.sections.remove(&prefix);
}
if prefix.is_empty() {
break;
} else {
prefix = prefix.popped();
}
}
}
}
impl<'de> Deserialize<'de> for NetworkPrefixMap {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
#[derive(Deserialize)]
struct NetworkPrefixMap {
sections: DashMap<Prefix, SectionAuth<crate::messaging::SectionAuthorityProvider>>,
genesis_pk: BlsPublicKey,
}
let helper = NetworkPrefixMap::deserialize(deserializer)?;
let sections = helper
.sections
.into_iter()
.map(|(k, v)| (k, v.into_authed_state()))
.collect();
Ok(Self {
sections: Arc::new(sections),
genesis_pk: helper.genesis_pk,
})
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::routing::{gen_section_authority_provider, section_signed};
use eyre::{eyre, Context, Result};
use rand::Rng;
#[test]
fn insert_existing_prefix() -> Result<()> {
let (map, _, _) = new_network_prefix_map();
let p0 = prefix("0")?;
let sap0 = gen_section_auth(p0)?;
let new_sap0 = gen_section_auth(p0)?;
assert_ne!(sap0, new_sap0);
assert!(map.insert(sap0));
assert!(map.insert(new_sap0.clone()));
assert_eq!(map.get(&p0), Some(new_sap0.value));
Ok(())
}
#[test]
fn insert_direct_descendants_of_existing_prefix() -> Result<()> {
let (map, _, _) = new_network_prefix_map();
let p0 = prefix("0")?;
let p00 = prefix("00")?;
let p01 = prefix("01")?;
let sap0 = gen_section_auth(p0)?;
assert!(map.insert(sap0.clone()));
let sap00 = gen_section_auth(p00)?;
assert!(map.insert(sap00.clone()));
assert_eq!(map.get(&p00), Some(sap00.value.clone()));
assert_eq!(map.get(&p01), None);
assert_eq!(map.get(&p0), Some(sap0.value));
let sap3 = gen_section_auth(p01)?;
assert!(map.insert(sap3.clone()));
assert_eq!(map.get(&p00), Some(sap00.value));
assert_eq!(map.get(&p01), Some(sap3.value));
assert_eq!(map.get(&p0), None);
Ok(())
}
#[test]
fn return_opposite_prefix_if_none_matching() -> Result<()> {
let mut rng = rand::thread_rng();
let (map, _, _) = new_network_prefix_map();
let p0 = prefix("0")?;
let p1 = prefix("1")?;
let sap0 = gen_section_auth(p0)?;
let _changed = map.insert(sap0.clone());
assert!(map.section_by_name(&p1.substituted_in(rng.gen())).is_err(),);
assert_eq!(
map.closest_or_opposite(&p1.substituted_in(rng.gen()), None)
.ok_or(Error::NoMatchingSection)?,
sap0
);
let _changed = map.insert(sap0.clone());
assert_eq!(
map.closest_or_opposite(&p1.substituted_in(rng.gen()), None)
.ok_or(Error::NoMatchingSection)?,
sap0
);
Ok(())
}
#[test]
fn insert_indirect_descendants_of_existing_prefix() -> Result<()> {
let (map, _, _) = new_network_prefix_map();
let p0 = prefix("0")?;
let p000 = prefix("000")?;
let p001 = prefix("001")?;
let p00 = prefix("00")?;
let p01 = prefix("01")?;
let sap0 = gen_section_auth(p0)?;
let sap01 = gen_section_auth(p01)?;
let sap000 = gen_section_auth(p000)?;
let sap001 = gen_section_auth(p001)?;
assert!(map.insert(sap0.clone()));
assert!(map.insert(sap000.clone()));
assert_eq!(map.get(&p000), Some(sap000.value.clone()));
assert_eq!(map.get(&p001), None);
assert_eq!(map.get(&p00), None);
assert_eq!(map.get(&p01), None);
assert_eq!(map.get(&p0), Some(sap0.value.clone()));
assert!(map.insert(sap001.clone()));
assert_eq!(map.get(&p000), Some(sap000.value.clone()));
assert_eq!(map.get(&p001), Some(sap001.value.clone()));
assert_eq!(map.get(&p00), None);
assert_eq!(map.get(&p01), None);
assert_eq!(map.get(&p0), Some(sap0.value));
assert!(map.insert(sap01.clone()));
assert_eq!(map.get(&p000), Some(sap000.value));
assert_eq!(map.get(&p001), Some(sap001.value));
assert_eq!(map.get(&p00), None);
assert_eq!(map.get(&p01), Some(sap01.value));
assert_eq!(map.get(&p0), None);
Ok(())
}
#[test]
fn insert_ancestor_of_existing_prefix() -> Result<()> {
let (map, _, _) = new_network_prefix_map();
let p0 = prefix("0")?;
let p00 = prefix("00")?;
let sap0 = gen_section_auth(p0)?;
let sap00 = gen_section_auth(p00)?;
let _changed = map.insert(sap00.clone());
assert!(!map.insert(sap0));
assert_eq!(map.get(&p0), None);
assert_eq!(map.get(&p00), Some(sap00.value));
Ok(())
}
#[test]
fn get_matching() -> Result<()> {
let mut rng = rand::thread_rng();
let (map, _, _) = new_network_prefix_map();
let p0 = prefix("0")?;
let p1 = prefix("1")?;
let p10 = prefix("10")?;
let sap0 = gen_section_auth(p0)?;
let sap1 = gen_section_auth(p1)?;
let sap10 = gen_section_auth(p10)?;
let _changed = map.insert(sap0.clone());
let _changed = map.insert(sap1.clone());
let _changed = map.insert(sap10.clone());
assert_eq!(
map.section_by_name(&p0.substituted_in(rng.gen()))?,
sap0.value
);
assert_eq!(
map.section_by_name(&prefix("11")?.substituted_in(rng.gen()))?,
sap1.value
);
assert_eq!(
map.section_by_name(&p10.substituted_in(rng.gen()))?,
sap10.value
);
Ok(())
}
#[test]
fn get_matching_prefix() -> Result<()> {
let (map, _, _) = new_network_prefix_map();
let p0 = prefix("0")?;
let p1 = prefix("1")?;
let p10 = prefix("10")?;
let sap0 = gen_section_auth(p0)?;
let sap1 = gen_section_auth(p1)?;
let sap10 = gen_section_auth(p10)?;
let _changed = map.insert(sap0.clone());
let _changed = map.insert(sap1.clone());
let _changed = map.insert(sap10.clone());
assert_eq!(map.section_by_prefix(&p0)?, sap0.value);
assert_eq!(map.section_by_prefix(&prefix("11")?)?, sap1.value);
assert_eq!(map.section_by_prefix(&p10)?, sap10.value);
assert_eq!(map.section_by_prefix(&prefix("101")?)?, sap10.value);
Ok(())
}
#[test]
fn closest() -> Result<()> {
let (map, genesis_sk, genesis_pk) = new_network_prefix_map();
let chain = SecuredLinkedList::new(genesis_pk);
let p01 = prefix("01")?;
let p10 = prefix("10")?;
let p11 = prefix("11")?;
let mut chain01 = chain.clone();
let section_auth_01 = gen_section_auth(p01)?;
let pk01 = section_auth_01.section_key();
let sig01 = bincode::serialize(&pk01).map(|bytes| genesis_sk.sign(&bytes))?;
chain01.insert(&genesis_pk, pk01, sig01)?;
let _updated = map.verify_with_chain_and_update(section_auth_01, &chain01, &chain);
let mut chain10 = chain.clone();
let section_auth_10 = gen_section_auth(p10)?;
let pk10 = section_auth_10.section_key();
let sig10 = bincode::serialize(&pk10).map(|bytes| genesis_sk.sign(&bytes))?;
chain10.insert(&genesis_pk, pk10, sig10)?;
let _updated = map.verify_with_chain_and_update(section_auth_10, &chain10, &chain);
let mut rng = rand::thread_rng();
let n01 = p01.substituted_in(rng.gen());
let n10 = p10.substituted_in(rng.gen());
let n11 = p11.substituted_in(rng.gen());
assert_eq!(map.closest(&n01, None).map(|sap| sap.prefix()), Some(p01));
assert_eq!(map.closest(&n10, None).map(|sap| sap.prefix()), Some(p10));
assert_eq!(map.closest(&n11, None).map(|sap| sap.prefix()), Some(p10));
Ok(())
}
fn prefix(s: &str) -> Result<Prefix> {
s.parse()
.map_err(|err| eyre!("failed to parse Prefix '{}': {}", s, err))
}
fn gen_section_auth(prefix: Prefix) -> Result<SectionAuth<SectionAuthorityProvider>> {
let (section_auth, _, secret_key_set) = gen_section_authority_provider(prefix, 5);
section_signed(secret_key_set.secret_key(), section_auth)
.context(format!("Failed to generate SAP for prefix {:?}", prefix))
}
fn new_network_prefix_map() -> (NetworkPrefixMap, bls::SecretKey, BlsPublicKey) {
let genesis_sk = bls::SecretKey::random();
let genesis_pk = genesis_sk.public_key();
let map = NetworkPrefixMap::new(genesis_pk);
(map, genesis_sk, genesis_pk)
}
}