route spec store work

This commit is contained in:
John Smith
2022-11-13 19:46:10 -05:00
parent 4a9d516f32
commit 5935ca9e41
9 changed files with 441 additions and 212 deletions

View File

@@ -141,3 +141,184 @@ impl fmt::Display for Destination {
}
}
}
impl RPCProcessor {
/// Convert the 'Destination' into a 'RespondTo' for a response
pub(super) fn get_destination_respond_to(
&self,
dest: &Destination,
) -> Result<NetworkResult<RespondTo>, RPCError> {
let routing_table = self.routing_table();
let rss = routing_table.route_spec_store();
match dest {
Destination::Direct {
target,
safety_selection,
} => match safety_selection {
SafetySelection::Unsafe(_) => {
// Sent directly with no safety route, can respond directly
Ok(NetworkResult::value(RespondTo::Sender))
}
SafetySelection::Safe(safety_spec) => {
// Sent directly but with a safety route, respond to private route
let Some(pr_key) = rss
.get_private_route_for_safety_spec(safety_spec, &[target.node_id()])
.map_err(RPCError::internal)? else {
return Ok(NetworkResult::no_connection_other("no private route for response at this time"));
};
// Get the assembled route for response
let private_route = rss
.assemble_private_route(&pr_key, None)
.map_err(RPCError::internal)?;
Ok(NetworkResult::Value(RespondTo::PrivateRoute(private_route)))
}
},
Destination::Relay {
relay,
target,
safety_selection,
} => match safety_selection {
SafetySelection::Unsafe(_) => {
// Sent via a relay with no safety route, can respond directly
Ok(NetworkResult::value(RespondTo::Sender))
}
SafetySelection::Safe(safety_spec) => {
// Sent via a relay but with a safety route, respond to private route
let Some(pr_key) = rss
.get_private_route_for_safety_spec(safety_spec, &[relay.node_id(), *target])
.map_err(RPCError::internal)? else {
return Ok(NetworkResult::no_connection_other("no private route for response at this time"));
};
// Get the assembled route for response
let private_route = rss
.assemble_private_route(&pr_key, None)
.map_err(RPCError::internal)?;
Ok(NetworkResult::Value(RespondTo::PrivateRoute(private_route)))
}
},
Destination::PrivateRoute {
private_route,
safety_selection,
} => {
let Some(pr_first_hop) = &private_route.first_hop else {
return Err(RPCError::internal("destination private route must have first_hop"));
};
match safety_selection {
SafetySelection::Unsafe(_) => {
// Sent to a private route with no safety route, use a stub safety route for the response
// Determine if we can use optimized nodeinfo
let route_node = match rss
.has_remote_private_route_seen_our_node_info(&private_route.public_key)
{
true => RouteNode::NodeId(NodeId::new(routing_table.node_id())),
false => RouteNode::PeerInfo(
routing_table.get_own_peer_info(RoutingDomain::PublicInternet),
),
};
Ok(NetworkResult::value(RespondTo::PrivateRoute(
PrivateRoute::new_stub(routing_table.node_id(), route_node),
)))
}
SafetySelection::Safe(safety_spec) => {
// Sent directly but with a safety route, respond to private route
let avoid_node_id = match &pr_first_hop.node {
RouteNode::NodeId(n) => n.key,
RouteNode::PeerInfo(p) => p.node_id.key,
};
let Some(pr_key) = rss
.get_private_route_for_safety_spec(safety_spec, &[avoid_node_id])
.map_err(RPCError::internal)? else {
return Ok(NetworkResult::no_connection_other("no private route for response at this time"));
};
// Get the assembled route for response
let private_route = rss
.assemble_private_route(&pr_key, None)
.map_err(RPCError::internal)?;
Ok(NetworkResult::Value(RespondTo::PrivateRoute(private_route)))
}
}
}
}
}
/// Convert the 'RespondTo' into a 'Destination' for a response
pub(super) fn get_respond_to_destination(
&self,
request: &RPCMessage,
) -> NetworkResult<Destination> {
// Get the question 'respond to'
let respond_to = match request.operation.kind() {
RPCOperationKind::Question(q) => q.respond_to(),
_ => {
panic!("not a question");
}
};
// To where should we respond?
match respond_to {
RespondTo::Sender => {
// Parse out the header detail from the question
let detail = match &request.header.detail {
RPCMessageHeaderDetail::Direct(detail) => detail,
RPCMessageHeaderDetail::SafetyRouted(_)
| RPCMessageHeaderDetail::PrivateRouted(_) => {
// If this was sent via a private route, we don't know what the sender was, so drop this
return NetworkResult::invalid_message(
"can't respond directly to non-direct question",
);
}
};
// Reply directly to the request's source
let sender_id = detail.envelope.get_sender_id();
// This may be a different node's reference than the 'sender' in the case of a relay
let peer_noderef = detail.peer_noderef.clone();
// If the sender_id is that of the peer, then this is a direct reply
// else it is a relayed reply through the peer
if peer_noderef.node_id() == sender_id {
NetworkResult::value(Destination::direct(peer_noderef))
} else {
NetworkResult::value(Destination::relay(peer_noderef, sender_id))
}
}
RespondTo::PrivateRoute(pr) => {
match &request.header.detail {
RPCMessageHeaderDetail::Direct(_) => {
// If this was sent directly, we should only ever respond directly
return NetworkResult::invalid_message(
"not responding to private route from direct question",
);
}
RPCMessageHeaderDetail::SafetyRouted(detail) => {
// If this was sent via a safety route, but not received over our private route, don't respond with a safety route,
// it would give away which safety routes belong to this node
NetworkResult::value(Destination::private_route(
pr.clone(),
SafetySelection::Unsafe(detail.sequencing),
))
}
RPCMessageHeaderDetail::PrivateRouted(detail) => {
// If this was received over our private route, it's okay to respond to a private route via our safety route
NetworkResult::value(Destination::private_route(
pr.clone(),
SafetySelection::Safe(detail.safety_spec.clone()),
))
}
}
}
}
}
}

