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

Commit

Permalink
fix: use age assigned by section
Browse files Browse the repository at this point in the history
  • Loading branch information
madadam committed Dec 15, 2020
1 parent 9cc26e9 commit 4db6351
Show file tree
Hide file tree
Showing 8 changed files with 132 additions and 78 deletions.
39 changes: 22 additions & 17 deletions src/messages/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -369,12 +369,15 @@ mod tests {
use super::*;
use crate::{
consensus, crypto,
section::{self, test_utils::gen_addr},
peer::Peer,
section::{self, test_utils::gen_addr, MemberInfo},
MIN_AGE,
};
use anyhow::Result;
use std::iter;

#[test]
fn extend_proof_chain() {
fn extend_proof_chain() -> Result<()> {
let node = Node::new(crypto::gen_keypair(), gen_addr());

let sk0 = bls::SecretKey::random();
Expand All @@ -384,42 +387,44 @@ mod tests {
let pk1 = sk1.public_key();

let mut full_proof_chain = SectionProofChain::new(sk0.public_key());
let pk1_sig = sk0.sign(&bincode::serialize(&pk1).unwrap());
let pk1_sig = sk0.sign(&bincode::serialize(&pk1)?);
let _ = full_proof_chain.push(pk1, pk1_sig);

let (elders_info, _) = section::test_utils::gen_elders_info(Default::default(), 3);
let elders_info = consensus::test_utils::proven(&sk1, elders_info).unwrap();
let elders_info = consensus::test_utils::proven(&sk1, elders_info)?;

let variant = Variant::NodeApproval(elders_info);
let peer = Peer::new(rand::random(), gen_addr(), MIN_AGE);
let member_info = MemberInfo::joined(peer);
let member_info = consensus::test_utils::proven(&sk1, member_info)?;

let variant = Variant::NodeApproval {
elders_info,
member_info,
};
let message = Message::single_src(
&node,
DstLocation::Direct,
variant,
Some(full_proof_chain.slice(1..)),
Some(pk1),
)
.unwrap();
)?;

assert_eq!(
message
.verify(iter::once((&Prefix::default(), &pk1)))
.unwrap(),
message.verify(iter::once((&Prefix::default(), &pk1)))?,
VerifyStatus::Full
);
assert_eq!(
message
.verify(iter::once((&Prefix::default(), &pk0)))
.unwrap(),
message.verify(iter::once((&Prefix::default(), &pk0)))?,
VerifyStatus::Unknown
);

let message = message.extend_proof_chain(&pk0, &full_proof_chain).unwrap();
let message = message.extend_proof_chain(&pk0, &full_proof_chain)?;

assert_eq!(
message
.verify(iter::once((&Prefix::default(), &pk0)))
.unwrap(),
message.verify(iter::once((&Prefix::default(), &pk0)))?,
VerifyStatus::Full
);

Ok(())
}
}
25 changes: 21 additions & 4 deletions src/messages/variant.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use crate::{
error::{Error, Result},
network::Network,
relocation::{RelocateDetails, RelocatePayload, RelocatePromise},
section::{EldersInfo, Section, SectionProofChain, TrustStatus},
section::{EldersInfo, MemberInfo, Section, SectionProofChain, TrustStatus},
};
use bls_dkg::key_gen::message::Message as DkgMessage;
use bytes::Bytes;
Expand Down Expand Up @@ -43,7 +43,10 @@ pub(crate) enum Variant {
UserMessage(Bytes),
/// Message sent to newly joined node containing the necessary info to become a member of our
/// section.
NodeApproval(Proven<EldersInfo>),
NodeApproval {
elders_info: Proven<EldersInfo>,
member_info: Proven<MemberInfo>,
},
/// Message sent to all members to update them about the state of our section.
Sync {
// Information about our section.
Expand Down Expand Up @@ -126,13 +129,20 @@ impl Variant {
I: IntoIterator<Item = &'a bls::PublicKey>,
{
match self {
Self::NodeApproval(elders_info) => {
Self::NodeApproval {
elders_info,
member_info,
} => {
let proof_chain = proof_chain.ok_or(Error::InvalidMessage)?;

if !elders_info.verify(proof_chain) {
return Err(Error::UntrustedMessage);
}

if !member_info.verify(proof_chain) {
return Err(Error::UntrustedMessage);
}

match proof_chain.check_trust(trusted_keys) {
TrustStatus::Trusted => Ok(VerifyStatus::Full),
TrustStatus::Unknown => Ok(VerifyStatus::Unknown),
Expand Down Expand Up @@ -166,7 +176,14 @@ impl Debug for Variant {
.field("nonce", nonce)
.finish(),
Self::UserMessage(payload) => write!(f, "UserMessage({:10})", HexFmt(payload)),
Self::NodeApproval(payload) => write!(f, "NodeApproval({:?})", payload),
Self::NodeApproval {
elders_info,
member_info,
} => f
.debug_struct("NodeApproval")
.field("elders_info", elders_info)
.field("member_info", member_info)
.finish(),
Self::Sync { section, .. } => f
.debug_struct("Sync")
.field("elders_info", section.elders_info())
Expand Down
100 changes: 56 additions & 44 deletions src/routing/approved.rs
Original file line number Diff line number Diff line change
Expand Up @@ -426,7 +426,7 @@ impl Approved {
return Ok(MessageStatus::Useless);
}
}
Variant::NodeApproval(_) | Variant::BootstrapResponse(_) => {
Variant::NodeApproval { .. } | Variant::BootstrapResponse(_) => {
// Skip validation of these. We will validate them inside the bootstrap task.
return Ok(MessageStatus::Useful);
}
Expand Down Expand Up @@ -561,7 +561,7 @@ impl Approved {
commands.extend(result?);
Ok(commands)
}
Variant::NodeApproval(_)
Variant::NodeApproval { .. }
| Variant::BootstrapResponse(_)
| Variant::ResourceChallenge { .. } => {
if let Some(RelocateState::InProgress(message_tx)) = &mut self.relocate_state {
Expand Down Expand Up @@ -1219,9 +1219,9 @@ impl Approved {
Ok(commands)
}

fn relocate_rejoining_peer(&self, peer: Peer, age: u8) -> Result<Vec<Command>> {
fn relocate_rejoining_peer(&self, peer: &Peer, age: u8) -> Result<Vec<Command>> {
let details =
RelocateDetails::with_age(&self.section, &self.network, &peer, *peer.name(), age);
RelocateDetails::with_age(&self.section, &self.network, peer, *peer.name(), age);

trace!(
"Relocating {:?} to {} with age {} due to rejoin",
Expand All @@ -1230,7 +1230,7 @@ impl Approved {
details.age
);

self.send_relocate(&peer, details)
self.send_relocate(peer, details)
}

// Are we in the startup phase? Startup phase is when the network consists of only one section
Expand All @@ -1242,62 +1242,64 @@ impl Approved {

fn handle_online_event(
&mut self,
member_info: MemberInfo,
new_info: MemberInfo,
previous_name: Option<XorName>,
their_knowledge: Option<bls::PublicKey>,
proof: Proof,
) -> Result<Vec<Command>> {
let peer = member_info.peer;
let signature = proof.signature.clone();

let mut commands = vec![];

let is_startup_phase = self.is_in_startup_phase();

if let Some(info) = self.section.members().get(peer.name()) {
if let Some(old_info) = self.section.members().get_proven(new_info.peer.name()) {
// This node is rejoin with same name.

if info.state != PeerState::Left {
if old_info.value.state != PeerState::Left {
debug!(
"Ignoring Online node {} - {:?} not Left.",
peer.name(),
info.state,
new_info.peer.name(),
old_info.value.state,
);

return Ok(commands);
}

if info.peer.age() / 2 > MIN_AGE {
// TODO: consider handling the relocation inside the bootstrap phase, to avoid having
// to send this `NodeApproval`.
commands.push(self.send_node_approval(&peer, their_knowledge)?);
commands.extend(
self.relocate_rejoining_peer(peer, cmp::max(MIN_AGE, info.peer.age() / 2))?,
);
let new_age = cmp::max(MIN_AGE, old_info.value.peer.age() / 2);

if new_age > MIN_AGE {
// TODO: consider handling the relocation inside the bootstrap phase, to avoid
// having to send this `NodeApproval`.
commands.push(self.send_node_approval(old_info.clone(), their_knowledge)?);
commands.extend(self.relocate_rejoining_peer(&old_info.value.peer, new_age)?);

return Ok(commands);
}
}

if !self.section.update_member(Proven {
value: member_info,
let new_info = Proven {
value: new_info,
proof,
}) {
info!("ignore Online: {:?}", peer);
};

if !self.section.update_member(new_info.clone()) {
info!("ignore Online: {:?}", new_info.value.peer);
return Ok(vec![]);
}

info!("handle Online: {:?}", peer);

commands.push(self.send_node_approval(&peer, their_knowledge)?);
commands.extend(self.relocate_peers(peer.name(), &signature)?);
commands.extend(self.promote_and_demote_elders()?);
info!("handle Online: {:?}", new_info.value.peer);

self.send_event(Event::MemberJoined {
name: *peer.name(),
name: *new_info.value.peer.name(),
previous_name,
age: peer.age(),
age: new_info.value.peer.age(),
startup_relocation: is_startup_phase,
});

commands
.extend(self.relocate_peers(new_info.value.peer.name(), &new_info.proof.signature)?);
commands.extend(self.promote_and_demote_elders()?);
commands.push(self.send_node_approval(new_info, their_knowledge)?);

self.print_network_stats();

Ok(commands)
Expand Down Expand Up @@ -1564,26 +1566,39 @@ impl Approved {
// Message sending
////////////////////////////////////////////////////////////////////////////

// Send NodeApproval to the current candidate which makes them a section member
// Send NodeApproval to a joining node which makes them a section member
fn send_node_approval(
&self,
peer: &Peer,
member_info: Proven<MemberInfo>,
their_knowledge: Option<bls::PublicKey>,
) -> Result<Command> {
info!(
"Our section with {:?} has approved candidate {:?}.",
"Our section with {:?} has approved peer {:?}.",
self.section.prefix(),
peer
member_info.value.peer
);

let their_knowledge = their_knowledge.and_then(|key| self.section.chain().index_of(&key));
let proof_chain = self
let addr = *member_info.value.peer.addr();

// Attach proof chain that includes the key the approved node knows (if any), the key its
// `MemberInfo` is signed with and the last key of our section chain.
let last_index = self.section.chain().last_key_index();
let their_knowledge_index = their_knowledge
.and_then(|key| self.section.chain().index_of(&key))
.unwrap_or(last_index);
let member_info_key_index = self
.section
.create_proof_chain_for_our_info(their_knowledge);
.chain()
.index_of(&member_info.proof.public_key)
.unwrap_or(last_index);
let start_index = their_knowledge_index.min(member_info_key_index);
let proof_chain = self.section.chain().slice(start_index..);

let variant = Variant::NodeApproval(self.section.proven_elders_info().clone());
let variant = Variant::NodeApproval {
elders_info: self.section.proven_elders_info().clone(),
member_info,
};

trace!("Send {:?} to {:?}", variant, peer);
let message = Message::single_src(
&self.node,
DstLocation::Direct,
Expand All @@ -1592,10 +1607,7 @@ impl Approved {
None,
)?;

Ok(Command::send_message_to_target(
peer.addr(),
message.to_bytes(),
))
Ok(Command::send_message_to_target(&addr, message.to_bytes()))
}

fn send_sync(&mut self, section: Section, network: Network) -> Result<Vec<Command>> {
Expand Down

0 comments on commit 4db6351

Please sign in to comment.