private route loopbacks
This commit is contained in:
		| @@ -434,15 +434,6 @@ impl DiscoveryContext { | ||||
|             return Ok(true); | ||||
|         } | ||||
|  | ||||
|         // XXX: is this necessary? | ||||
|         // Redo our external_1 dial info detection because a failed port mapping attempt | ||||
|         // may cause it to become invalid | ||||
|         // Get our external address from some fast node, call it node 1 | ||||
|         // if !self.protocol_get_external_address_1().await { | ||||
|         //     // If we couldn't get an external address, then we should just try the whole network class detection again later | ||||
|         //     return Ok(false); | ||||
|         // } | ||||
|  | ||||
|         // Get the external dial info for our use here | ||||
|         let (node_1, external_1_dial_info, external_1_address, protocol_type, address_type) = { | ||||
|             let inner = self.inner.lock(); | ||||
|   | ||||
| @@ -864,7 +864,20 @@ impl RouteSpecStore { | ||||
|                     safety_selection, | ||||
|                 } | ||||
|             } else { | ||||
|                 let target = rsd.hop_node_refs[rsd.hops.len() - 2].clone(); | ||||
|                 // let target = rsd.hop_node_refs[rsd.hops.len() - 2].clone(); | ||||
|                 // let safety_spec = SafetySpec { | ||||
|                 //     preferred_route: Some(key.clone()), | ||||
|                 //     hop_count, | ||||
|                 //     stability, | ||||
|                 //     sequencing, | ||||
|                 // }; | ||||
|                 // let safety_selection = SafetySelection::Safe(safety_spec); | ||||
|  | ||||
|                 // Destination::Direct { | ||||
|                 //     target, | ||||
|                 //     safety_selection, | ||||
|                 // } | ||||
|  | ||||
|                 let safety_spec = SafetySpec { | ||||
|                     preferred_route: Some(key.clone()), | ||||
|                     hop_count, | ||||
| @@ -873,38 +886,22 @@ impl RouteSpecStore { | ||||
|                 }; | ||||
|                 let safety_selection = SafetySelection::Safe(safety_spec); | ||||
|  | ||||
|                 Destination::Direct { | ||||
|                     target, | ||||
|                 Destination::PrivateRoute { | ||||
|                     private_route, | ||||
|                     safety_selection, | ||||
|                 } | ||||
|             } | ||||
|         }; | ||||
|  | ||||
|         // Test with ping to end | ||||
|         let cur_ts = intf::get_timestamp(); | ||||
|         let res = match rpc_processor.rpc_call_status(dest).await? { | ||||
|         // Test with double-round trip ping to self | ||||
|         let _res = match rpc_processor.rpc_call_status(dest).await? { | ||||
|             NetworkResult::Value(v) => v, | ||||
|             _ => { | ||||
|                 // // Do route stats for single hop route test because it | ||||
|                 // // won't get stats for the route since it's done Direct | ||||
|                 // if matches!(safety_selection, SafetySelection::Unsafe(_)) { | ||||
|                 //     self.with_route_stats(cur_ts, &key, |s| s.record_question_lost()); | ||||
|                 // } | ||||
|  | ||||
|                 // Did not error, but did not come back, just return false | ||||
|                 return Ok(false); | ||||
|             } | ||||
|         }; | ||||
|  | ||||
|         // // Do route stats for single hop route test because it | ||||
|         // // won't get stats for the route since it's done Direct | ||||
|         // if matches!(safety_selection, SafetySelection::Unsafe(_)) { | ||||
|         //     self.with_route_stats(cur_ts, &key, |s| { | ||||
|         //         s.record_tested(cur_ts); | ||||
|         //         s.record_latency(res.latency); | ||||
|         //     }); | ||||
|         // } | ||||
|  | ||||
|         Ok(true) | ||||
|     } | ||||
|  | ||||
| @@ -1065,14 +1062,21 @@ impl RouteSpecStore { | ||||
|             bail!("compiled private route should have first hop"); | ||||
|         }; | ||||
|  | ||||
|         // Get the safety route to use from the spec | ||||
|         let avoid_node_id = match &pr_first_hop.node { | ||||
|             RouteNode::NodeId(n) => n.key, | ||||
|             RouteNode::PeerInfo(p) => p.node_id.key, | ||||
|         }; | ||||
|         let Some(sr_pubkey) = self.get_route_for_safety_spec_inner(inner, rti, &safety_spec, Direction::Outbound.into(), &[avoid_node_id])? else { | ||||
|             // No safety route could be found for this spec | ||||
|             return Ok(None); | ||||
|         // If the safety route requested is also the private route, this is a loopback test, just accept it | ||||
|         let sr_pubkey = if safety_spec.preferred_route == Some(private_route.public_key) { | ||||
|             // Private route is also safety route during loopback test | ||||
|             private_route.public_key | ||||
|         } else { | ||||
|             // Get the safety route to use from the spec | ||||
|             let avoid_node_id = match &pr_first_hop.node { | ||||
|                 RouteNode::NodeId(n) => n.key, | ||||
|                 RouteNode::PeerInfo(p) => p.node_id.key, | ||||
|             }; | ||||
|             let Some(sr_pubkey) = self.get_route_for_safety_spec_inner(inner, rti, &safety_spec, Direction::Outbound.into(), &[avoid_node_id])? else { | ||||
|                 // No safety route could be found for this spec | ||||
|                 return Ok(None); | ||||
|             }; | ||||
|             sr_pubkey | ||||
|         }; | ||||
|         let safety_rsd = Self::detail_mut(inner, &sr_pubkey).unwrap(); | ||||
|  | ||||
|   | ||||
| @@ -228,18 +228,29 @@ impl RPCProcessor { | ||||
|                         ))) | ||||
|                     } | ||||
|                     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, | ||||
|                         }; | ||||
|                         // Sent to a private route via a safety route, respond to private route | ||||
|  | ||||
|                         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")); | ||||
|                         // Check for loopback test | ||||
|                         let pr_key = if safety_spec.preferred_route | ||||
|                             == Some(private_route.public_key) | ||||
|                         { | ||||
|                             // Private route is also safety route during loopback test | ||||
|                             private_route.public_key | ||||
|                         } else { | ||||
|                             // Get the privat route to respond to that matches the safety route spec we sent the request with | ||||
|                             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")); | ||||
|                                 }; | ||||
|                             pr_key | ||||
|                         }; | ||||
|  | ||||
|                         // Get the assembled route for response | ||||
|                         let private_route = rss | ||||
|                             .assemble_private_route(&pr_key, None) | ||||
|   | ||||
| @@ -4,16 +4,17 @@ impl RPCProcessor { | ||||
|     #[instrument(level = "trace", skip_all, err)] | ||||
|     async fn process_route_safety_route_hop( | ||||
|         &self, | ||||
|         route: RPCOperationRoute, | ||||
|         routed_operation: RoutedOperation, | ||||
|         route_hop: RouteHop, | ||||
|         safety_route: SafetyRoute, | ||||
|     ) -> Result<NetworkResult<()>, RPCError> { | ||||
|         // Make sure hop count makes sense | ||||
|         if route.safety_route.hop_count as usize > self.unlocked_inner.max_route_hop_count { | ||||
|         if safety_route.hop_count as usize > self.unlocked_inner.max_route_hop_count { | ||||
|             return Ok(NetworkResult::invalid_message( | ||||
|                 "Safety route hop count too high to process", | ||||
|             )); | ||||
|         } | ||||
|         if route.safety_route.hop_count == 0 { | ||||
|         if safety_route.hop_count == 0 { | ||||
|             return Ok(NetworkResult::invalid_message( | ||||
|                 "Safety route hop count should not be zero if there are more hops", | ||||
|             )); | ||||
| @@ -55,11 +56,11 @@ impl RPCProcessor { | ||||
|         // Pass along the route | ||||
|         let next_hop_route = RPCOperationRoute { | ||||
|             safety_route: SafetyRoute { | ||||
|                 public_key: route.safety_route.public_key, | ||||
|                 hop_count: route.safety_route.hop_count - 1, | ||||
|                 public_key: safety_route.public_key, | ||||
|                 hop_count: safety_route.hop_count - 1, | ||||
|                 hops: SafetyRouteHops::Data(route_hop.next_hop.unwrap()), | ||||
|             }, | ||||
|             operation: route.operation, | ||||
|             operation: routed_operation, | ||||
|         }; | ||||
|         let next_hop_route_stmt = RPCStatement::new(RPCStatementDetail::Route(next_hop_route)); | ||||
|  | ||||
| @@ -135,7 +136,7 @@ impl RPCProcessor { | ||||
|         &self, | ||||
|         detail: RPCMessageHeaderDetailDirect, | ||||
|         routed_operation: RoutedOperation, | ||||
|         remote_safety_route: &SafetyRoute, | ||||
|         remote_sr_pubkey: DHTKey, | ||||
|     ) -> Result<NetworkResult<()>, RPCError> { | ||||
|         // Get sequencing preference | ||||
|         let sequencing = if detail | ||||
| @@ -153,7 +154,7 @@ impl RPCProcessor { | ||||
|         let node_id_secret = self.routing_table.node_id_secret(); | ||||
|         let dh_secret = self | ||||
|             .crypto | ||||
|             .cached_dh(&remote_safety_route.public_key, &node_id_secret) | ||||
|             .cached_dh(&remote_sr_pubkey, &node_id_secret) | ||||
|             .map_err(RPCError::protocol)?; | ||||
|         let body = match Crypto::decrypt_aead( | ||||
|             &routed_operation.data, | ||||
| @@ -168,7 +169,7 @@ impl RPCProcessor { | ||||
|         }; | ||||
|          | ||||
|         // Pass message to RPC system | ||||
|         self.enqueue_safety_routed_message(remote_safety_route.public_key, sequencing, body) | ||||
|         self.enqueue_safety_routed_message(remote_sr_pubkey, sequencing, body) | ||||
|             .map_err(RPCError::internal)?; | ||||
|  | ||||
|         Ok(NetworkResult::value(())) | ||||
| @@ -180,8 +181,8 @@ impl RPCProcessor { | ||||
|         &self, | ||||
|         detail: RPCMessageHeaderDetailDirect, | ||||
|         routed_operation: RoutedOperation, | ||||
|         remote_safety_route: &SafetyRoute, | ||||
|         private_route: &PrivateRoute, | ||||
|         remote_sr_pubkey: DHTKey, | ||||
|         pr_pubkey: DHTKey, | ||||
|     ) -> Result<NetworkResult<()>, RPCError> { | ||||
|         // Get sender id | ||||
|         let sender_id = detail.envelope.get_sender_id(); | ||||
| @@ -190,7 +191,7 @@ impl RPCProcessor { | ||||
|         let rss = self.routing_table.route_spec_store(); | ||||
|         let Some((secret_key, safety_spec)) = rss | ||||
|             .validate_signatures( | ||||
|                 &private_route.public_key, | ||||
|                 &pr_pubkey, | ||||
|                 &routed_operation.signatures, | ||||
|                 &routed_operation.data, | ||||
|                 sender_id, | ||||
| @@ -204,7 +205,7 @@ impl RPCProcessor { | ||||
|         // xxx: punish nodes that send messages that fail to decrypt eventually. How to do this for private routes? | ||||
|         let dh_secret = self | ||||
|             .crypto | ||||
|             .cached_dh(&remote_safety_route.public_key, &secret_key) | ||||
|             .cached_dh(&remote_sr_pubkey, &secret_key) | ||||
|             .map_err(RPCError::protocol)?; | ||||
|         let body = Crypto::decrypt_aead( | ||||
|             &routed_operation.data, | ||||
| @@ -217,7 +218,7 @@ impl RPCProcessor { | ||||
|         ))?; | ||||
|  | ||||
|         // Pass message to RPC system | ||||
|         self.enqueue_private_routed_message(remote_safety_route.public_key, private_route.public_key, safety_spec, body) | ||||
|         self.enqueue_private_routed_message(remote_sr_pubkey, pr_pubkey, safety_spec, body) | ||||
|             .map_err(RPCError::internal)?; | ||||
|  | ||||
|         Ok(NetworkResult::value(())) | ||||
| @@ -228,65 +229,123 @@ impl RPCProcessor { | ||||
|         &self, | ||||
|         detail: RPCMessageHeaderDetailDirect, | ||||
|         routed_operation: RoutedOperation, | ||||
|         safety_route: &SafetyRoute, | ||||
|         private_route: &PrivateRoute, | ||||
|         remote_sr_pubkey: DHTKey, | ||||
|         pr_pubkey: DHTKey, | ||||
|     ) -> Result<NetworkResult<()>, RPCError> { | ||||
|         // Make sure hop count makes sense | ||||
|         if safety_route.hop_count != 0 { | ||||
|             return Ok(NetworkResult::invalid_message( | ||||
|                 "Safety hop count should be zero if switched to private route", | ||||
|             )); | ||||
|         } | ||||
|         if private_route.hop_count != 0 { | ||||
|             return Ok(NetworkResult::invalid_message( | ||||
|                 "Private route hop count should be zero if we are at the end", | ||||
|             )); | ||||
|         } | ||||
|  | ||||
|         | ||||
|         // If the private route public key is our node id, then this was sent via safety route to our node directly | ||||
|         // so there will be no signatures to validate | ||||
|         if private_route.public_key == self.routing_table.node_id() { | ||||
|         if pr_pubkey == self.routing_table.node_id() { | ||||
|             // The private route was a stub | ||||
|             self.process_safety_routed_operation(detail, routed_operation, safety_route) | ||||
|             self.process_safety_routed_operation(detail, routed_operation, remote_sr_pubkey) | ||||
|         } else { | ||||
|             // Both safety and private routes used, should reply with a safety route | ||||
|             self.process_private_routed_operation( | ||||
|                 detail, | ||||
|                 routed_operation, | ||||
|                 safety_route, | ||||
|                 private_route, | ||||
|                 remote_sr_pubkey, | ||||
|                 pr_pubkey, | ||||
|             ) | ||||
|         } | ||||
|     } | ||||
|     #[instrument(level = "trace", skip_all, err)] | ||||
|     pub(crate) async fn process_private_route_first_hop( | ||||
|         &self, | ||||
|         operation: RoutedOperation, | ||||
|         mut routed_operation: RoutedOperation, | ||||
|         sr_pubkey: DHTKey, | ||||
|         private_route: &PrivateRoute, | ||||
|         mut private_route: PrivateRoute, | ||||
|     ) -> Result<NetworkResult<()>, RPCError> { | ||||
|         let PrivateRouteHops::FirstHop(pr_first_hop) = &private_route.hops else { | ||||
|         let Some(pr_first_hop) = private_route.pop_first_hop() else { | ||||
|             return Ok(NetworkResult::invalid_message("switching from safety route to private route requires first hop")); | ||||
|         }; | ||||
|  | ||||
|         // Check for loopback test where private route is the same as safety route | ||||
|         if sr_pubkey == private_route.public_key { | ||||
|             // If so, we're going to turn this thing right around without transiting the network | ||||
|             let PrivateRouteHops::Data(route_hop_data) = private_route.hops else { | ||||
|                 return Ok(NetworkResult::invalid_message("Loopback test requires hops")); | ||||
|             }; | ||||
|  | ||||
|             // Decrypt route hop data | ||||
|             let route_hop = network_result_try!(self.decrypt_private_route_hop_data(&route_hop_data, &private_route.public_key, &mut routed_operation)?); | ||||
|                      | ||||
|             // Ensure hop count > 0 | ||||
|             if private_route.hop_count == 0 { | ||||
|                 return Ok(NetworkResult::invalid_message( | ||||
|                     "route should not be at the end", | ||||
|                 )); | ||||
|             } | ||||
|  | ||||
|             // Make next PrivateRoute and pass it on | ||||
|             return self.process_route_private_route_hop( | ||||
|                 routed_operation, | ||||
|                 route_hop.node, | ||||
|                 sr_pubkey, | ||||
|                 PrivateRoute { | ||||
|                     public_key: private_route.public_key, | ||||
|                     hop_count: private_route.hop_count - 1, | ||||
|                     hops: route_hop | ||||
|                         .next_hop | ||||
|                         .map(|rhd| PrivateRouteHops::Data(rhd)) | ||||
|                         .unwrap_or(PrivateRouteHops::Empty), | ||||
|                 }, | ||||
|             ) | ||||
|             .await; | ||||
|         } | ||||
|  | ||||
|         // Switching to private route from safety route | ||||
|         self.process_route_private_route_hop( | ||||
|             operation, | ||||
|             pr_first_hop.node.clone(), | ||||
|             routed_operation, | ||||
|             pr_first_hop, | ||||
|             sr_pubkey, | ||||
|             PrivateRoute { | ||||
|                 public_key: private_route.public_key, | ||||
|                 hop_count: private_route.hop_count - 1, | ||||
|                 hops: pr_first_hop | ||||
|                     .next_hop | ||||
|                     .clone() | ||||
|                     .map(|rhd| PrivateRouteHops::Data(rhd)) | ||||
|                     .unwrap_or(PrivateRouteHops::Empty), | ||||
|             }, | ||||
|             private_route, | ||||
|         ) | ||||
|         .await | ||||
|     } | ||||
|  | ||||
|     /// Decrypt route hop data and sign routed operation | ||||
|     pub(crate) fn decrypt_private_route_hop_data(&self, route_hop_data: &RouteHopData, pr_pubkey: &DHTKey, route_operation: &mut RoutedOperation) -> Result<NetworkResult<RouteHop>, RPCError> | ||||
|     { | ||||
|         // Decrypt the blob with DEC(nonce, DH(the PR's public key, this hop's secret) | ||||
|         let node_id_secret = self.routing_table.node_id_secret(); | ||||
|         let dh_secret = self | ||||
|             .crypto | ||||
|             .cached_dh(&pr_pubkey, &node_id_secret) | ||||
|             .map_err(RPCError::protocol)?; | ||||
|         let dec_blob_data = match Crypto::decrypt_aead( | ||||
|             &route_hop_data.blob, | ||||
|             &route_hop_data.nonce, | ||||
|             &dh_secret, | ||||
|             None, | ||||
|         ) { | ||||
|             Ok(v) => v, | ||||
|             Err(e) => { | ||||
|                 return Ok(NetworkResult::invalid_message(format!("unable to decrypt private route hop data: {}", e))); | ||||
|             } | ||||
|         }; | ||||
|         let dec_blob_reader = RPCMessageData::new(dec_blob_data).get_reader()?; | ||||
|  | ||||
|         // Decode next RouteHop | ||||
|         let route_hop = { | ||||
|             let rh_reader = dec_blob_reader | ||||
|                 .get_root::<veilid_capnp::route_hop::Reader>() | ||||
|                 .map_err(RPCError::protocol)?; | ||||
|             decode_route_hop(&rh_reader)? | ||||
|         }; | ||||
|  | ||||
|         // Sign the operation if this is not our last hop | ||||
|         // as the last hop is already signed by the envelope | ||||
|         if route_hop.next_hop.is_some() { | ||||
|             let node_id = self.routing_table.node_id(); | ||||
|             let node_id_secret = self.routing_table.node_id_secret(); | ||||
|             let sig = sign(&node_id, &node_id_secret, &route_operation.data) | ||||
|                 .map_err(RPCError::internal)?; | ||||
|             route_operation.signatures.push(sig); | ||||
|         } | ||||
|  | ||||
|         Ok(NetworkResult::value(route_hop)) | ||||
|     } | ||||
|  | ||||
|     #[instrument(level = "trace", skip(self, msg), ret, err)] | ||||
|     pub(crate) async fn process_route( | ||||
|         &self, | ||||
| @@ -322,14 +381,14 @@ impl RPCProcessor { | ||||
|         // See what kind of safety route we have going on here | ||||
|         match route.safety_route.hops { | ||||
|             // There is a safety route hop | ||||
|             SafetyRouteHops::Data(ref d) => { | ||||
|             SafetyRouteHops::Data(ref route_hop_data) => { | ||||
|                 // 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(); | ||||
|                 let dh_secret = self | ||||
|                     .crypto | ||||
|                     .cached_dh(&route.safety_route.public_key, &node_id_secret) | ||||
|                     .map_err(RPCError::protocol)?; | ||||
|                 let mut dec_blob_data = Crypto::decrypt_aead(&d.blob, &d.nonce, &dh_secret, None) | ||||
|                 let mut dec_blob_data = Crypto::decrypt_aead(&route_hop_data.blob, &route_hop_data.nonce, &dh_secret, None) | ||||
|                     .map_err(RPCError::protocol)?; | ||||
|  | ||||
|                 // See if this is last hop in safety route, if so, we're decoding a PrivateRoute not a RouteHop | ||||
| @@ -353,7 +412,7 @@ impl RPCProcessor { | ||||
|                     network_result_try!(self.process_private_route_first_hop( | ||||
|                         route.operation, | ||||
|                         route.safety_route.public_key, | ||||
|                         &private_route, | ||||
|                         private_route, | ||||
|                     ) | ||||
|                     .await?); | ||||
|                 } else if dec_blob_tag == 0 { | ||||
| @@ -366,16 +425,16 @@ impl RPCProcessor { | ||||
|                     }; | ||||
|  | ||||
|                     // Continue the full safety route with another hop | ||||
|                     network_result_try!(self.process_route_safety_route_hop(route, route_hop) | ||||
|                     network_result_try!(self.process_route_safety_route_hop(route.operation, route_hop, route.safety_route) | ||||
|                         .await?); | ||||
|                 } else { | ||||
|                     return Ok(NetworkResult::invalid_message("invalid blob tag")); | ||||
|                 } | ||||
|             } | ||||
|             // No safety route left, now doing private route | ||||
|             SafetyRouteHops::Private(ref private_route) => { | ||||
|             SafetyRouteHops::Private(private_route) => { | ||||
|                 // See if we have a hop, if not, we are at the end of the private route | ||||
|                 match &private_route.hops { | ||||
|                 match private_route.hops { | ||||
|                     PrivateRouteHops::FirstHop(_) => { | ||||
|                         // Safety route was a stub, start with the beginning of the private route | ||||
|                         network_result_try!(self.process_private_route_first_hop( | ||||
| @@ -386,33 +445,10 @@ impl RPCProcessor { | ||||
|                         .await?); | ||||
|                     } | ||||
|                     PrivateRouteHops::Data(route_hop_data) => { | ||||
|                         // Decrypt the blob with DEC(nonce, DH(the PR's public key, this hop's secret) | ||||
|                         let node_id_secret = self.routing_table.node_id_secret(); | ||||
|                         let dh_secret = self | ||||
|                             .crypto | ||||
|                             .cached_dh(&private_route.public_key, &node_id_secret) | ||||
|                             .map_err(RPCError::protocol)?; | ||||
|                         let dec_blob_data = match Crypto::decrypt_aead( | ||||
|                             &route_hop_data.blob, | ||||
|                             &route_hop_data.nonce, | ||||
|                             &dh_secret, | ||||
|                             None, | ||||
|                         ) { | ||||
|                             Ok(v) => v, | ||||
|                             Err(e) => { | ||||
|                                 return Ok(NetworkResult::invalid_message(format!("unable to decrypt private route hop data: {}", e))); | ||||
|                             } | ||||
|                         }; | ||||
|                         let dec_blob_reader = RPCMessageData::new(dec_blob_data).get_reader()?; | ||||
|  | ||||
|                         // Decode next RouteHop | ||||
|                         let route_hop = { | ||||
|                             let rh_reader = dec_blob_reader | ||||
|                                 .get_root::<veilid_capnp::route_hop::Reader>() | ||||
|                                 .map_err(RPCError::protocol)?; | ||||
|                             decode_route_hop(&rh_reader)? | ||||
|                         }; | ||||
|  | ||||
|                          | ||||
|                         // Decrypt route hop data | ||||
|                         let route_hop = network_result_try!(self.decrypt_private_route_hop_data(&route_hop_data, &private_route.public_key, &mut route.operation)?); | ||||
|                          | ||||
|                         // Ensure hop count > 0 | ||||
|                         if private_route.hop_count == 0 { | ||||
|                             return Ok(NetworkResult::invalid_message( | ||||
| @@ -420,16 +456,6 @@ impl RPCProcessor { | ||||
|                             )); | ||||
|                         } | ||||
|  | ||||
|                         // Sign the operation if this is not our last hop | ||||
|                         // as the last hop is already signed by the envelope | ||||
|                         if route_hop.next_hop.is_some() { | ||||
|                             let node_id = self.routing_table.node_id(); | ||||
|                             let node_id_secret = self.routing_table.node_id_secret(); | ||||
|                             let sig = sign(&node_id, &node_id_secret, &route.operation.data) | ||||
|                                 .map_err(RPCError::internal)?; | ||||
|                             route.operation.signatures.push(sig); | ||||
|                         } | ||||
|  | ||||
|                         // Make next PrivateRoute and pass it on | ||||
|                         network_result_try!(self.process_route_private_route_hop( | ||||
|                             route.operation, | ||||
| @@ -453,13 +479,18 @@ impl RPCProcessor { | ||||
|                                 "route should be at the end", | ||||
|                             )); | ||||
|                         } | ||||
|                         if route.safety_route.hop_count != 0 { | ||||
|                             return Ok(NetworkResult::invalid_message( | ||||
|                                 "Safety hop count should be zero if switched to private route", | ||||
|                             )); | ||||
|                         } | ||||
|  | ||||
|                         // No hops left, time to process the routed operation | ||||
|                         network_result_try!(self.process_routed_operation( | ||||
|                             detail, | ||||
|                             route.operation, | ||||
|                             &route.safety_route, | ||||
|                             private_route, | ||||
|                             route.safety_route.public_key, | ||||
|                             private_route.public_key, | ||||
|                         )?); | ||||
|                     } | ||||
|                 } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user