Skip to content
This repository has been archived by the owner on Jun 25, 2021. It is now read-only.

Commit

Permalink
fix(AE): implement SrcAhead flow
Browse files Browse the repository at this point in the history
  • Loading branch information
Yoga07 authored and dirvine committed May 13, 2021
1 parent bdbc320 commit ade92fb
Show file tree
Hide file tree
Showing 11 changed files with 175 additions and 251 deletions.
1 change: 1 addition & 0 deletions src/agreement/proposal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,7 @@ mod tests {
use anyhow::Result;
use rand::Rng;
use std::fmt::Debug;
use xor_name::Prefix;

#[test]
#[ignore]
Expand Down
53 changes: 23 additions & 30 deletions src/messages/variant.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,15 @@ use xor_name::XorName;
/// Message variant
pub(crate) enum Variant {
/// Inform other sections about our section or vice-versa.
OtherSection {
/// `SectionAuthorityProvider` of the sender's section, with the proof chain.
section_auth: Proven<SectionAuthorityProvider>,
/// Nonce that is derived from the incoming message that triggered sending this
/// message. It's purpose is to make sure that `OtherSection`s that are identical
/// but triggered by different messages are not filtered out.
nonce: MessageHash,
SectionKnowledge {
/// `SectionAuthorityProvider` and `SectionChain` of the sender's section, with the proof chain.
src_info: (Proven<SectionAuthorityProvider>, SectionChain),
/// Message
msg: Box<Message>,
// Nonce that is derived from the incoming message that triggered sending this
// message. It's purpose is to make sure that `OtherSection`s that are identical
// but triggered by different messages are not filtered out.
// nonce: MessageHash,
},
/// User-facing message
UserMessage(Bytes),
Expand Down Expand Up @@ -111,10 +113,19 @@ pub(crate) enum Variant {
nonce: [u8; 32],
nonce_signature: Signature,
},
/// Message sent by dst to indicate that Src is ahead in knowledge.
/// A follow-up reply will be sent by Src with SectionKnowledge
SrcAhead {
key: bls::PublicKey,
msg: Box<Message>,
},
/// Message sent by dst to indicate that sender is lagging on knowledge and shares it.
// SrcOutdated(Variant),
/// Message sent by dst to indicate that the Dst is ahead on knowledge and shares it.
DstAhead(SectionChain),
DstOutdated,
SrcAhead,
SrcOutdated,
/// Message sent by dst to indicate that Dst is outdated in knowledge.
/// A follow-up reply will be sent by src with SectionKnowledge.
// DstOutdated,
/// Direct complaint sent from an adult to elders regarding the connectivity issue of an elder.
ConnectivityComplaint(XorName),
}
Expand Down Expand Up @@ -147,15 +158,6 @@ impl Variant {
proof_chain
}
Self::Sync { section, .. } => section.chain(),
Self::OtherSection { section_auth, .. } => {
let proof_chain = proof_chain.ok_or(Error::InvalidMessage)?;

if !section_auth.verify(proof_chain) {
return Err(Error::InvalidMessage);
}

proof_chain
}
_ => return Ok(VerifyStatus::Full),
};

Expand All @@ -170,14 +172,7 @@ impl Variant {
impl Debug for Variant {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
match self {
Self::OtherSection {
section_auth,
nonce,
} => f
.debug_struct("OtherSection")
.field("section_auth", section_auth)
.field("nonce", nonce)
.finish(),
Self::SectionKnowledge { .. } => f.debug_struct("SectionKnowledge").finish(),
Self::UserMessage(payload) => write!(f, "UserMessage({:10})", HexFmt(payload)),
Self::NodeApproval {
genesis_key,
Expand Down Expand Up @@ -259,9 +254,7 @@ impl Debug for Variant {
.finish(),
Self::ConnectivityComplaint(name) => write!(f, "ConnectivityComplaint({:?})", name),
Self::DstAhead(_) => write!(f, "DstAhead"),
Self::DstOutdated => write!(f, "DstOutdated"),
Self::SrcAhead => write!(f, "SrcAhead"),
Self::SrcOutdated => write!(f, "SrcOutdated"),
Self::SrcAhead { .. } => write!(f, "SrcAhead"),
}
}
}
Expand Down
114 changes: 11 additions & 103 deletions src/network/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,17 +26,14 @@ pub struct Network {
// Other sections: maps section prefixes to their latest signed section authority providers.
sections: PrefixMap<OtherSection>,
// BLS public keys of known sections excluding ours.
keys: PrefixMap<Proven<(Prefix, bls::PublicKey)>>,
// Our section keys that are trusted by other sections.
knowledge: PrefixMap<Proven<(Prefix, bls::PublicKey)>>,
keys: PrefixMap<(Prefix, bls::PublicKey)>,
}

impl Network {
pub fn new() -> Self {
Self {
sections: PrefixMap::new(),
keys: PrefixMap::new(),
knowledge: PrefixMap::new(),
}
}

Expand Down Expand Up @@ -97,15 +94,7 @@ impl Network {
}

for entry in other.keys {
if entry.verify(section_chain) {
let _ = self.keys.insert(entry);
}
}

for entry in other.knowledge {
if entry.verify(section_chain) {
let _ = self.knowledge.insert(entry);
}
let _ = self.keys.insert(entry);
}
}

Expand Down Expand Up @@ -144,16 +133,12 @@ impl Network {

/// Updates the entry in `keys` for `prefix` to the latest known key.
#[allow(unused)]
pub fn update_their_key(&mut self, new_key: Proven<(Prefix, bls::PublicKey)>) -> bool {
pub fn update_their_key(&mut self, new_key: (Prefix, bls::PublicKey)) -> bool {
// TODO: verify against section chain

trace!(
"update key for {:?}: {:?}",
new_key.value.0,
new_key.value.1
);
trace!("update key for {:?}: {:?}", new_key.0, new_key.1);

if let Some(old) = self.keys.insert(new_key.clone()) {
if let Some(old) = self.keys.insert(new_key) {
if old == new_key {
return false;
}
Expand All @@ -164,27 +149,25 @@ impl Network {

/// Returns the known section keys.
pub fn keys(&self) -> impl Iterator<Item = (&Prefix, &bls::PublicKey)> {
self.keys
.iter()
.map(|entry| (&entry.value.0, &entry.value.1))
self.keys.iter().map(|entry| (&entry.0, &entry.1))
}

#[allow(unused)]
pub fn has_key(&self, key: &bls::PublicKey) -> bool {
self.keys.iter().any(|entry| entry.value.1 == *key)
self.keys.iter().any(|entry| entry.1 == *key)
}

/// Returns the latest known key for the prefix that matches `name`.
pub fn key_by_name(&self, name: &XorName) -> Option<&bls::PublicKey> {
self.keys.get_matching(name).map(|entry| &entry.value.1)
self.keys.get_matching(name).map(|entry| &entry.1)
}

/// Returns the latest known key for a section with `prefix`.
/// If this returns `None` that means the latest known key is the genesis key.
pub fn key_by_prefix(&self, prefix: &Prefix) -> Option<&bls::PublicKey> {
self.keys
.get_equal_or_ancestor(prefix)
.map(|entry| &entry.value.1)
.map(|entry| &entry.1)
}

/// Returns the section_auth and the latest known key for the prefix that matches `name`,
Expand All @@ -194,34 +177,13 @@ impl Network {
name: &XorName,
) -> (Option<&bls::PublicKey>, Option<&SectionAuthorityProvider>) {
(
self.keys.get_matching(name).map(|entry| &entry.value.1),
self.keys.get_matching(name).map(|entry| &entry.1),
self.sections
.get_matching(name)
.map(|entry| &entry.section_auth.value),
)
}

/// Returns the public key in our chain that will be trusted by the given name.
pub fn knowledge_by_name(&self, name: &XorName) -> Option<&bls::PublicKey> {
self.knowledge
.get_matching(name)
.map(|entry| &entry.value.1)
}

/// Updates the key of our section that is known by some other section.
/// The passed in proven tuple consist of the prefix of the section whose knowledge we are
/// updaing and the key of our section we are updating it to.
#[allow(unused)]
pub fn update_knowledge(&mut self, knowledge: Proven<(Prefix, bls::PublicKey)>) {
trace!(
"update knowledge of section ({:b}) about our section to {:?}",
knowledge.value.0,
knowledge.value.1,
);

let _ = self.knowledge.insert(knowledge);
}

/// Returns network statistics.
pub fn network_stats(&self, our: &SectionAuthorityProvider) -> NetworkStats {
let (known_elders, total_elders, total_elders_exact) = self.network_elder_counts(our);
Expand Down Expand Up @@ -378,28 +340,6 @@ mod tests {
);
}

#[test]
fn update_their_knowledge_after_split_from_one_sibling() {
let pk1 = gen_key();
let pk2 = gen_key();

update_their_knowledge_and_check(
vec![("1", pk1), ("10", pk2)],
vec![("10", pk2), ("11", pk1)],
)
}

#[test]
fn update_their_knowledge_after_split_from_both_siblings() {
let pk1 = gen_key();
let pk2 = gen_key();

update_their_knowledge_and_check(
vec![("1", pk1), ("10", pk2), ("11", pk2)],
vec![("10", pk2), ("11", pk2)],
)
}

#[test]
fn closest() {
let sk = bls::SecretKey::random();
Expand Down Expand Up @@ -435,15 +375,11 @@ mod tests {
updates: Vec<(&str, &bls::PublicKey)>,
expected: Vec<(&str, &bls::PublicKey)>,
) {
let sk = bls::SecretKey::random();

let mut map = Network::new();

for (prefix, key) in updates {
let prefix = prefix.parse().unwrap();
let proof = agreement::test_utils::prove(&sk, &(&prefix, key)).unwrap();
let proven = Proven::new((prefix, *key), proof);
let _ = map.update_their_key(proven);
let _ = map.update_their_key((prefix, *key));
}

let actual: Vec<_> = map.keys().map(|(prefix, key)| (*prefix, key)).collect();
Expand All @@ -454,34 +390,6 @@ mod tests {
assert_eq!(actual, expected);
}

// Perform a series of updates to `knowledge`, then verify that the known keys for the given
// dst locations are as expected.
//
// - `updates` - pairs of (prefix, key) to pass to `update_knowledge`
// - `expected_trusted_keys` - pairs of (prefix, key) where the dst location name is
// generated such that it matches `prefix` and `key` is the expected trusted key.
fn update_their_knowledge_and_check(
updates: Vec<(&str, bls::PublicKey)>,
expected_trusted_keys: Vec<(&str, bls::PublicKey)>,
) {
let sk = bls::SecretKey::random();

let mut map = Network::new();

for (prefix_str, key) in updates {
let prefix = prefix_str.parse().unwrap();
let payload = agreement::test_utils::proven(&sk, (prefix, key)).unwrap();
map.update_knowledge(payload);
}

for (dst_name_prefix_str, expected_key) in expected_trusted_keys {
let dst_name_prefix: Prefix = dst_name_prefix_str.parse().unwrap();
let dst_name = dst_name_prefix.substituted_in(rand::random());

assert_eq!(map.knowledge_by_name(&dst_name), Some(&expected_key));
}
}

fn gen_proven_section_auth(
sk: &bls::SecretKey,
prefix: Prefix,
Expand Down
19 changes: 1 addition & 18 deletions src/routing/core/messaging/handling/agreement.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use std::cmp;

use bls_signature_aggregator::Proof;
use sn_messaging::{DestInfo, DstLocation};
use xor_name::{Prefix, XorName};
use xor_name::XorName;

use crate::{
agreement::{Proposal, Proven},
Expand Down Expand Up @@ -286,23 +286,6 @@ impl Core {
self.update_state(snapshot)
}

#[allow(unused)]
fn handle_their_key_agreement(&mut self, prefix: Prefix, key: bls::PublicKey, proof: Proof) {
let key = Proven::new((prefix, key), proof);
let _ = self.network.update_their_key(key);
}

#[allow(unused)]
fn handle_their_knowledge_agreement(
&mut self,
prefix: Prefix,
knowledge: bls::PublicKey,
proof: Proof,
) {
let knowledge = Proven::new((prefix, knowledge), proof);
self.network.update_knowledge(knowledge)
}

fn handle_accumulate_at_src_agreement(
&self,
message: PlainMessage,
Expand Down
6 changes: 2 additions & 4 deletions src/routing/core/messaging/handling/decisions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ use crate::{
impl Core {
pub(crate) fn decide_message_status(&self, msg: &Message) -> Result<MessageStatus> {
match msg.variant() {
Variant::OtherSection { .. } | Variant::ConnectivityComplaint(_) => {
Variant::SectionKnowledge { .. } | Variant::ConnectivityComplaint(_) => {
if !self.is_elder() {
return Ok(MessageStatus::Useless);
}
Expand Down Expand Up @@ -83,10 +83,8 @@ impl Core {
| Variant::DkgMessage { .. }
| Variant::DkgFailureObservation { .. }
| Variant::DkgFailureAgreement { .. }
| Variant::SrcAhead
| Variant::SrcOutdated
| Variant::SrcAhead { .. }
| Variant::DstAhead(_)
| Variant::DstOutdated
| Variant::ResourceChallenge { .. } => {}
}

Expand Down

0 comments on commit ade92fb

Please sign in to comment.