xfer
This commit is contained in:
parent
cd9a3414cf
commit
f17c2f62cb
@ -29,6 +29,13 @@ pub enum Destination {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Destination {
|
impl Destination {
|
||||||
|
pub fn target(&self) -> Option<NodeRef> {
|
||||||
|
match self {
|
||||||
|
Destination::Direct { target, safety_selection: _ } => Some(target.clone()),
|
||||||
|
Destination::Relay { relay:_, target, safety_selection: _ } => Some(target.clone()),
|
||||||
|
Destination::PrivateRoute { private_route:_, safety_selection:_ } => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
pub fn direct(target: NodeRef) -> Self {
|
pub fn direct(target: NodeRef) -> Self {
|
||||||
let sequencing = target.sequencing();
|
let sequencing = target.sequencing();
|
||||||
Self::Direct {
|
Self::Direct {
|
||||||
|
@ -88,6 +88,7 @@ where
|
|||||||
for cn in &ctx.closest_nodes {
|
for cn in &ctx.closest_nodes {
|
||||||
if cn.same_entry(&nn) {
|
if cn.same_entry(&nn) {
|
||||||
dup = true;
|
dup = true;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !dup {
|
if !dup {
|
||||||
@ -125,6 +126,7 @@ where
|
|||||||
// New fanout call candidate found
|
// New fanout call candidate found
|
||||||
next_node = Some(cn.clone());
|
next_node = Some(cn.clone());
|
||||||
ctx.called_nodes.add(key);
|
ctx.called_nodes.add(key);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -395,7 +395,7 @@ impl RPCProcessor {
|
|||||||
//////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
/// Determine if a SignedNodeInfo can be placed into the specified routing domain
|
/// Determine if a SignedNodeInfo can be placed into the specified routing domain
|
||||||
fn filter_node_info(
|
fn verify_node_info(
|
||||||
&self,
|
&self,
|
||||||
routing_domain: RoutingDomain,
|
routing_domain: RoutingDomain,
|
||||||
signed_node_info: &SignedNodeInfo,
|
signed_node_info: &SignedNodeInfo,
|
||||||
@ -404,6 +404,37 @@ impl RPCProcessor {
|
|||||||
routing_table.signed_node_info_is_valid_in_routing_domain(routing_domain, &signed_node_info)
|
routing_table.signed_node_info_is_valid_in_routing_domain(routing_domain, &signed_node_info)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Determine if set of peers is closer to key_near than key_far
|
||||||
|
fn verify_peers_closer(
|
||||||
|
&self,
|
||||||
|
vcrypto: CryptoSystemVersion,
|
||||||
|
key_far: TypedKey,
|
||||||
|
key_near: TypedKey,
|
||||||
|
peers: &[PeerInfo],
|
||||||
|
) -> Result<bool, RPCError> {
|
||||||
|
let kind = vcrypto.kind();
|
||||||
|
|
||||||
|
if key_far.kind != kind || key_near.kind != kind {
|
||||||
|
return Err(RPCError::internal("keys all need the same cryptosystem"));
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut closer = true;
|
||||||
|
for peer in peers {
|
||||||
|
let Some(key_peer) = peer.node_ids().get(kind) else {
|
||||||
|
return Err(RPCError::invalid_format(
|
||||||
|
"peers need to have a key with the same cryptosystem",
|
||||||
|
));
|
||||||
|
};
|
||||||
|
let d_near = vcrypto.distance(&key_near.value, &key_peer.value);
|
||||||
|
let d_far = vcrypto.distance(&key_far.value, &key_peer.value);
|
||||||
|
if d_far < d_near {
|
||||||
|
closer = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(closer)
|
||||||
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
/// Search the DHT for a single node closest to a key and add it to the routing table and return the node reference
|
/// Search the DHT for a single node closest to a key and add it to the routing table and return the node reference
|
||||||
@ -1348,7 +1379,7 @@ impl RPCProcessor {
|
|||||||
// Ensure the sender peer info is for the actual sender specified in the envelope
|
// Ensure the sender peer info is for the actual sender specified in the envelope
|
||||||
|
|
||||||
// Sender PeerInfo was specified, update our routing table with it
|
// Sender PeerInfo was specified, update our routing table with it
|
||||||
if !self.filter_node_info(routing_domain, sender_peer_info.signed_node_info()) {
|
if !self.verify_node_info(routing_domain, sender_peer_info.signed_node_info()) {
|
||||||
return Ok(NetworkResult::invalid_message(
|
return Ok(NetworkResult::invalid_message(
|
||||||
"sender peerinfo has invalid peer scope",
|
"sender peerinfo has invalid peer scope",
|
||||||
));
|
));
|
||||||
|
@ -29,9 +29,9 @@ impl RPCProcessor {
|
|||||||
let app_call_a = match kind {
|
let app_call_a = match kind {
|
||||||
RPCOperationKind::Answer(a) => match a.destructure() {
|
RPCOperationKind::Answer(a) => match a.destructure() {
|
||||||
RPCAnswerDetail::AppCallA(a) => a,
|
RPCAnswerDetail::AppCallA(a) => a,
|
||||||
_ => return Err(RPCError::invalid_format("not an appcall answer")),
|
_ => return Ok(NetworkResult::invalid_message("not an appcall answer")),
|
||||||
},
|
},
|
||||||
_ => return Err(RPCError::invalid_format("not an answer")),
|
_ => return Ok(NetworkResult::invalid_message("not an answer")),
|
||||||
};
|
};
|
||||||
|
|
||||||
let a_message = app_call_a.destructure();
|
let a_message = app_call_a.destructure();
|
||||||
|
@ -46,17 +46,17 @@ impl RPCProcessor {
|
|||||||
let find_node_a = match kind {
|
let find_node_a = match kind {
|
||||||
RPCOperationKind::Answer(a) => match a.destructure() {
|
RPCOperationKind::Answer(a) => match a.destructure() {
|
||||||
RPCAnswerDetail::FindNodeA(a) => a,
|
RPCAnswerDetail::FindNodeA(a) => a,
|
||||||
_ => return Err(RPCError::invalid_format("not a find_node answer")),
|
_ => return Ok(NetworkResult::invalid_message("not a find_node answer")),
|
||||||
},
|
},
|
||||||
_ => return Err(RPCError::invalid_format("not an answer")),
|
_ => return Ok(NetworkResult::invalid_message("not an answer")),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Verify peers are in the correct peer scope
|
// Verify peers are in the correct peer scope
|
||||||
let peers = find_node_a.destructure();
|
let peers = find_node_a.destructure();
|
||||||
|
|
||||||
for peer_info in &peers {
|
for peer_info in &peers {
|
||||||
if !self.filter_node_info(RoutingDomain::PublicInternet, peer_info.signed_node_info()) {
|
if !self.verify_node_info(RoutingDomain::PublicInternet, peer_info.signed_node_info()) {
|
||||||
return Err(RPCError::invalid_format(
|
return Ok(NetworkResult::invalid_message(
|
||||||
"find_node response has invalid peer scope",
|
"find_node response has invalid peer scope",
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
@ -24,32 +24,32 @@ impl RPCProcessor {
|
|||||||
last_descriptor: Option<SignedValueDescriptor>,
|
last_descriptor: Option<SignedValueDescriptor>,
|
||||||
) -> Result<NetworkResult<Answer<GetValueAnswer>>, RPCError> {
|
) -> Result<NetworkResult<Answer<GetValueAnswer>>, RPCError> {
|
||||||
// Ensure destination never has a private route
|
// Ensure destination never has a private route
|
||||||
if matches!(
|
// and get the target noderef so we can validate the response
|
||||||
dest,
|
let Some(target) = dest.target() else {
|
||||||
Destination::PrivateRoute {
|
|
||||||
private_route: _,
|
|
||||||
safety_selection: _
|
|
||||||
}
|
|
||||||
) {
|
|
||||||
return Err(RPCError::internal(
|
return Err(RPCError::internal(
|
||||||
"Never send get value requests over private routes",
|
"Never send set value requests over private routes",
|
||||||
));
|
));
|
||||||
}
|
};
|
||||||
|
|
||||||
|
// Get the target node id
|
||||||
|
let Some(vcrypto) = self.crypto.get(key.kind) else {
|
||||||
|
return Err(RPCError::internal("unsupported cryptosystem"));
|
||||||
|
};
|
||||||
|
let Some(target_node_id) = target.node_ids().get(key.kind) else {
|
||||||
|
return Err(RPCError::internal("No node id for crypto kind"));
|
||||||
|
};
|
||||||
|
|
||||||
|
// Send the getvalue question
|
||||||
let get_value_q = RPCOperationGetValueQ::new(key, subkey, last_descriptor.is_none());
|
let get_value_q = RPCOperationGetValueQ::new(key, subkey, last_descriptor.is_none());
|
||||||
let question = RPCQuestion::new(
|
let question = RPCQuestion::new(
|
||||||
network_result_try!(self.get_destination_respond_to(&dest)?),
|
network_result_try!(self.get_destination_respond_to(&dest)?),
|
||||||
RPCQuestionDetail::GetValueQ(get_value_q),
|
RPCQuestionDetail::GetValueQ(get_value_q),
|
||||||
);
|
);
|
||||||
let Some(vcrypto) = self.crypto.get(key.kind) else {
|
|
||||||
return Err(RPCError::internal("unsupported cryptosystem"));
|
|
||||||
};
|
|
||||||
|
|
||||||
// Send the getvalue question
|
|
||||||
let question_context = QuestionContext::GetValue(ValidateGetValueContext {
|
let question_context = QuestionContext::GetValue(ValidateGetValueContext {
|
||||||
last_descriptor,
|
last_descriptor,
|
||||||
subkey,
|
subkey,
|
||||||
vcrypto,
|
vcrypto: vcrypto.clone(),
|
||||||
});
|
});
|
||||||
|
|
||||||
let waitable_reply = network_result_try!(
|
let waitable_reply = network_result_try!(
|
||||||
@ -68,13 +68,29 @@ impl RPCProcessor {
|
|||||||
let get_value_a = match kind {
|
let get_value_a = match kind {
|
||||||
RPCOperationKind::Answer(a) => match a.destructure() {
|
RPCOperationKind::Answer(a) => match a.destructure() {
|
||||||
RPCAnswerDetail::GetValueA(a) => a,
|
RPCAnswerDetail::GetValueA(a) => a,
|
||||||
_ => return Err(RPCError::invalid_format("not a getvalue answer")),
|
_ => return Ok(NetworkResult::invalid_message("not a getvalue answer")),
|
||||||
},
|
},
|
||||||
_ => return Err(RPCError::invalid_format("not an answer")),
|
_ => return Ok(NetworkResult::invalid_message("not an answer")),
|
||||||
};
|
};
|
||||||
|
|
||||||
let (value, peers, descriptor) = get_value_a.destructure();
|
let (value, peers, descriptor) = get_value_a.destructure();
|
||||||
|
|
||||||
|
// Validate peers returned are, in fact, closer to the key than the node we sent this to
|
||||||
|
let valid = match self.verify_peers_closer(vcrypto, target_node_id, key, &peers) {
|
||||||
|
Ok(v) => v,
|
||||||
|
Err(e) => {
|
||||||
|
if matches!(e, RPCError::Internal(_)) {
|
||||||
|
return Err(e);
|
||||||
|
}
|
||||||
|
return Ok(NetworkResult::invalid_message(
|
||||||
|
"missing cryptosystem in peers node ids",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if !valid {
|
||||||
|
return Ok(NetworkResult::invalid_message("non-closer peers returned"));
|
||||||
|
}
|
||||||
|
|
||||||
Ok(NetworkResult::value(Answer::new(
|
Ok(NetworkResult::value(Answer::new(
|
||||||
latency,
|
latency,
|
||||||
GetValueAnswer {
|
GetValueAnswer {
|
||||||
|
@ -62,7 +62,7 @@ impl RPCProcessor {
|
|||||||
) -> Result<NetworkResult<()>, RPCError> {
|
) -> Result<NetworkResult<()>, RPCError> {
|
||||||
// Make sure hop count makes sense
|
// Make sure hop count makes sense
|
||||||
if next_private_route.hop_count as usize > self.unlocked_inner.max_route_hop_count {
|
if next_private_route.hop_count as usize > self.unlocked_inner.max_route_hop_count {
|
||||||
return Err(RPCError::protocol(
|
return Ok(NetworkResult::invalid_message(
|
||||||
"Private route hop count too high to process",
|
"Private route hop count too high to process",
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
@ -110,9 +110,9 @@ impl RPCProcessor {
|
|||||||
// Now that things are valid, decrypt the routed operation with DEC(nonce, DH(the SR's public key, the PR's (or node's) secret)
|
// Now that things are valid, decrypt the routed operation with DEC(nonce, DH(the SR's public key, the PR's (or node's) secret)
|
||||||
// xxx: punish nodes that send messages that fail to decrypt eventually? How to do this for safety routes?
|
// xxx: punish nodes that send messages that fail to decrypt eventually? How to do this for safety routes?
|
||||||
let node_id_secret = self.routing_table.node_id_secret_key(remote_sr_pubkey.kind);
|
let node_id_secret = self.routing_table.node_id_secret_key(remote_sr_pubkey.kind);
|
||||||
let dh_secret = vcrypto
|
let Ok(dh_secret) = vcrypto.cached_dh(&remote_sr_pubkey.value, &node_id_secret) else {
|
||||||
.cached_dh(&remote_sr_pubkey.value, &node_id_secret)
|
return Ok(NetworkResult::invalid_message("dh failed for remote safety route for safety routed operation"));
|
||||||
.map_err(RPCError::protocol)?;
|
};
|
||||||
let body = match vcrypto.decrypt_aead(
|
let body = match vcrypto.decrypt_aead(
|
||||||
routed_operation.data(),
|
routed_operation.data(),
|
||||||
routed_operation.nonce(),
|
routed_operation.nonce(),
|
||||||
@ -183,19 +183,18 @@ impl RPCProcessor {
|
|||||||
|
|
||||||
// Now that things are valid, decrypt the routed operation with DEC(nonce, DH(the SR's public key, the PR's (or node's) secret)
|
// Now that things are valid, decrypt the routed operation with DEC(nonce, DH(the SR's public key, the PR's (or node's) secret)
|
||||||
// xxx: punish nodes that send messages that fail to decrypt eventually. How to do this for private routes?
|
// xxx: punish nodes that send messages that fail to decrypt eventually. How to do this for private routes?
|
||||||
let dh_secret = vcrypto
|
let Ok(dh_secret) = vcrypto.cached_dh(&remote_sr_pubkey.value, &secret_key) else {
|
||||||
.cached_dh(&remote_sr_pubkey.value, &secret_key)
|
return Ok(NetworkResult::invalid_message("dh failed for remote safety route for private routed operation"));
|
||||||
.map_err(RPCError::protocol)?;
|
};
|
||||||
let body = vcrypto
|
let Ok(body) = vcrypto
|
||||||
.decrypt_aead(
|
.decrypt_aead(
|
||||||
routed_operation.data(),
|
routed_operation.data(),
|
||||||
routed_operation.nonce(),
|
routed_operation.nonce(),
|
||||||
&dh_secret,
|
&dh_secret,
|
||||||
None,
|
None,
|
||||||
)
|
) else {
|
||||||
.map_err(RPCError::map_internal(
|
return Ok(NetworkResult::invalid_message("decryption of routed operation failed"));
|
||||||
"decryption of routed operation failed",
|
};
|
||||||
))?;
|
|
||||||
|
|
||||||
// Pass message to RPC system
|
// Pass message to RPC system
|
||||||
self.enqueue_private_routed_message(
|
self.enqueue_private_routed_message(
|
||||||
@ -401,37 +400,48 @@ impl RPCProcessor {
|
|||||||
SafetyRouteHops::Data(ref route_hop_data) => {
|
SafetyRouteHops::Data(ref route_hop_data) => {
|
||||||
// Decrypt the blob with DEC(nonce, DH(the SR's public key, this hop's secret)
|
// Decrypt the blob with DEC(nonce, DH(the SR's public key, this hop's secret)
|
||||||
let node_id_secret = self.routing_table.node_id_secret_key(crypto_kind);
|
let node_id_secret = self.routing_table.node_id_secret_key(crypto_kind);
|
||||||
let dh_secret = vcrypto
|
let Ok(dh_secret) = vcrypto
|
||||||
.cached_dh(&safety_route.public_key.value, &node_id_secret)
|
.cached_dh(&safety_route.public_key.value, &node_id_secret) else {
|
||||||
.map_err(RPCError::protocol)?;
|
return Ok(NetworkResult::invalid_message("dh failed for safety route hop"));
|
||||||
let mut dec_blob_data = vcrypto
|
};
|
||||||
|
let Ok(mut dec_blob_data) = vcrypto
|
||||||
.decrypt_aead(
|
.decrypt_aead(
|
||||||
&route_hop_data.blob,
|
&route_hop_data.blob,
|
||||||
&route_hop_data.nonce,
|
&route_hop_data.nonce,
|
||||||
&dh_secret,
|
&dh_secret,
|
||||||
None,
|
None,
|
||||||
)
|
)
|
||||||
.map_err(RPCError::protocol)?;
|
else {
|
||||||
|
return Ok(NetworkResult::invalid_message("failed to decrypt route hop data for safety route hop"));
|
||||||
|
};
|
||||||
|
|
||||||
// See if this is last hop in safety route, if so, we're decoding a PrivateRoute not a RouteHop
|
// See if this is last hop in safety route, if so, we're decoding a PrivateRoute not a RouteHop
|
||||||
let Some(dec_blob_tag) = dec_blob_data.pop() else {
|
let Some(dec_blob_tag) = dec_blob_data.pop() else {
|
||||||
return Ok(NetworkResult::invalid_message("no bytes in blob"));
|
return Ok(NetworkResult::invalid_message("no bytes in blob"));
|
||||||
};
|
};
|
||||||
|
|
||||||
let dec_blob_reader = RPCMessageData::new(dec_blob_data).get_reader()?;
|
let Ok(dec_blob_reader) = RPCMessageData::new(dec_blob_data).get_reader() else {
|
||||||
|
return Ok(NetworkResult::invalid_message("Failed to decode RPCMessageData from blob"));
|
||||||
|
};
|
||||||
|
|
||||||
// Decode the blob appropriately
|
// Decode the blob appropriately
|
||||||
if dec_blob_tag == 1 {
|
if dec_blob_tag == 1 {
|
||||||
// PrivateRoute
|
// PrivateRoute
|
||||||
let private_route = {
|
let private_route = {
|
||||||
let pr_reader = dec_blob_reader
|
let Ok(pr_reader) = dec_blob_reader
|
||||||
.get_root::<veilid_capnp::private_route::Reader>()
|
.get_root::<veilid_capnp::private_route::Reader>() else {
|
||||||
.map_err(RPCError::protocol)?;
|
return Ok(NetworkResult::invalid_message("failed to get private route reader for blob"));
|
||||||
decode_private_route(&pr_reader)?
|
};
|
||||||
|
let Ok(private_route) = decode_private_route(&pr_reader) else {
|
||||||
|
return Ok(NetworkResult::invalid_message("failed to decode private route"));
|
||||||
|
};
|
||||||
|
private_route
|
||||||
};
|
};
|
||||||
|
|
||||||
// Validate the private route
|
// Validate the private route
|
||||||
private_route.validate(self.crypto.clone()).map_err(RPCError::protocol)?;
|
if let Err(_) = private_route.validate(self.crypto.clone()) {
|
||||||
|
return Ok(NetworkResult::invalid_message("failed to validate private route"));
|
||||||
|
}
|
||||||
|
|
||||||
// Switching from full safety route to private route first hop
|
// Switching from full safety route to private route first hop
|
||||||
network_result_try!(
|
network_result_try!(
|
||||||
@ -445,14 +455,20 @@ impl RPCProcessor {
|
|||||||
} else if dec_blob_tag == 0 {
|
} else if dec_blob_tag == 0 {
|
||||||
// RouteHop
|
// RouteHop
|
||||||
let route_hop = {
|
let route_hop = {
|
||||||
let rh_reader = dec_blob_reader
|
let Ok(rh_reader) = dec_blob_reader
|
||||||
.get_root::<veilid_capnp::route_hop::Reader>()
|
.get_root::<veilid_capnp::route_hop::Reader>() else {
|
||||||
.map_err(RPCError::protocol)?;
|
return Ok(NetworkResult::invalid_message("failed to get route hop reader for blob"));
|
||||||
decode_route_hop(&rh_reader)?
|
};
|
||||||
|
let Ok(route_hop) = decode_route_hop(&rh_reader) else {
|
||||||
|
return Ok(NetworkResult::invalid_message("failed to decode route hop"));
|
||||||
|
};
|
||||||
|
route_hop
|
||||||
};
|
};
|
||||||
|
|
||||||
// Validate the route hop
|
// Validate the route hop
|
||||||
route_hop.validate(self.crypto.clone()).map_err(RPCError::protocol)?;
|
if let Err(_) = route_hop.validate(self.crypto.clone()) {
|
||||||
|
return Ok(NetworkResult::invalid_message("failed to validate route hop"));
|
||||||
|
}
|
||||||
|
|
||||||
// Continue the full safety route with another hop
|
// Continue the full safety route with another hop
|
||||||
network_result_try!(
|
network_result_try!(
|
||||||
|
@ -14,7 +14,6 @@ impl RPCProcessor {
|
|||||||
/// Because this leaks information about the identity of the node itself,
|
/// Because this leaks information about the identity of the node itself,
|
||||||
/// replying to this request received over a private route will leak
|
/// replying to this request received over a private route will leak
|
||||||
/// the identity of the node and defeat the private route.
|
/// the identity of the node and defeat the private route.
|
||||||
#[instrument(level = "trace", skip(self), ret, err)]
|
|
||||||
pub async fn rpc_call_set_value(
|
pub async fn rpc_call_set_value(
|
||||||
self,
|
self,
|
||||||
dest: Destination,
|
dest: Destination,
|
||||||
@ -25,18 +24,22 @@ impl RPCProcessor {
|
|||||||
send_descriptor: bool,
|
send_descriptor: bool,
|
||||||
) -> Result<NetworkResult<Answer<SetValueAnswer>>, RPCError> {
|
) -> Result<NetworkResult<Answer<SetValueAnswer>>, RPCError> {
|
||||||
// Ensure destination never has a private route
|
// Ensure destination never has a private route
|
||||||
if matches!(
|
// and get the target noderef so we can validate the response
|
||||||
dest,
|
let Some(target) = dest.target() else {
|
||||||
Destination::PrivateRoute {
|
|
||||||
private_route: _,
|
|
||||||
safety_selection: _
|
|
||||||
}
|
|
||||||
) {
|
|
||||||
return Err(RPCError::internal(
|
return Err(RPCError::internal(
|
||||||
"Never send set value requests over private routes",
|
"Never send set value requests over private routes",
|
||||||
));
|
));
|
||||||
}
|
};
|
||||||
|
|
||||||
|
// Get the target node id
|
||||||
|
let Some(vcrypto) = self.crypto.get(key.kind) else {
|
||||||
|
return Err(RPCError::internal("unsupported cryptosystem"));
|
||||||
|
};
|
||||||
|
let Some(target_node_id) = target.node_ids().get(key.kind) else {
|
||||||
|
return Err(RPCError::internal("No node id for crypto kind"));
|
||||||
|
};
|
||||||
|
|
||||||
|
// Send the setvalue question
|
||||||
let set_value_q = RPCOperationSetValueQ::new(
|
let set_value_q = RPCOperationSetValueQ::new(
|
||||||
key,
|
key,
|
||||||
subkey,
|
subkey,
|
||||||
@ -51,17 +54,11 @@ impl RPCProcessor {
|
|||||||
network_result_try!(self.get_destination_respond_to(&dest)?),
|
network_result_try!(self.get_destination_respond_to(&dest)?),
|
||||||
RPCQuestionDetail::SetValueQ(set_value_q),
|
RPCQuestionDetail::SetValueQ(set_value_q),
|
||||||
);
|
);
|
||||||
let Some(vcrypto) = self.crypto.get(key.kind) else {
|
|
||||||
return Err(RPCError::internal("unsupported cryptosystem"));
|
|
||||||
};
|
|
||||||
|
|
||||||
// Send the setvalue question
|
|
||||||
let question_context = QuestionContext::SetValue(ValidateSetValueContext {
|
let question_context = QuestionContext::SetValue(ValidateSetValueContext {
|
||||||
descriptor,
|
descriptor,
|
||||||
subkey,
|
subkey,
|
||||||
vcrypto,
|
vcrypto: vcrypto.clone(),
|
||||||
});
|
});
|
||||||
|
|
||||||
let waitable_reply = network_result_try!(
|
let waitable_reply = network_result_try!(
|
||||||
self.question(dest, question, Some(question_context))
|
self.question(dest, question, Some(question_context))
|
||||||
.await?
|
.await?
|
||||||
@ -78,13 +75,29 @@ impl RPCProcessor {
|
|||||||
let set_value_a = match kind {
|
let set_value_a = match kind {
|
||||||
RPCOperationKind::Answer(a) => match a.destructure() {
|
RPCOperationKind::Answer(a) => match a.destructure() {
|
||||||
RPCAnswerDetail::SetValueA(a) => a,
|
RPCAnswerDetail::SetValueA(a) => a,
|
||||||
_ => return Err(RPCError::invalid_format("not a setvalue answer")),
|
_ => return Ok(NetworkResult::invalid_message("not a setvalue answer")),
|
||||||
},
|
},
|
||||||
_ => return Err(RPCError::invalid_format("not an answer")),
|
_ => return Ok(NetworkResult::invalid_message("not an answer")),
|
||||||
};
|
};
|
||||||
|
|
||||||
let (set, value, peers) = set_value_a.destructure();
|
let (set, value, peers) = set_value_a.destructure();
|
||||||
|
|
||||||
|
// Validate peers returned are, in fact, closer to the key than the node we sent this to
|
||||||
|
let valid = match self.verify_peers_closer(vcrypto, target_node_id, key, &peers) {
|
||||||
|
Ok(v) => v,
|
||||||
|
Err(e) => {
|
||||||
|
if matches!(e, RPCError::Internal(_)) {
|
||||||
|
return Err(e);
|
||||||
|
}
|
||||||
|
return Ok(NetworkResult::invalid_message(
|
||||||
|
"missing cryptosystem in peers node ids",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if !valid {
|
||||||
|
return Ok(NetworkResult::invalid_message("non-closer peers returned"));
|
||||||
|
}
|
||||||
|
|
||||||
Ok(NetworkResult::value(Answer::new(
|
Ok(NetworkResult::value(Answer::new(
|
||||||
latency,
|
latency,
|
||||||
SetValueAnswer { set, value, peers },
|
SetValueAnswer { set, value, peers },
|
||||||
|
@ -119,9 +119,9 @@ impl RPCProcessor {
|
|||||||
let status_a = match kind {
|
let status_a = match kind {
|
||||||
RPCOperationKind::Answer(a) => match a.destructure() {
|
RPCOperationKind::Answer(a) => match a.destructure() {
|
||||||
RPCAnswerDetail::StatusA(a) => a,
|
RPCAnswerDetail::StatusA(a) => a,
|
||||||
_ => return Err(RPCError::invalid_format("not a status answer")),
|
_ => return Ok(NetworkResult::invalid_message("not a status answer")),
|
||||||
},
|
},
|
||||||
_ => return Err(RPCError::invalid_format("not an answer")),
|
_ => return Ok(NetworkResult::invalid_message("not an answer")),
|
||||||
};
|
};
|
||||||
let (a_node_status, sender_info) = status_a.destructure();
|
let (a_node_status, sender_info) = status_a.destructure();
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
/// The context of the do_get_value operation
|
/// The context of the outbound_get_value operation
|
||||||
struct DoGetValueContext {
|
struct OutboundGetValueContext {
|
||||||
/// The latest value of the subkey, may be the value passed in
|
/// The latest value of the subkey, may be the value passed in
|
||||||
pub value: Option<SignedValueData>,
|
pub value: Option<SignedValueData>,
|
||||||
/// The consensus count for the value we have received
|
/// The consensus count for the value we have received
|
||||||
@ -42,7 +42,7 @@ impl StorageManager {
|
|||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
let context = Arc::new(Mutex::new(DoGetValueContext {
|
let context = Arc::new(Mutex::new(OutboundGetValueContext {
|
||||||
value: last_subkey_result.value,
|
value: last_subkey_result.value,
|
||||||
value_count: 0,
|
value_count: 0,
|
||||||
descriptor: last_subkey_result.descriptor.clone(),
|
descriptor: last_subkey_result.descriptor.clone(),
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
/// The context of the do_get_value operation
|
/// The context of the outbound_set_value operation
|
||||||
struct DoSetValueContext {
|
struct OutboundSetValueContext {
|
||||||
/// The latest value of the subkey, may be the value passed in
|
/// The latest value of the subkey, may be the value passed in
|
||||||
pub value: SignedValueData,
|
pub value: SignedValueData,
|
||||||
/// The consensus count for the value we have received
|
/// The consensus count for the value we have received
|
||||||
@ -37,7 +37,7 @@ impl StorageManager {
|
|||||||
|
|
||||||
// Make do-set-value answer context
|
// Make do-set-value answer context
|
||||||
let schema = descriptor.schema()?;
|
let schema = descriptor.schema()?;
|
||||||
let context = Arc::new(Mutex::new(DoSetValueContext {
|
let context = Arc::new(Mutex::new(OutboundSetValueContext {
|
||||||
value,
|
value,
|
||||||
value_count: 0,
|
value_count: 0,
|
||||||
schema,
|
schema,
|
||||||
|
@ -1,74 +1,74 @@
|
|||||||
# # Routing context veilid tests
|
# Routing context veilid tests
|
||||||
|
|
||||||
# import veilid
|
import veilid
|
||||||
# import pytest
|
import pytest
|
||||||
# import asyncio
|
import asyncio
|
||||||
# import json
|
import json
|
||||||
# from . import *
|
from . import *
|
||||||
|
|
||||||
# ##################################################################
|
##################################################################
|
||||||
# BOGUS_KEY = veilid.TypedKey.from_value(veilid.CryptoKind.CRYPTO_KIND_VLD0, veilid.PublicKey.from_bytes(b' '))
|
BOGUS_KEY = veilid.TypedKey.from_value(veilid.CryptoKind.CRYPTO_KIND_VLD0, veilid.PublicKey.from_bytes(b' '))
|
||||||
|
|
||||||
# @pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
# async def test_get_dht_value_unopened(api_connection: veilid.VeilidAPI):
|
async def test_get_dht_value_unopened(api_connection: veilid.VeilidAPI):
|
||||||
# rc = await api_connection.new_routing_context()
|
rc = await api_connection.new_routing_context()
|
||||||
# async with rc:
|
async with rc:
|
||||||
# with pytest.raises(veilid.VeilidAPIError):
|
with pytest.raises(veilid.VeilidAPIError):
|
||||||
# out = await rc.get_dht_value(BOGUS_KEY, veilid.ValueSubkey(0), False)
|
out = await rc.get_dht_value(BOGUS_KEY, veilid.ValueSubkey(0), False)
|
||||||
|
|
||||||
|
|
||||||
# @pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
# async def test_open_dht_record_nonexistent_no_writer(api_connection: veilid.VeilidAPI):
|
async def test_open_dht_record_nonexistent_no_writer(api_connection: veilid.VeilidAPI):
|
||||||
# rc = await api_connection.new_routing_context()
|
rc = await api_connection.new_routing_context()
|
||||||
# async with rc:
|
async with rc:
|
||||||
# with pytest.raises(veilid.VeilidAPIError):
|
with pytest.raises(veilid.VeilidAPIError):
|
||||||
# out = await rc.open_dht_record(BOGUS_KEY, None)
|
out = await rc.open_dht_record(BOGUS_KEY, None)
|
||||||
|
|
||||||
# @pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
# async def test_close_dht_record_nonexistent(api_connection: veilid.VeilidAPI):
|
async def test_close_dht_record_nonexistent(api_connection: veilid.VeilidAPI):
|
||||||
# rc = await api_connection.new_routing_context()
|
rc = await api_connection.new_routing_context()
|
||||||
# async with rc:
|
async with rc:
|
||||||
# with pytest.raises(veilid.VeilidAPIError):
|
with pytest.raises(veilid.VeilidAPIError):
|
||||||
# await rc.close_dht_record(BOGUS_KEY)
|
await rc.close_dht_record(BOGUS_KEY)
|
||||||
|
|
||||||
# @pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
# async def test_delete_dht_record_nonexistent(api_connection: veilid.VeilidAPI):
|
async def test_delete_dht_record_nonexistent(api_connection: veilid.VeilidAPI):
|
||||||
# rc = await api_connection.new_routing_context()
|
rc = await api_connection.new_routing_context()
|
||||||
# async with rc:
|
async with rc:
|
||||||
# with pytest.raises(veilid.VeilidAPIError):
|
with pytest.raises(veilid.VeilidAPIError):
|
||||||
# await rc.delete_dht_record(BOGUS_KEY)
|
await rc.delete_dht_record(BOGUS_KEY)
|
||||||
|
|
||||||
# @pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
# async def test_create_delete_dht_record_simple(api_connection: veilid.VeilidAPI):
|
async def test_create_delete_dht_record_simple(api_connection: veilid.VeilidAPI):
|
||||||
# rc = await api_connection.new_routing_context()
|
rc = await api_connection.new_routing_context()
|
||||||
# async with rc:
|
async with rc:
|
||||||
# rec = await rc.create_dht_record(veilid.CryptoKind.CRYPTO_KIND_VLD0, veilid.DHTSchema.dflt(1))
|
rec = await rc.create_dht_record(veilid.CryptoKind.CRYPTO_KIND_VLD0, veilid.DHTSchema.dflt(1))
|
||||||
# await rc.close_dht_record(rec.key)
|
await rc.close_dht_record(rec.key)
|
||||||
# await rc.delete_dht_record(rec.key)
|
await rc.delete_dht_record(rec.key)
|
||||||
|
|
||||||
# @pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
# async def test_get_dht_value_nonexistent(api_connection: veilid.VeilidAPI):
|
async def test_get_dht_value_nonexistent(api_connection: veilid.VeilidAPI):
|
||||||
# rc = await api_connection.new_routing_context()
|
rc = await api_connection.new_routing_context()
|
||||||
# async with rc:
|
async with rc:
|
||||||
# rec = await rc.create_dht_record(veilid.CryptoKind.CRYPTO_KIND_VLD0, veilid.DHTSchema.dflt(1))
|
rec = await rc.create_dht_record(veilid.CryptoKind.CRYPTO_KIND_VLD0, veilid.DHTSchema.dflt(1))
|
||||||
# assert await rc.get_dht_value(rec.key, 0, False) == None
|
assert await rc.get_dht_value(rec.key, 0, False) == None
|
||||||
# await rc.close_dht_record(rec.key)
|
await rc.close_dht_record(rec.key)
|
||||||
# await rc.delete_dht_record(rec.key)
|
await rc.delete_dht_record(rec.key)
|
||||||
|
|
||||||
# @pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
# async def test_set_get_dht_value(api_connection: veilid.VeilidAPI):
|
async def test_set_get_dht_value(api_connection: veilid.VeilidAPI):
|
||||||
# rc = await api_connection.new_routing_context()
|
rc = await api_connection.new_routing_context()
|
||||||
# async with rc:
|
async with rc:
|
||||||
# rec = await rc.create_dht_record(veilid.CryptoKind.CRYPTO_KIND_VLD0, veilid.DHTSchema.dflt(1))
|
rec = await rc.create_dht_record(veilid.CryptoKind.CRYPTO_KIND_VLD0, veilid.DHTSchema.dflt(1))
|
||||||
|
|
||||||
# vd = await rc.set_dht_value(rec.key, 0, b"BLAH BLAH BLAH")
|
vd = await rc.set_dht_value(rec.key, 0, b"BLAH BLAH BLAH")
|
||||||
# assert vd != None
|
assert vd != None
|
||||||
|
|
||||||
# vd2 = await rc.get_dht_value(rec.key, 0, False)
|
vd2 = await rc.get_dht_value(rec.key, 0, False)
|
||||||
# assert vd2 != None
|
assert vd2 != None
|
||||||
|
|
||||||
# assert vd == vd2
|
assert vd == vd2
|
||||||
|
|
||||||
# await rc.close_dht_record(rec.key)
|
await rc.close_dht_record(rec.key)
|
||||||
# await rc.delete_dht_record(rec.key)
|
await rc.delete_dht_record(rec.key)
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user