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

Commit

Permalink
fix: do not require resource proof for relocated node + test
Browse files Browse the repository at this point in the history
  • Loading branch information
madadam authored and dirvine committed Dec 9, 2020
1 parent 9a18b4c commit 667e1fb
Show file tree
Hide file tree
Showing 2 changed files with 144 additions and 23 deletions.
71 changes: 48 additions & 23 deletions src/routing/approved.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1028,39 +1028,64 @@ impl Approved {
(MIN_AGE + 1, None, None)
};

if let Some(ResourceProofResponse {
solution,
data,
nonce,
nonce_signature,
}) = join_request.resource_proof_response
{
let serialized = bincode::serialize(&(*peer.name(), nonce))?;
if self
.node
.keypair
.public
.verify(&serialized, &nonce_signature)
.is_ok()
&& self.resource_proof.validate_all(&nonce, &data, solution)
{
return self.vote(Vote::Online {
member_info: MemberInfo::joined(peer.with_age(age)),
previous_name,
their_knowledge,
});
// Require resource proof only if joining as a new node.
if previous_name.is_none() {
if let Some(response) = join_request.resource_proof_response {
if !self.validate_resource_proof_response(peer.name(), response) {
debug!(
"Ignoring JoinRequest from {} - invalid resource proof response",
pub_id
);
return Ok(vec![]);
}
} else {
return Ok(vec![self.send_resource_proof_challenge(&peer)?]);
}
}

self.vote(Vote::Online {
member_info: MemberInfo::joined(peer.with_age(age)),
previous_name,
their_knowledge,
})
}

fn validate_resource_proof_response(
&self,
peer_name: &XorName,
response: ResourceProofResponse,
) -> bool {
let serialized = if let Ok(serialized) = bincode::serialize(&(peer_name, &response.nonce)) {
serialized
} else {
return false;
};

if self
.node
.keypair
.public
.verify(&serialized, &response.nonce_signature)
.is_err()
{
return false;
}

self.resource_proof
.validate_all(&response.nonce, &response.data, response.solution)
}

fn send_resource_proof_challenge(&self, peer: &Peer) -> Result<Command> {
let nonce: [u8; 32] = rand::random();
let serialized = bincode::serialize(&(*peer.name(), nonce))?;
let serialized = bincode::serialize(&(peer.name(), &nonce))?;
let response = Variant::ResourceChallenge {
data_size: RESOURCE_PROOF_DATA_SIZE,
difficulty: RESOURCE_PROOF_DIFFICULTY,
nonce,
nonce_signature: crypto::sign(&serialized, &self.node.keypair),
};
Ok(vec![self.send_direct_message(peer.addr(), response)?])

self.send_direct_message(peer.addr(), response)
}

fn handle_dkg_start(
Expand Down
96 changes: 96 additions & 0 deletions src/routing/tests/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ use crate::{
peer::Peer,
relocation,
relocation::RelocateDetails,
relocation::RelocatePayload,
relocation::SignedRelocateDetails,
section::{
test_utils::*, EldersInfo, MemberInfo, PeerState, Section, SectionKeyShare,
SectionProofChain, MIN_AGE,
Expand Down Expand Up @@ -186,6 +188,100 @@ async fn receive_join_request_with_resource_proof_response() -> Result<()> {
Ok(())
}

#[tokio::test]
async fn receive_join_request_from_relocated_node() -> Result<()> {
let (elders_info, mut nodes) = create_elders_info();

let sk_set = SecretKeySet::random();
let pk_set = sk_set.public_keys();
let section_key = pk_set.public_key();

let (section, section_key_share) = create_section(&sk_set, &elders_info)?;
let node = nodes.remove(0);
let state = Approved::new(
node,
section,
Some(section_key_share),
mpsc::unbounded_channel().0,
);
let stage = Stage::new(state, create_comm()?);

let relocated_node_old_keypair = crypto::gen_keypair();
let relocated_node_old_name = crypto::name(&relocated_node_old_keypair.public);
let relocated_node = Node::new(crypto::gen_keypair(), gen_addr()).with_age(MIN_AGE + 2);

let relocate_details = RelocateDetails {
pub_id: relocated_node_old_name,
destination: rand::random(),
destination_key: section_key,
age: relocated_node.age,
};

let relocate_message = PlainMessage {
src: Prefix::default(),
dst: DstLocation::Node(relocated_node_old_name),
dst_key: section_key,
variant: Variant::Relocate(relocate_details),
};
let signature = sk_set
.secret_key()
.sign(&bincode::serialize(&relocate_message.as_signable())?);
let proof_chain = SectionProofChain::new(section_key);
let relocate_message = Message::section_src(relocate_message, signature, proof_chain)?;
let relocate_details = SignedRelocateDetails::new(relocate_message)?;
let relocate_payload = RelocatePayload::new(
relocate_details,
&relocated_node.name(),
&relocated_node_old_keypair,
)?;

let join_request = Message::single_src(
&relocated_node,
DstLocation::Direct,
Variant::JoinRequest(Box::new(JoinRequest {
section_key,
relocate_payload: Some(relocate_payload),
resource_proof_response: None,
})),
None,
None,
)?;

let commands = stage
.handle_command(Command::HandleMessage {
sender: Some(relocated_node.addr),
message: join_request,
})
.await?;

let mut online_voted = false;

for command in commands {
let vote = match command {
Command::HandleVote { vote, .. } => vote,
_ => continue,
};

if let Vote::Online {
member_info,
previous_name,
their_knowledge,
} = vote
{
assert_eq!(member_info.peer, relocated_node.peer());
assert_eq!(member_info.state, PeerState::Joined);
assert_eq!(previous_name, Some(relocated_node_old_name));
assert_eq!(their_knowledge, Some(section_key));

online_voted = true;
}
}

assert!(online_voted);

Ok(())
}

#[tokio::test]
async fn accumulate_votes() -> Result<()> {
let (elders_info, mut nodes) = create_elders_info();
Expand Down

0 comments on commit 667e1fb

Please sign in to comment.