View File

@@ -792,73 +792,6 @@ impl RPCProcessor {
Ok(NetworkResult::value(()))
}
// Convert the 'RespondTo' into a 'Destination' for a response
fn get_respond_to_destination(&self, request: &RPCMessage) -> NetworkResult<Destination> {
// Get the question 'respond to'
let respond_to = match request.operation.kind() {
RPCOperationKind::Question(q) => q.respond_to(),
_ => {
panic!("not a question");
}
};
// To where should we respond?
match respond_to {
RespondTo::Sender => {
// Parse out the header detail from the question
let detail = match &request.header.detail {
RPCMessageHeaderDetail::Direct(detail) => detail,
RPCMessageHeaderDetail::SafetyRouted(_)
| RPCMessageHeaderDetail::PrivateRouted(_) => {
// If this was sent via a private route, we don't know what the sender was, so drop this
return NetworkResult::invalid_message(
"can't respond directly to non-direct question",
);
}
};
// Reply directly to the request's source
let sender_id = detail.envelope.get_sender_id();
// This may be a different node's reference than the 'sender' in the case of a relay
let peer_noderef = detail.peer_noderef.clone();
// If the sender_id is that of the peer, then this is a direct reply
// else it is a relayed reply through the peer
if peer_noderef.node_id() == sender_id {
NetworkResult::value(Destination::direct(peer_noderef))
} else {
NetworkResult::value(Destination::relay(peer_noderef, sender_id))
}
}
RespondTo::PrivateRoute(pr) => {
match &request.header.detail {
RPCMessageHeaderDetail::Direct(_) => {
// If this was sent directly, we should only ever respond directly
return NetworkResult::invalid_message(
"not responding to private route from direct question",
);
}
RPCMessageHeaderDetail::SafetyRouted(detail) => {
// If this was sent via a safety route, but not received over our private route, don't respond with a safety route,
// it would give away which safety routes belong to this node
NetworkResult::value(Destination::private_route(
pr.clone(),
SafetySelection::Unsafe(detail.sequencing),
))
}
RPCMessageHeaderDetail::PrivateRouted(detail) => {
// If this was received over our private route, it's okay to respond to a private route via our safety route
NetworkResult::value(Destination::private_route(
pr.clone(),
SafetySelection::Safe(detail.safety_spec.clone()),
))
}
}
}
}
}
// Issue a reply over the network, possibly using an anonymized route
// The request must want a response, or this routine fails
#[instrument(level = "debug", skip(self, request, answer), err)]

View File

@@ -1,53 +0,0 @@
use super::*;
#[derive(Debug, Clone)]
pub enum Origin {
Sender,
PrivateRoute(PrivateRoute),
}
impl Origin {
pub fn sender() -> Self {
Self::Sender
}
pub fn private_route(private_route: PrivateRoute) -> Self {
Self::PrivateRoute(private_route)
}
pub fn into_respond_to(self, destination: &Destination) -> Result<RespondTo, RPCError> {
match self {
Self::Sender => {
let peer = match destination {
Destination::Direct {
target,
safety_route_spec,
} => todo!(),
Destination::Relay {
relay,
target,
safety_route_spec,
} => todo!(),
Destination::PrivateRoute {
private_route,
safety_route_spec,
} => todo!(),
};
let routing_table = peer.routing_table();
let routing_domain = peer.best_routing_domain();
// Send some signed node info along with the question if this node needs to be replied to
if routing_table.has_valid_own_node_info()
&& !peer.has_seen_our_node_info(routing_domain)
{
let our_sni = self
.routing_table()
.get_own_signed_node_info(routing_domain);
RespondTo::Sender(Some(our_sni))
} else {
RespondTo::Sender(None)
}
}
Self::PrivateRoute(pr) => RespondTo::PrivateRoute(pr),
}
}
}

View File

@@ -10,7 +10,10 @@ impl RPCProcessor {
message: Vec<u8>,
) -> Result<NetworkResult<Answer<Vec<u8>>>, RPCError> {
let app_call_q = RPCOperationAppCallQ { message };
let question = RPCQuestion::new(RespondTo::Sender, RPCQuestionDetail::AppCallQ(app_call_q));
let question = RPCQuestion::new(
network_result_try!(self.get_destination_respond_to(&dest)?),
RPCQuestionDetail::AppCallQ(app_call_q),
);
// Send the app call question
let waitable_reply = network_result_try!(self.question(dest, question).await?);

View File

@@ -28,7 +28,10 @@ impl RPCProcessor {
let find_node_q_detail =
RPCQuestionDetail::FindNodeQ(RPCOperationFindNodeQ { node_id: key });
let find_node_q = RPCQuestion::new(RespondTo::Sender, find_node_q_detail);
let find_node_q = RPCQuestion::new(
network_result_try!(self.get_destination_respond_to(&dest)?),
find_node_q_detail,
);
// Send the find_node request
let waitable_reply = network_result_try!(self.question(dest, find_node_q).await?);

View File

@@ -70,7 +70,10 @@ impl RPCProcessor {
};
let status_q = RPCOperationStatusQ { node_status };
let question = RPCQuestion::new(RespondTo::Sender, RPCQuestionDetail::StatusQ(status_q));
let question = RPCQuestion::new(
network_result_try!(self.get_destination_respond_to(&dest)?),
RPCQuestionDetail::StatusQ(status_q),
);
// Send the info request
let waitable_reply = network_result_try!(self.question(dest.clone(), question).await?);