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

Commit

Permalink
feat/relocation: implement new relocation mechanism
Browse files Browse the repository at this point in the history
This takes many changes from PR #1429 by @michaelsproul which was closed in favour of this approach.

The main changes include:
* the addition of a new state 'JoiningNode'
* the removal of the ability to mutate a 'PublicId'
* changes to messages and internal states to allow a relocating node to use two different IDs
* changes to the state machine to allow a 'JoiningNode' to transition back into 'Bootstrapping'
  • Loading branch information
Fraser Hutchison committed Apr 19, 2017
1 parent 8e7f3be commit f89c730
Show file tree
Hide file tree
Showing 22 changed files with 1,539 additions and 714 deletions.
1 change: 1 addition & 0 deletions .gitignore
Expand Up @@ -13,3 +13,4 @@ target/
/bin
*.sublime-*
.cargo/
.DS_Store
1 change: 0 additions & 1 deletion src/action.rs
Expand Up @@ -31,7 +31,6 @@ use xor_name::XorName;
/// 2. `Action::Terminate` indicates to `Core` that no new actions should be taken and all
/// pending events should be handled.
/// After completion `Core` will send `Event::Terminated`.
#[derive(Clone)]
// FIXME - See https://maidsafe.atlassian.net/browse/MAID-2026 for info on removing this exclusion.
#[cfg_attr(feature="cargo-clippy", allow(large_enum_variant))]
pub enum Action {
Expand Down
18 changes: 8 additions & 10 deletions src/client.rs
Expand Up @@ -29,7 +29,7 @@ use routing_table::Authority;
#[cfg(not(feature = "use-mock-crust"))]
use rust_sodium;
use state_machine::{State, StateMachine};
use states;
use states::{Bootstrapping, BootstrappingTargetState};
#[cfg(feature = "use-mock-crust")]
use std::cell::RefCell;
use std::sync::mpsc::{Receiver, Sender, channel};
Expand Down Expand Up @@ -119,16 +119,14 @@ impl Client {
outbox: &mut EventBox)
-> (RoutingActionSender, StateMachine) {
let cache = Box::new(NullCache);
let full_id = keys.unwrap_or_else(FullId::new);

StateMachine::new(move |action_sender, crust_service, timer, _outbox2| {
states::Bootstrapping::new(action_sender,
cache,
true,
crust_service,
full_id,
min_section_size,
timer)
let target_state = BootstrappingTargetState::Client { opt_full_id: keys };
Bootstrapping::new(action_sender,
cache,
target_state,
crust_service,
min_section_size,
timer)
.map_or(State::Terminated, State::Bootstrapping)
},
outbox)
Expand Down
30 changes: 19 additions & 11 deletions src/id.rs
Expand Up @@ -51,6 +51,25 @@ impl FullId {
}
}

/// Construct a `FullId` whose name is in the interval [start, end] (both endpoint inclusive).
/// FIXME(Fraser) - time limit this function? Document behaviour
pub fn within_range(start: &XorName, end: &XorName) -> FullId {
let mut sign_keys = sign::gen_keypair();
loop {
let name = XorName(hash::sha256::hash(&sign_keys.0[..]).0);
if name.between(start, end) {
let encrypt_keys = box_::gen_keypair();
let full_id = FullId::with_keys(encrypt_keys, sign_keys);
// Ensure we update this `name` generation above if we change how `PublicId::name()`
// is calculated in the future.
assert_eq!(name, *full_id.public_id().name());
return full_id;
}
sign_keys = sign::gen_keypair();
}
}


/// Returns public ID reference.
pub fn public_id(&self) -> &PublicId {
&self.public_id
Expand Down Expand Up @@ -98,12 +117,6 @@ impl PublicId {
&self.name
}

/// Name field is initially same as original_name, this should be replaced by relocated name
/// calculated by the nodes close to original_name by using this method
pub fn set_name(&mut self, name: XorName) {
self.name = name;
}

/// Return public signing key.
pub fn encrypting_public_key(&self) -> &box_::PublicKey {
&self.public_encrypt_key
Expand All @@ -114,11 +127,6 @@ impl PublicId {
&self.public_sign_key
}

/// Returns whether our name is the hash of our public sign key.
pub fn is_client_id(&self) -> bool {
self.name.0 == hash::sha256::hash(&self.public_sign_key[..]).0
}

fn new(public_encrypt_key: box_::PublicKey, public_sign_key: sign::PublicKey) -> PublicId {
PublicId {
public_encrypt_key: public_encrypt_key,
Expand Down
150 changes: 83 additions & 67 deletions src/messages.rs
Expand Up @@ -100,7 +100,9 @@ impl Message {
/// Messages sent via a direct connection.
///
/// Allows routing to directly send specific messages between nodes.
#[derive(Clone, Serialize, Deserialize)]
#[derive(Serialize, Deserialize)]
// FIXME - See https://maidsafe.atlassian.net/browse/MAID-2026 for info on removing this exclusion.
#[cfg_attr(feature="cargo-clippy", allow(large_enum_variant))]
pub enum DirectMessage {
/// Sent from members of a section or group message's source authority to the first hop. The
/// message will only be relayed once enough signatures have been accumulated.
Expand Down Expand Up @@ -137,13 +139,20 @@ pub enum DirectMessage {
/// Should not influence JoiningNode / Proxy states which are expected to be direct only.
is_tunnel: bool,
},
/// Sent from a node which is still joining the network to another node, to allow the latter to
/// add the former to its routing table.
/// Sent from a node which is still relocating on the network to another node, to allow the
/// latter to add the former to its routing table.
CandidateIdentify {
/// Keys and claimed name, serialised outside routing.
serialised_public_id: Vec<u8>,
/// Signature of the originator of this message.
signature: sign::Signature,
/// `PublicId` from before relocation.
old_public_id: PublicId,
/// `PublicId` from after relocation.
new_public_id: PublicId,
/// Signature of concatenated `PublicId`s using the pre-relocation key.
signature_using_old: sign::Signature,
/// Signature of concatenated `PublicId`s and `signature_using_old` using the
/// post-relocation key.
signature_using_new: sign::Signature,
/// Client authority from after relocation.
new_client_auth: Authority<XorName>,
/// FIXME: Should be deprecated.
/// Tunnel connection indicator from sender which would override
/// intermediate peer_mgr states for routing table connection type.
Expand All @@ -158,9 +167,9 @@ pub enum DirectMessage {
TunnelClosed(PeerId),
/// Sent to a tunnel node to indicate the tunnel is not needed any more.
TunnelDisconnect(PeerId),
/// Request a proof to be provided by the joining node
/// Request a proof to be provided by the relocating node.
///
/// This is sent from member of Group Y to the joining node
/// This is sent from member of Group Y to the relocating node.
ResourceProof {
/// seed of proof
seed: Vec<u8>,
Expand All @@ -171,7 +180,7 @@ pub enum DirectMessage {
},
/// Provide a proof to the network
///
/// This is sent from the joining node to member of Group Y
/// This is sent from the relocating node to member of Group Y
ResourceProofResponse {
/// The index of this part of the resource proof.
part_index: usize,
Expand Down Expand Up @@ -525,13 +534,14 @@ impl RoutingMessage {
/// table and get added to their routing tables.
///
///
/// ### Getting a new network name from the `NaeManager`
/// ### Relocating on the network
///
/// Once in `Client` state, A sends a `GetNodeName` request to the `NaeManager` section authority X
/// of A's current name. X computes a new name and sends it in an `ExpectCandidate` request to the
/// `NaeManager` Y of A's new name. Each member of Y caches A's public ID, and sends
/// `AcceptAsCandidate` to self section. Once Y receives `AcceptAsCandidate`, sends a `GetNodeName`
/// response back to A, which includes the public IDs of the members of Y.
/// Once in `JoiningNode` state, A sends a `Relocate` request to the `NaeManager` section authority
/// X of A's current name. X computes a target destination Y to which A should relocate and sends
/// that section's `NaeManager`s an `ExpectCandidate` containing A's current public ID. Each member
/// of Y caches A's public ID, and sends `AcceptAsCandidate` to self section. Once Y receives
/// `AcceptAsCandidate`, sends a `RelocateResponse` back to A, which includes an address space range
/// into which A should relocate and also the public IDs of the members of Y.
///
///
/// ### Connecting to the matching section
Expand Down Expand Up @@ -561,22 +571,22 @@ impl RoutingMessage {
#[cfg_attr(feature="cargo-clippy", allow(large_enum_variant))]
pub enum MessageContent {
// ---------- Internal ------------
/// Ask the network to alter your `PublicId` name.
/// Ask the network to relocate you.
///
/// This is sent by a `Client` to its `NaeManager` with the intent to become a routing node with
/// a new name chosen by the `NaeManager`.
GetNodeName {
/// The client's `PublicId` (public keys and name)
current_id: PublicId,
/// This is sent by a relocating node to its `NaeManager`s with the intent to become a full
/// routing node with a new ID in an address range chosen by the `NaeManager`s.
Relocate {
/// The relocating node's current public ID.
public_id: PublicId,
/// The message's unique identifier.
message_id: MessageId,
},
/// Notify a joining node's `NaeManager` so that it sends a `GetNodeNameResponse`.
/// Notify a relocating node's `NaeManager` so that it sends a `RelocateResponse`.
ExpectCandidate {
/// The joining node's `PublicId` (public keys and name)
expect_id: PublicId,
/// The client's current authority.
client_auth: Authority<XorName>,
/// The relocating node's current public ID.
old_public_id: PublicId,
/// The relocating node's current authority.
old_client_auth: Authority<XorName>,
/// The message's unique identifier.
message_id: MessageId,
},
Expand Down Expand Up @@ -604,13 +614,11 @@ pub enum MessageContent {
/// The message's unique identifier.
msg_id: MessageId,
},
/// Reply with the new `PublicId` for the joining node.
///
/// Sent from the `NodeManager` to the `Client`.
GetNodeNameResponse {
/// Supplied `PublicId`, but with the new name
relocated_id: PublicId,
/// The relocated section that the joining node shall connect to
/// Reply with the address range into which the relocating node should move.
RelocateResponse {
/// The interval into which the relocating node should join.
target_interval: (XorName, XorName),
/// The section that the relocating node shall connect to.
section: BTreeSet<PublicId>,
/// The message's unique identifier.
message_id: MessageId,
Expand Down Expand Up @@ -660,25 +668,29 @@ pub enum MessageContent {
///
/// Sent from the `NaeManager` to the `NaeManager`.
AcceptAsCandidate {
/// Supplied `PublicId`, but with the new name
expect_id: PublicId,
/// Client authority of the candidate
client_auth: Authority<XorName>,
/// The relocating node's current public ID.
old_public_id: PublicId,
/// The relocating node's current authority.
old_client_auth: Authority<XorName>,
/// The interval into which the relocating node should join.
target_interval: (XorName, XorName),
/// The message's unique identifier.
message_id: MessageId,
},
/// Sent among Group Y to vote to accept a joining node.
/// Sent among Group Y to vote to accept a relocating node.
CandidateApproval {
/// The `PublicId` of the candidate
candidate_id: PublicId,
/// Client authority of the candidate
client_auth: Authority<XorName>,
/// The relocating node's current public ID.
old_public_id: PublicId,
/// The relocating node's current public ID.
new_public_id: PublicId,
/// Client authority of the candidate.
new_client_auth: Authority<XorName>,
/// The `PublicId`s of all routing table contacts shared by the nodes in our section.
sections: SectionMap,
},
/// Approves the joining node as a routing node.
/// Approves the relocating node as a routing node.
///
/// Sent from Group Y to the joining node.
/// Sent from Group Y to the relocating node.
NodeApproval {
/// The routing table shared by the nodes in our group, including the `PublicId`s of our
/// contacts.
Expand Down Expand Up @@ -778,24 +790,24 @@ impl Debug for MessageContent {
fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
use self::MessageContent::*;
match *self {
GetNodeName {
ref current_id,
Relocate {
ref public_id,
ref message_id,
} => {
write!(formatter,
"GetNodeName {{ {:?}, {:?} }}",
current_id,
"Relocate {{ {:?}, {:?} }}",
public_id,
message_id)
}
ExpectCandidate {
ref expect_id,
ref client_auth,
ref old_public_id,
ref old_client_auth,
ref message_id,
} => {
write!(formatter,
"ExpectCandidate {{ {:?}, {:?}, {:?} }}",
expect_id,
client_auth,
old_public_id,
old_client_auth,
message_id)
}
ConnectionInfoRequest {
Expand All @@ -818,14 +830,14 @@ impl Debug for MessageContent {
pub_id,
msg_id)
}
GetNodeNameResponse {
ref relocated_id,
RelocateResponse {
ref target_interval,
ref section,
ref message_id,
} => {
write!(formatter,
"GetNodeNameResponse {{ {:?}, {:?}, {:?} }}",
relocated_id,
"RelocateResponse {{ {:?}, {:?}, {:?} }}",
target_interval,
section,
message_id)
}
Expand Down Expand Up @@ -866,26 +878,30 @@ impl Debug for MessageContent {
hash[2])
}
AcceptAsCandidate {
ref expect_id,
ref client_auth,
ref old_public_id,
ref old_client_auth,
ref target_interval,
ref message_id,
} => {
write!(formatter,
"AcceptAsCandidate {{ {:?}, {:?}, {:?} }}",
expect_id,
client_auth,
"AcceptAsCandidate {{ {:?}, {:?}, {:?}, {:?} }}",
old_public_id,
old_client_auth,
target_interval,
message_id)
}
CandidateApproval {
ref candidate_id,
ref client_auth,
ref old_public_id,
ref new_public_id,
ref new_client_auth,
ref sections,
} => {
write!(formatter,
"CandidateApproval {{ candidate_id: {:?}, client_auth: {:?}, sections: \
"CandidateApproval {{ old: {:?}, new: {:?}, new: {:?}, sections: \
{:?} }}",
candidate_id,
client_auth,
old_public_id,
new_public_id,
new_client_auth,
sections)
}
NodeApproval { ref sections } => write!(formatter, "NodeApproval {{ {:?} }}", sections),
Expand Down
3 changes: 1 addition & 2 deletions src/mock_crust/crust.rs
Expand Up @@ -36,8 +36,7 @@ impl Service {
Self::with_handle(&support::get_current(), event_sender)
}

/// Create new mock `Service` by explicitly passing the mock device to associate
/// with.
/// Create new mock `Service` by explicitly passing the mock device to associate with.
pub fn with_handle(handle: &ServiceHandle,
event_sender: CrustEventSender)
-> Result<Self, CrustError> {
Expand Down

0 comments on commit f89c730

Please sign in to comment.