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

Commit

Permalink
feat: relocation during startup no-longer required
Browse files Browse the repository at this point in the history
  • Loading branch information
maqi committed Dec 3, 2020
1 parent a047ca1 commit cf937e4
Show file tree
Hide file tree
Showing 5 changed files with 26 additions and 88 deletions.
22 changes: 3 additions & 19 deletions src/relocation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,19 +15,13 @@ use crate::{
network::Network,
peer::Peer,
section::{MemberInfo, Section},
MIN_AGE,
};
use bytes::Bytes;
use rand::{Rng, SeedableRng};
use rand_chacha::ChaCha8Rng;
use serde::{de::Error as SerdeDeError, Deserialize, Deserializer, Serialize, Serializer};
use std::{convert::TryInto, net::SocketAddr, ops::Range};
use std::net::SocketAddr;
use tokio::sync::mpsc;
use xor_name::XorName;

// Range from which the age of a joining node is selected during the startup phase.
pub(crate) const STARTUP_PHASE_AGE_RANGE: Range<u8> = (MIN_AGE + 1)..32;

/// Find all nodes to relocate after a churn event and create the relocate actions for them.
pub(crate) fn actions(
section: &Section,
Expand Down Expand Up @@ -268,16 +262,6 @@ pub(crate) fn check(age: u8, churn_signature: &bls::Signature) -> bool {
trailing_zeros(&churn_signature.to_bytes()[..]) >= age as u32
}

// Generate age for relocated peer during the starup phase, using the `Online` vote signature as
// the random seed.
pub(crate) fn startup_phase_age(signature: &bls::Signature) -> u8 {
let seed = signature.to_bytes()[..32]
.try_into()
.expect("invalid signature length");
let mut rng = ChaCha8Rng::from_seed(seed);
rng.gen_range(STARTUP_PHASE_AGE_RANGE.start, STARTUP_PHASE_AGE_RANGE.end)
}

// Compute the destination for the node with `relocating_name` to be relocated to. `churn_name` is
// the name of the joined/left node that triggered the relocation.
fn destination(relocating_name: &XorName, churn_name: &XorName) -> XorName {
Expand Down Expand Up @@ -316,13 +300,13 @@ mod tests {
use super::*;
use crate::{
consensus::test_utils::proven, peer::test_utils::arbitrary_unique_peers,
section::EldersInfo, SectionProofChain, ELDER_SIZE,
section::EldersInfo, SectionProofChain, ELDER_SIZE, MIN_AGE,
};
use anyhow::Result;
use assert_matches::assert_matches;
use itertools::Itertools;
use proptest::prelude::*;
use rand::rngs::SmallRng;
use rand::{rngs::SmallRng, Rng, SeedableRng};
use xor_name::Prefix;

#[test]
Expand Down
77 changes: 20 additions & 57 deletions src/routing/approved.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1130,25 +1130,6 @@ impl Approved {
Ok(commands)
}

fn relocate_peer_in_startup_phase(
&self,
peer: Peer,
signature: &bls::Signature,
) -> Result<Vec<Command>> {
let age = relocation::startup_phase_age(signature);
let details =
RelocateDetails::with_age(&self.section, &self.network, &peer, *peer.name(), age);

trace!(
"Relocating {:?} to {} with age {} in startup phase",
peer,
details.destination,
details.age
);

self.send_relocate(&peer, details)
}

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);
Expand Down Expand Up @@ -1195,9 +1176,8 @@ impl Approved {
);
return Ok(commands);
}
// To avoid during startup_phase, a rejoin node being given a randmly higher age,
// force it to be halved.
if is_startup_phase || info.peer.age() / 2 > MIN_AGE {

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)?);
Expand All @@ -1208,45 +1188,28 @@ impl Approved {
}
}

if is_startup_phase && peer.age() <= MIN_AGE {
// In startup phase, instantly relocate the joining peer in order to promote it to
// adult.

if self.section.members().is_known(peer.name()) {
info!("ignore Online: {:?}", peer);
return Ok(vec![]);
}

// 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_peer_in_startup_phase(peer, &signature)?);
} else {
// Post startup phase, add the new peer normally.

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

info!("handle Online: {:?}", peer);
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()?);
commands.push(self.send_node_approval(&peer, their_knowledge)?);
commands.extend(self.relocate_peers(peer.name(), &signature)?);
commands.extend(self.promote_and_demote_elders()?);

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

self.print_network_stats();
}
self.print_network_stats();

Ok(commands)
}
Expand Down
6 changes: 2 additions & 4 deletions src/routing/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,8 @@ use crate::{
messages::{Message, PING},
node::Node,
peer::Peer,
relocation::STARTUP_PHASE_AGE_RANGE,
section::{EldersInfo, SectionProofChain},
TransportConfig,
TransportConfig, MIN_AGE,
};
use bytes::Bytes;
use ed25519_dalek::{Keypair, PublicKey, Signature, Signer};
Expand Down Expand Up @@ -96,8 +95,7 @@ impl Routing {
let (state, comm, backlog) = if config.first {
info!("{} Starting a new network as the seed node.", node_name);
let comm = Comm::new(config.transport_config, connection_event_tx)?;
let node = Node::new(keypair, comm.our_connection_info().await?)
.with_age(STARTUP_PHASE_AGE_RANGE.end);
let node = Node::new(keypair, comm.our_connection_info().await?).with_age(MIN_AGE + 1);
let state = Approved::first_node(node, event_tx)?;

state.send_event(Event::PromotedToElder);
Expand Down
5 changes: 0 additions & 5 deletions src/section/section_peers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,11 +92,6 @@ impl SectionPeers {
.unwrap_or(false)
}

/// Returns whether the given peer is known to us (joined or left)
pub fn is_known(&self, name: &XorName) -> bool {
self.members.contains_key(name)
}

/// Update a member of our section.
/// Returns whether anything actually changed.
pub fn update(&mut self, new_info: Proven<MemberInfo>) -> bool {
Expand Down
4 changes: 1 addition & 3 deletions tests/bootstrap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,9 +97,7 @@ async fn test_startup_section_bootstrapping() -> Result<()> {
let (node, mut event_stream) =
create_node(config_with_contact(genesis_contact)).await?;

// During the startup phase, joining nodes are instantly relocated.
assert_next_event!(event_stream, Event::RelocationStarted { .. });
assert_next_event!(event_stream, Event::Relocated { .. });
assert_event!(event_stream, Event::PromotedToElder);

Ok::<_, Error>(node)
})
Expand Down

0 comments on commit cf937e4

Please sign in to comment.