checkpoint
This commit is contained in:
		@@ -529,7 +529,7 @@ struct Answer @0xacacb8b6988c1058 {
 | 
			
		||||
 | 
			
		||||
struct Operation @0xbf2811c435403c3b {
 | 
			
		||||
    opId                    @0  :UInt64;                # Random RPC ID. Must be random to foil reply forgery attacks. 
 | 
			
		||||
    senderNodeInfo          @1  :SignedNodeInfo;        # (optional) SignedNodeInfo for the sender to be cached by the receiver.
 | 
			
		||||
    senderPeerInfo          @1  :PeerInfo;              # (optional) PeerInfo for the sender to be cached by the receiver.
 | 
			
		||||
    targetNodeInfoTs        @2  :UInt64;                # Timestamp the sender believes the target's node info to be at or zero if not sent
 | 
			
		||||
    kind :union {
 | 
			
		||||
        question            @3  :Question;
 | 
			
		||||
 
 | 
			
		||||
@@ -159,6 +159,13 @@ impl TypedKeySet {
 | 
			
		||||
        out.sort_by(compare_crypto_kind);
 | 
			
		||||
        out
 | 
			
		||||
    }
 | 
			
		||||
    pub fn keys(&self) -> Vec<PublicKey> {
 | 
			
		||||
        let mut out = Vec::new();
 | 
			
		||||
        for tk in &self.items {
 | 
			
		||||
            out.push(tk.key);
 | 
			
		||||
        }
 | 
			
		||||
        out
 | 
			
		||||
    }
 | 
			
		||||
    pub fn get(&self, kind: CryptoKind) -> Option<TypedKey> {
 | 
			
		||||
        self.items.iter().find(|x| x.kind == kind).copied()
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -765,34 +765,33 @@ impl NetworkManager {
 | 
			
		||||
 | 
			
		||||
    /// Called by the RPC handler when we want to issue an RPC request or response
 | 
			
		||||
    /// node_ref is the direct destination to which the envelope will be sent
 | 
			
		||||
    /// If 'envelope_node_id' is specified, it can be different than the node_ref being sent to
 | 
			
		||||
    /// If 'envelope_node_ref' is specified, it can be different than the node_ref being sent to
 | 
			
		||||
    /// which will cause the envelope to be relayed
 | 
			
		||||
    #[instrument(level = "trace", skip(self, body), ret, err)]
 | 
			
		||||
    pub async fn send_envelope<B: AsRef<[u8]>>(
 | 
			
		||||
        &self,
 | 
			
		||||
        node_ref: NodeRef,
 | 
			
		||||
        envelope_node_id: Option<TypedKey>,
 | 
			
		||||
        envelope_node_ref: Option<NodeRef>,
 | 
			
		||||
        body: B,
 | 
			
		||||
    ) -> EyreResult<NetworkResult<SendDataKind>> {
 | 
			
		||||
        let via_node_ids = node_ref.node_ids();
 | 
			
		||||
        let Some(best_via_node_id) = via_node_ids.best() else {
 | 
			
		||||
            bail!("should have a best node id");
 | 
			
		||||
        };
 | 
			
		||||
        let envelope_node_id = envelope_node_id.unwrap_or(best_via_node_id);
 | 
			
		||||
 | 
			
		||||
        if !via_node_ids.contains(&envelope_node_id) {
 | 
			
		||||
        let end_node_ref = envelope_node_ref.as_ref().unwrap_or(&node_ref).clone();
 | 
			
		||||
        
 | 
			
		||||
        if !node_ref.same_entry(&end_node_ref) {
 | 
			
		||||
            log_net!(
 | 
			
		||||
                "sending envelope to {:?} via {:?}",
 | 
			
		||||
                envelope_node_id,
 | 
			
		||||
                end_node_ref,
 | 
			
		||||
                node_ref
 | 
			
		||||
            );
 | 
			
		||||
        } else {
 | 
			
		||||
            log_net!("sending envelope to {:?}", node_ref);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        let best_node_id = end_node_ref.best_node_id();
 | 
			
		||||
 | 
			
		||||
        // Get node's envelope versions and see if we can send to it
 | 
			
		||||
        // and if so, get the max version we can use
 | 
			
		||||
        let Some(envelope_version) = node_ref.envelope_support().into_iter().rev().find(|x| VALID_ENVELOPE_VERSIONS.contains(x)) else {
 | 
			
		||||
        let Some(envelope_version) = end_node_ref.best_envelope_version() else {
 | 
			
		||||
            bail!(
 | 
			
		||||
                "can't talk to this node {} because we dont support its envelope versions",
 | 
			
		||||
                node_ref
 | 
			
		||||
@@ -800,10 +799,10 @@ impl NetworkManager {
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        // Build the envelope to send
 | 
			
		||||
        let out = self.build_envelope(envelope_node_id, envelope_version, body)?;
 | 
			
		||||
        let out = self.build_envelope(best_node_id, envelope_version, body)?;
 | 
			
		||||
 | 
			
		||||
        // Send the envelope via whatever means necessary
 | 
			
		||||
        self.send_data(node_ref.clone(), out).await
 | 
			
		||||
        self.send_data(node_ref, out).await
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Called by the RPC handler when we want to issue an direct receipt
 | 
			
		||||
@@ -867,7 +866,7 @@ impl NetworkManager {
 | 
			
		||||
        let rpc = self.rpc_processor();
 | 
			
		||||
        network_result_try!(rpc
 | 
			
		||||
            .rpc_call_signal(
 | 
			
		||||
                Destination::relay(relay_nr, target_nr.node_id()),
 | 
			
		||||
                Destination::relay(relay_nr, target_nr.clone()),
 | 
			
		||||
                SignalInfo::ReverseConnect { receipt, peer_info },
 | 
			
		||||
            )
 | 
			
		||||
            .await
 | 
			
		||||
@@ -972,7 +971,7 @@ impl NetworkManager {
 | 
			
		||||
        let rpc = self.rpc_processor();
 | 
			
		||||
        network_result_try!(rpc
 | 
			
		||||
            .rpc_call_signal(
 | 
			
		||||
                Destination::relay(relay_nr, target_nr.node_id()),
 | 
			
		||||
                Destination::relay(relay_nr, target_nr.clone()),
 | 
			
		||||
                SignalInfo::HolePunch { receipt, peer_info },
 | 
			
		||||
            )
 | 
			
		||||
            .await
 | 
			
		||||
@@ -1076,7 +1075,7 @@ impl NetworkManager {
 | 
			
		||||
                let relay_nr = routing_table
 | 
			
		||||
                    .lookup_and_filter_noderef(relay_key, routing_domain.into(), dial_info_filter)
 | 
			
		||||
                    .ok_or_else(|| eyre!("couldn't look up relay"))?;
 | 
			
		||||
                if target_node_ref.node_id() != target_key {
 | 
			
		||||
                if !target_node_ref.node_ids().contains(&target_key) {
 | 
			
		||||
                    bail!("target noderef didn't match target key");
 | 
			
		||||
                }
 | 
			
		||||
                NodeContactMethod::SignalReverse(relay_nr, target_node_ref)
 | 
			
		||||
@@ -1085,7 +1084,7 @@ impl NetworkManager {
 | 
			
		||||
                let relay_nr = routing_table
 | 
			
		||||
                    .lookup_and_filter_noderef(relay_key, routing_domain.into(), dial_info_filter)
 | 
			
		||||
                    .ok_or_else(|| eyre!("couldn't look up relay"))?;
 | 
			
		||||
                if target_node_ref.node_id() != target_key {
 | 
			
		||||
                if target_node_ref.node_ids().contains(&target_key) {
 | 
			
		||||
                    bail!("target noderef didn't match target key");
 | 
			
		||||
                }
 | 
			
		||||
                NodeContactMethod::SignalHolePunch(relay_nr, target_node_ref)
 | 
			
		||||
@@ -1386,7 +1385,7 @@ impl NetworkManager {
 | 
			
		||||
 | 
			
		||||
            let some_relay_nr = if self.check_client_whitelist(sender_id) {
 | 
			
		||||
                // Full relay allowed, do a full resolve_node
 | 
			
		||||
                match rpc.resolve_node(recipient_id).await {
 | 
			
		||||
                match rpc.resolve_node(recipient_id.key).await {
 | 
			
		||||
                    Ok(v) => v,
 | 
			
		||||
                    Err(e) => {
 | 
			
		||||
                        log_net!(debug "failed to resolve recipient node for relay, dropping outbound relayed packet: {}" ,e);
 | 
			
		||||
 
 | 
			
		||||
@@ -476,6 +476,10 @@ impl BucketEntryInner {
 | 
			
		||||
        self.envelope_support.clone()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn best_envelope_version(&self) -> Option<u8> {
 | 
			
		||||
        self.envelope_support.iter().rev().find(|x| VALID_ENVELOPE_VERSIONS.contains(x)).copied()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn state(&self, cur_ts: Timestamp) -> BucketEntryState {
 | 
			
		||||
        if self.check_reliable(cur_ts) {
 | 
			
		||||
            BucketEntryState::Reliable
 | 
			
		||||
 
 | 
			
		||||
@@ -132,6 +132,9 @@ pub trait NodeRefBase: Sized {
 | 
			
		||||
    fn set_envelope_support(&self, envelope_support: Vec<u8>) {
 | 
			
		||||
        self.operate_mut(|_rti, e| e.set_envelope_support(envelope_support))
 | 
			
		||||
    }
 | 
			
		||||
    fn best_envelope_version(&self) -> Option<u8> {
 | 
			
		||||
        self.operate(|_rti, e| e.best_envelope_version())
 | 
			
		||||
    }
 | 
			
		||||
    fn state(&self, cur_ts: Timestamp) -> BucketEntryState {
 | 
			
		||||
        self.operate(|_rti, e| e.state(cur_ts))
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -16,7 +16,7 @@ pub struct RouteHopData {
 | 
			
		||||
#[derive(Clone, Debug)]
 | 
			
		||||
pub enum RouteNode {
 | 
			
		||||
    /// Route node is optimized, no contact method information as this node id has been seen before
 | 
			
		||||
    NodeId(TypedKey),
 | 
			
		||||
    NodeId(PublicKey),
 | 
			
		||||
    /// Route node with full contact method information to ensure the peer is reachable
 | 
			
		||||
    PeerInfo(PeerInfo),
 | 
			
		||||
}
 | 
			
		||||
@@ -79,6 +79,11 @@ impl PrivateRoute {
 | 
			
		||||
        false
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Get the crypto kind in use for this route
 | 
			
		||||
    pub fn crypto_kind(&self) -> CryptoKind {
 | 
			
		||||
        self.public_key.kind
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Remove the first unencrypted hop if possible
 | 
			
		||||
    pub fn pop_first_hop(&mut self) -> Option<RouteNode> {
 | 
			
		||||
        match &mut self.hops {
 | 
			
		||||
@@ -112,8 +117,8 @@ impl PrivateRoute {
 | 
			
		||||
 | 
			
		||||
        // Get the safety route to use from the spec
 | 
			
		||||
        Some(match &pr_first_hop.node {
 | 
			
		||||
            RouteNode::NodeId(n) => n,
 | 
			
		||||
            RouteNode::PeerInfo(p) => p.node_id.key,
 | 
			
		||||
            RouteNode::NodeId(n) => TypedKey::new(self.public_key.kind, *n),
 | 
			
		||||
            RouteNode::PeerInfo(p) => p.node_ids.get(self.public_key.kind).unwrap(),
 | 
			
		||||
        })
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -126,8 +131,13 @@ impl fmt::Display for PrivateRoute {
 | 
			
		||||
            self.public_key,
 | 
			
		||||
            self.hop_count,
 | 
			
		||||
            match &self.hops {
 | 
			
		||||
                PrivateRouteHops::FirstHop(fh) => {
 | 
			
		||||
                    format!("->{}", fh.node)
 | 
			
		||||
                PrivateRouteHops::FirstHop(_) => {
 | 
			
		||||
                    format!(
 | 
			
		||||
                        "->{}",
 | 
			
		||||
                        self.first_hop_node_id()
 | 
			
		||||
                            .map(|n| n.to_string())
 | 
			
		||||
                            .unwrap_or_else(|| "None".to_owned())
 | 
			
		||||
                    )
 | 
			
		||||
                }
 | 
			
		||||
                PrivateRouteHops::Data(_) => {
 | 
			
		||||
                    "->?".to_owned()
 | 
			
		||||
@@ -156,6 +166,7 @@ pub struct SafetyRoute {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl SafetyRoute {
 | 
			
		||||
    /// Stub route is the form used when no privacy is required, but you need to directly contact a private route
 | 
			
		||||
    pub fn new_stub(public_key: TypedKey, private_route: PrivateRoute) -> Self {
 | 
			
		||||
        // First hop should have already been popped off for stubbed safety routes since
 | 
			
		||||
        // we are sending directly to the first hop
 | 
			
		||||
@@ -166,9 +177,16 @@ impl SafetyRoute {
 | 
			
		||||
            hops: SafetyRouteHops::Private(private_route),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Check if this is a stub route
 | 
			
		||||
    pub fn is_stub(&self) -> bool {
 | 
			
		||||
        matches!(self.hops, SafetyRouteHops::Private(_))
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Get the crypto kind in use for this route
 | 
			
		||||
    pub fn crypto_kind(&self) -> CryptoKind {
 | 
			
		||||
        self.public_key.kind
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl fmt::Display for SafetyRoute {
 | 
			
		||||
 
 | 
			
		||||
@@ -163,6 +163,8 @@ impl RouteStats {
 | 
			
		||||
#[derive(Clone, Debug, RkyvArchive, RkyvSerialize, RkyvDeserialize)]
 | 
			
		||||
#[archive_attr(repr(C), derive(CheckBytes))]
 | 
			
		||||
pub struct RouteSpecDetail {
 | 
			
		||||
    /// Crypto kind
 | 
			
		||||
    crypto_kind: CryptoKind,
 | 
			
		||||
    /// Secret key
 | 
			
		||||
    #[with(Skip)]
 | 
			
		||||
    secret_key: SecretKey,
 | 
			
		||||
@@ -187,6 +189,9 @@ pub struct RouteSpecDetail {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl RouteSpecDetail {
 | 
			
		||||
    pub fn get_crypto_kind(&self) -> CryptoKind {
 | 
			
		||||
        self.crypto_kind
 | 
			
		||||
    }
 | 
			
		||||
    pub fn get_stats(&self) -> &RouteStats {
 | 
			
		||||
        &self.stats
 | 
			
		||||
    }
 | 
			
		||||
@@ -221,13 +226,13 @@ impl RouteSpecDetail {
 | 
			
		||||
#[archive_attr(repr(C, align(8)), derive(CheckBytes))]
 | 
			
		||||
pub struct RouteSpecStoreContent {
 | 
			
		||||
    /// All of the routes we have allocated so far
 | 
			
		||||
    details: HashMap<TypedKey, RouteSpecDetail>,
 | 
			
		||||
    details: HashMap<PublicKey, RouteSpecDetail>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// What remote private routes have seen
 | 
			
		||||
#[derive(Debug, Clone, Default)]
 | 
			
		||||
pub struct RemotePrivateRouteInfo {
 | 
			
		||||
    // The private route itself
 | 
			
		||||
    /// The private route itself
 | 
			
		||||
    private_route: Option<PrivateRoute>,
 | 
			
		||||
    /// Did this remote private route see our node info due to no safety route in use
 | 
			
		||||
    last_seen_our_node_info_ts: Timestamp,
 | 
			
		||||
@@ -256,13 +261,13 @@ pub struct RouteSpecStoreCache {
 | 
			
		||||
    /// Route spec hop cache, used to quickly disqualify routes
 | 
			
		||||
    hop_cache: HashSet<Vec<u8>>,
 | 
			
		||||
    /// Has a remote private route responded to a question and when
 | 
			
		||||
    remote_private_route_cache: LruCache<TypedKey, RemotePrivateRouteInfo>,
 | 
			
		||||
    remote_private_route_cache: LruCache<PublicKey, RemotePrivateRouteInfo>,
 | 
			
		||||
    /// Compiled route cache
 | 
			
		||||
    compiled_route_cache: LruCache<CompiledRouteCacheKey, SafetyRoute>,
 | 
			
		||||
    /// List of dead allocated routes
 | 
			
		||||
    dead_routes: Vec<TypedKey>,
 | 
			
		||||
    dead_routes: Vec<PublicKey>,
 | 
			
		||||
    /// List of dead remote routes
 | 
			
		||||
    dead_remote_routes: Vec<TypedKey>,
 | 
			
		||||
    dead_remote_routes: Vec<PublicKey>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Default for RouteSpecStoreCache {
 | 
			
		||||
@@ -602,6 +607,7 @@ impl RouteSpecStore {
 | 
			
		||||
    /// Prefers nodes that are not currently in use by another route
 | 
			
		||||
    /// The route is not yet tested for its reachability
 | 
			
		||||
    /// Returns None if no route could be allocated at this time
 | 
			
		||||
    /// Returns Some list of public keys for the requested set of crypto kinds
 | 
			
		||||
    #[instrument(level = "trace", skip(self), ret, err)]
 | 
			
		||||
    pub fn allocate_route(
 | 
			
		||||
        &self,
 | 
			
		||||
@@ -1590,8 +1596,8 @@ impl RouteSpecStore {
 | 
			
		||||
        rti: &RoutingTableInner,
 | 
			
		||||
        safety_spec: &SafetySpec,
 | 
			
		||||
        direction: DirectionSet,
 | 
			
		||||
        avoid_nodes: &[TypedKey],
 | 
			
		||||
    ) -> EyreResult<Option<TypedKeySet>> {
 | 
			
		||||
        avoid_nodes: &[PublicKey],
 | 
			
		||||
    ) -> EyreResult<Option<PublicKey>> {
 | 
			
		||||
        // Ensure the total hop count isn't too long for our config
 | 
			
		||||
        let max_route_hop_count = self.unlocked_inner.max_route_hop_count;
 | 
			
		||||
        if safety_spec.hop_count == 0 {
 | 
			
		||||
@@ -1645,13 +1651,14 @@ impl RouteSpecStore {
 | 
			
		||||
        Ok(Some(sr_pubkey))
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Get a private sroute to use for the answer to question
 | 
			
		||||
    /// Get a private route to use for the answer to question
 | 
			
		||||
    #[instrument(level = "trace", skip(self), ret, err)]
 | 
			
		||||
    pub fn get_private_route_for_safety_spec(
 | 
			
		||||
        &self,
 | 
			
		||||
        crypto_kind: CryptoKind,
 | 
			
		||||
        safety_spec: &SafetySpec,
 | 
			
		||||
        avoid_nodes: &[TypedKey],
 | 
			
		||||
    ) -> EyreResult<Option<TypedKey>> {
 | 
			
		||||
        avoid_nodes: &[PublicKey],
 | 
			
		||||
    ) -> EyreResult<Option<PublicKey>> {
 | 
			
		||||
        let inner = &mut *self.inner.lock();
 | 
			
		||||
        let routing_table = self.unlocked_inner.routing_table.clone();
 | 
			
		||||
        let rti = &*routing_table.inner.read();
 | 
			
		||||
@@ -1669,7 +1676,7 @@ impl RouteSpecStore {
 | 
			
		||||
    #[instrument(level = "trace", skip(self), err)]
 | 
			
		||||
    pub fn assemble_private_route(
 | 
			
		||||
        &self,
 | 
			
		||||
        key: &TypedKey,
 | 
			
		||||
        key: &PublicKey,
 | 
			
		||||
        optimized: Option<bool>,
 | 
			
		||||
    ) -> EyreResult<PrivateRoute> {
 | 
			
		||||
        let inner = &*self.inner.lock();
 | 
			
		||||
@@ -1758,7 +1765,7 @@ impl RouteSpecStore {
 | 
			
		||||
 | 
			
		||||
    /// Import a remote private route for compilation
 | 
			
		||||
    #[instrument(level = "trace", skip(self, blob), ret, err)]
 | 
			
		||||
    pub fn import_remote_private_route(&self, blob: Vec<u8>) -> EyreResult<TypedKey> {
 | 
			
		||||
    pub fn import_remote_private_route(&self, blob: Vec<u8>) -> EyreResult<PublicKey> {
 | 
			
		||||
        // decode the pr blob
 | 
			
		||||
        let private_route = RouteSpecStore::blob_to_private_route(blob)?;
 | 
			
		||||
 | 
			
		||||
@@ -1783,7 +1790,7 @@ impl RouteSpecStore {
 | 
			
		||||
 | 
			
		||||
    /// Release a remote private route that is no longer in use
 | 
			
		||||
    #[instrument(level = "trace", skip(self), ret)]
 | 
			
		||||
    fn release_remote_private_route(&self, key: &TypedKey) -> bool {
 | 
			
		||||
    fn release_remote_private_route(&self, key: &PublicKey) -> bool {
 | 
			
		||||
        let inner = &mut *self.inner.lock();
 | 
			
		||||
        if inner.cache.remote_private_route_cache.remove(key).is_some() {
 | 
			
		||||
            // Mark it as dead for the update
 | 
			
		||||
@@ -1795,7 +1802,7 @@ impl RouteSpecStore {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Retrieve an imported remote private route by its public key
 | 
			
		||||
    pub fn get_remote_private_route(&self, key: &TypedKey) -> Option<PrivateRoute> {
 | 
			
		||||
    pub fn get_remote_private_route(&self, key: &PublicKey) -> Option<PrivateRoute> {
 | 
			
		||||
        let inner = &mut *self.inner.lock();
 | 
			
		||||
        let cur_ts = get_aligned_timestamp();
 | 
			
		||||
        Self::with_get_remote_private_route(inner, cur_ts, key, |r| {
 | 
			
		||||
@@ -1804,7 +1811,7 @@ impl RouteSpecStore {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Retrieve an imported remote private route by its public key but don't 'touch' it
 | 
			
		||||
    pub fn peek_remote_private_route(&self, key: &TypedKey) -> Option<PrivateRoute> {
 | 
			
		||||
    pub fn peek_remote_private_route(&self, key: &PublicKey) -> Option<PrivateRoute> {
 | 
			
		||||
        let inner = &mut *self.inner.lock();
 | 
			
		||||
        let cur_ts = get_aligned_timestamp();
 | 
			
		||||
        Self::with_peek_remote_private_route(inner, cur_ts, key, |r| {
 | 
			
		||||
@@ -1865,7 +1872,7 @@ impl RouteSpecStore {
 | 
			
		||||
    fn with_get_remote_private_route<F, R>(
 | 
			
		||||
        inner: &mut RouteSpecStoreInner,
 | 
			
		||||
        cur_ts: Timestamp,
 | 
			
		||||
        remote_private_route: &TypedKey,
 | 
			
		||||
        key: &PublicKey,
 | 
			
		||||
        f: F,
 | 
			
		||||
    ) -> Option<R>
 | 
			
		||||
    where
 | 
			
		||||
@@ -1885,7 +1892,7 @@ impl RouteSpecStore {
 | 
			
		||||
    fn with_peek_remote_private_route<F, R>(
 | 
			
		||||
        inner: &mut RouteSpecStoreInner,
 | 
			
		||||
        cur_ts: Timestamp,
 | 
			
		||||
        remote_private_route: &TypedKey,
 | 
			
		||||
        key: &PublicKey,
 | 
			
		||||
        f: F,
 | 
			
		||||
    ) -> Option<R>
 | 
			
		||||
    where
 | 
			
		||||
@@ -1907,7 +1914,7 @@ impl RouteSpecStore {
 | 
			
		||||
 | 
			
		||||
    /// Check to see if this remote (not ours) private route has seen our current node info yet
 | 
			
		||||
    /// This happens when you communicate with a private route without a safety route
 | 
			
		||||
    pub fn has_remote_private_route_seen_our_node_info(&self, remote_private_route: &TypedKey) -> bool {
 | 
			
		||||
    pub fn has_remote_private_route_seen_our_node_info(&self, key: &PublicKey) -> bool {
 | 
			
		||||
        let our_node_info_ts = {
 | 
			
		||||
            let rti = &*self.unlocked_inner.routing_table.inner.read();
 | 
			
		||||
            let Some(ts) = rti.get_own_node_info_ts(RoutingDomain::PublicInternet) else {
 | 
			
		||||
@@ -1919,7 +1926,7 @@ impl RouteSpecStore {
 | 
			
		||||
        let opt_rpr_node_info_ts = {
 | 
			
		||||
            let inner = &mut *self.inner.lock();
 | 
			
		||||
            let cur_ts = get_aligned_timestamp();
 | 
			
		||||
            Self::with_peek_remote_private_route(inner, cur_ts, remote_private_route, |rpr| {
 | 
			
		||||
            Self::with_peek_remote_private_route(inner, cur_ts, key, |rpr| {
 | 
			
		||||
                rpr.last_seen_our_node_info_ts
 | 
			
		||||
            })
 | 
			
		||||
        };
 | 
			
		||||
 
 | 
			
		||||
@@ -16,12 +16,15 @@ impl RPCOperationKind {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn decode(kind_reader: &veilid_capnp::operation::kind::Reader) -> Result<Self, RPCError> {
 | 
			
		||||
    pub fn decode(
 | 
			
		||||
        kind_reader: &veilid_capnp::operation::kind::Reader,
 | 
			
		||||
        crypto: Crypto,
 | 
			
		||||
    ) -> Result<Self, RPCError> {
 | 
			
		||||
        let which_reader = kind_reader.which().map_err(RPCError::protocol)?;
 | 
			
		||||
        let out = match which_reader {
 | 
			
		||||
            veilid_capnp::operation::kind::Which::Question(r) => {
 | 
			
		||||
                let q_reader = r.map_err(RPCError::protocol)?;
 | 
			
		||||
                let out = RPCQuestion::decode(&q_reader)?;
 | 
			
		||||
                let out = RPCQuestion::decode(&q_reader, crypto)?;
 | 
			
		||||
                RPCOperationKind::Question(out)
 | 
			
		||||
            }
 | 
			
		||||
            veilid_capnp::operation::kind::Which::Statement(r) => {
 | 
			
		||||
@@ -54,31 +57,25 @@ impl RPCOperationKind {
 | 
			
		||||
#[derive(Debug, Clone)]
 | 
			
		||||
pub struct RPCOperation {
 | 
			
		||||
    op_id: OperationId,
 | 
			
		||||
    sender_node_info: Option<SignedNodeInfo>,
 | 
			
		||||
    opt_sender_peer_info: Option<PeerInfo>,
 | 
			
		||||
    target_node_info_ts: Timestamp,
 | 
			
		||||
    kind: RPCOperationKind,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl RPCOperation {
 | 
			
		||||
    pub fn new_question(
 | 
			
		||||
        question: RPCQuestion,
 | 
			
		||||
        sender_signed_node_info: SenderSignedNodeInfo,
 | 
			
		||||
    ) -> Self {
 | 
			
		||||
    pub fn new_question(question: RPCQuestion, sender_peer_info: SenderPeerInfo) -> Self {
 | 
			
		||||
        Self {
 | 
			
		||||
            op_id: OperationId::new(get_random_u64()),
 | 
			
		||||
            sender_node_info: sender_signed_node_info.signed_node_info,
 | 
			
		||||
            target_node_info_ts: sender_signed_node_info.target_node_info_ts,
 | 
			
		||||
            opt_sender_peer_info: sender_peer_info.opt_sender_peer_info,
 | 
			
		||||
            target_node_info_ts: sender_peer_info.target_node_info_ts,
 | 
			
		||||
            kind: RPCOperationKind::Question(question),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    pub fn new_statement(
 | 
			
		||||
        statement: RPCStatement,
 | 
			
		||||
        sender_signed_node_info: SenderSignedNodeInfo,
 | 
			
		||||
    ) -> Self {
 | 
			
		||||
    pub fn new_statement(statement: RPCStatement, sender_peer_info: SenderPeerInfo) -> Self {
 | 
			
		||||
        Self {
 | 
			
		||||
            op_id: OperationId::new(get_random_u64()),
 | 
			
		||||
            sender_node_info: sender_signed_node_info.signed_node_info,
 | 
			
		||||
            target_node_info_ts: sender_signed_node_info.target_node_info_ts,
 | 
			
		||||
            opt_sender_peer_info: sender_peer_info.opt_sender_peer_info,
 | 
			
		||||
            target_node_info_ts: sender_peer_info.target_node_info_ts,
 | 
			
		||||
            kind: RPCOperationKind::Statement(statement),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
@@ -86,12 +83,12 @@ impl RPCOperation {
 | 
			
		||||
    pub fn new_answer(
 | 
			
		||||
        request: &RPCOperation,
 | 
			
		||||
        answer: RPCAnswer,
 | 
			
		||||
        sender_signed_node_info: SenderSignedNodeInfo,
 | 
			
		||||
        sender_peer_info: SenderPeerInfo,
 | 
			
		||||
    ) -> Self {
 | 
			
		||||
        Self {
 | 
			
		||||
            op_id: request.op_id,
 | 
			
		||||
            sender_node_info: sender_signed_node_info.signed_node_info,
 | 
			
		||||
            target_node_info_ts: sender_signed_node_info.target_node_info_ts,
 | 
			
		||||
            opt_sender_peer_info: sender_peer_info.opt_sender_peer_info,
 | 
			
		||||
            target_node_info_ts: sender_peer_info.target_node_info_ts,
 | 
			
		||||
            kind: RPCOperationKind::Answer(answer),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
@@ -100,8 +97,8 @@ impl RPCOperation {
 | 
			
		||||
        self.op_id
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn sender_node_info(&self) -> Option<&SignedNodeInfo> {
 | 
			
		||||
        self.sender_node_info.as_ref()
 | 
			
		||||
    pub fn sender_peer_info(&self) -> Option<&PeerInfo> {
 | 
			
		||||
        self.opt_sender_peer_info.as_ref()
 | 
			
		||||
    }
 | 
			
		||||
    pub fn target_node_info_ts(&self) -> Timestamp {
 | 
			
		||||
        self.target_node_info_ts
 | 
			
		||||
@@ -117,20 +114,16 @@ impl RPCOperation {
 | 
			
		||||
 | 
			
		||||
    pub fn decode(
 | 
			
		||||
        operation_reader: &veilid_capnp::operation::Reader,
 | 
			
		||||
        opt_sender_node_id: Option<&TypedKey>,
 | 
			
		||||
        crypto: Crypto,
 | 
			
		||||
    ) -> Result<Self, RPCError> {
 | 
			
		||||
        let op_id = OperationId::new(operation_reader.get_op_id());
 | 
			
		||||
 | 
			
		||||
        let sender_node_info = if operation_reader.has_sender_node_info() {
 | 
			
		||||
            if let Some(sender_node_id) = opt_sender_node_id {
 | 
			
		||||
                let sni_reader = operation_reader
 | 
			
		||||
                    .get_sender_node_info()
 | 
			
		||||
                    .map_err(RPCError::protocol)?;
 | 
			
		||||
                let sni = decode_signed_node_info(&sni_reader, sender_node_id)?;
 | 
			
		||||
                Some(sni)
 | 
			
		||||
            } else {
 | 
			
		||||
                None
 | 
			
		||||
            }
 | 
			
		||||
        let sender_peer_info = if operation_reader.has_sender_peer_info() {
 | 
			
		||||
            let pi_reader = operation_reader
 | 
			
		||||
                .get_sender_peer_info()
 | 
			
		||||
                .map_err(RPCError::protocol)?;
 | 
			
		||||
            let pi = decode_peer_info(&pi_reader, crypto.clone())?;
 | 
			
		||||
            Some(pi)
 | 
			
		||||
        } else {
 | 
			
		||||
            None
 | 
			
		||||
        };
 | 
			
		||||
@@ -138,11 +131,11 @@ impl RPCOperation {
 | 
			
		||||
        let target_node_info_ts = Timestamp::new(operation_reader.get_target_node_info_ts());
 | 
			
		||||
 | 
			
		||||
        let kind_reader = operation_reader.get_kind();
 | 
			
		||||
        let kind = RPCOperationKind::decode(&kind_reader)?;
 | 
			
		||||
        let kind = RPCOperationKind::decode(&kind_reader, crypto)?;
 | 
			
		||||
 | 
			
		||||
        Ok(RPCOperation {
 | 
			
		||||
            op_id,
 | 
			
		||||
            sender_node_info,
 | 
			
		||||
            opt_sender_peer_info: sender_peer_info,
 | 
			
		||||
            target_node_info_ts,
 | 
			
		||||
            kind,
 | 
			
		||||
        })
 | 
			
		||||
@@ -150,9 +143,9 @@ impl RPCOperation {
 | 
			
		||||
 | 
			
		||||
    pub fn encode(&self, builder: &mut veilid_capnp::operation::Builder) -> Result<(), RPCError> {
 | 
			
		||||
        builder.set_op_id(self.op_id.as_u64());
 | 
			
		||||
        if let Some(sender_info) = &self.sender_node_info {
 | 
			
		||||
            let mut si_builder = builder.reborrow().init_sender_node_info();
 | 
			
		||||
            encode_signed_node_info(&sender_info, &mut si_builder)?;
 | 
			
		||||
        if let Some(sender_peer_info) = &self.opt_sender_peer_info {
 | 
			
		||||
            let mut pi_builder = builder.reborrow().init_sender_peer_info();
 | 
			
		||||
            encode_peer_info(&sender_peer_info, &mut pi_builder)?;
 | 
			
		||||
        }
 | 
			
		||||
        builder.set_target_node_info_ts(self.target_node_info_ts.as_u64());
 | 
			
		||||
        let mut k_builder = builder.reborrow().init_kind();
 | 
			
		||||
 
 | 
			
		||||
@@ -19,9 +19,12 @@ impl RPCQuestion {
 | 
			
		||||
    pub fn desc(&self) -> &'static str {
 | 
			
		||||
        self.detail.desc()
 | 
			
		||||
    }
 | 
			
		||||
    pub fn decode(reader: &veilid_capnp::question::Reader) -> Result<RPCQuestion, RPCError> {
 | 
			
		||||
    pub fn decode(
 | 
			
		||||
        reader: &veilid_capnp::question::Reader,
 | 
			
		||||
        crypto: Crypto,
 | 
			
		||||
    ) -> Result<RPCQuestion, RPCError> {
 | 
			
		||||
        let rt_reader = reader.get_respond_to();
 | 
			
		||||
        let respond_to = RespondTo::decode(&rt_reader)?;
 | 
			
		||||
        let respond_to = RespondTo::decode(&rt_reader, crypto)?;
 | 
			
		||||
        let d_reader = reader.get_detail();
 | 
			
		||||
        let detail = RPCQuestionDetail::decode(&d_reader)?;
 | 
			
		||||
        Ok(RPCQuestion { respond_to, detail })
 | 
			
		||||
 
 | 
			
		||||
@@ -23,12 +23,15 @@ impl RespondTo {
 | 
			
		||||
        Ok(())
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn decode(reader: &veilid_capnp::question::respond_to::Reader) -> Result<Self, RPCError> {
 | 
			
		||||
    pub fn decode(
 | 
			
		||||
        reader: &veilid_capnp::question::respond_to::Reader,
 | 
			
		||||
        crypto: Crypto,
 | 
			
		||||
    ) -> Result<Self, RPCError> {
 | 
			
		||||
        let respond_to = match reader.which().map_err(RPCError::protocol)? {
 | 
			
		||||
            veilid_capnp::question::respond_to::Sender(()) => RespondTo::Sender,
 | 
			
		||||
            veilid_capnp::question::respond_to::PrivateRoute(pr_reader) => {
 | 
			
		||||
                let pr_reader = pr_reader.map_err(RPCError::protocol)?;
 | 
			
		||||
                let pr = decode_private_route(&pr_reader)?;
 | 
			
		||||
                let pr = decode_private_route(&pr_reader, crypto)?;
 | 
			
		||||
                RespondTo::PrivateRoute(pr)
 | 
			
		||||
            }
 | 
			
		||||
        };
 | 
			
		||||
 
 | 
			
		||||
@@ -53,7 +53,7 @@ pub fn encode_route_hop(
 | 
			
		||||
    match &route_hop.node {
 | 
			
		||||
        RouteNode::NodeId(ni) => {
 | 
			
		||||
            let mut ni_builder = node_builder.init_node_id();
 | 
			
		||||
            encode_key256(&ni.key, &mut ni_builder)?;
 | 
			
		||||
            encode_key256(&ni, &mut ni_builder);
 | 
			
		||||
        }
 | 
			
		||||
        RouteNode::PeerInfo(pi) => {
 | 
			
		||||
            let mut pi_builder = node_builder.init_peer_info();
 | 
			
		||||
@@ -67,17 +67,20 @@ pub fn encode_route_hop(
 | 
			
		||||
    Ok(())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub fn decode_route_hop(reader: &veilid_capnp::route_hop::Reader) -> Result<RouteHop, RPCError> {
 | 
			
		||||
pub fn decode_route_hop(
 | 
			
		||||
    reader: &veilid_capnp::route_hop::Reader,
 | 
			
		||||
    crypto: Crypto,
 | 
			
		||||
) -> Result<RouteHop, RPCError> {
 | 
			
		||||
    let n_reader = reader.reborrow().get_node();
 | 
			
		||||
    let node = match n_reader.which().map_err(RPCError::protocol)? {
 | 
			
		||||
        veilid_capnp::route_hop::node::Which::NodeId(ni) => {
 | 
			
		||||
            let ni_reader = ni.map_err(RPCError::protocol)?;
 | 
			
		||||
            RouteNode::NodeId(NodeId::new(decode_key256(&ni_reader)))
 | 
			
		||||
            RouteNode::NodeId(decode_key256(&ni_reader))
 | 
			
		||||
        }
 | 
			
		||||
        veilid_capnp::route_hop::node::Which::PeerInfo(pi) => {
 | 
			
		||||
            let pi_reader = pi.map_err(RPCError::protocol)?;
 | 
			
		||||
            RouteNode::PeerInfo(
 | 
			
		||||
                decode_peer_info(&pi_reader)
 | 
			
		||||
                decode_peer_info(&pi_reader, crypto)
 | 
			
		||||
                    .map_err(RPCError::map_protocol("invalid peer info in route hop"))?,
 | 
			
		||||
            )
 | 
			
		||||
        }
 | 
			
		||||
@@ -101,10 +104,10 @@ pub fn encode_private_route(
 | 
			
		||||
    private_route: &PrivateRoute,
 | 
			
		||||
    builder: &mut veilid_capnp::private_route::Builder,
 | 
			
		||||
) -> Result<(), RPCError> {
 | 
			
		||||
    encode_key256(
 | 
			
		||||
    encode_typed_key(
 | 
			
		||||
        &private_route.public_key,
 | 
			
		||||
        &mut builder.reborrow().init_public_key(),
 | 
			
		||||
    )?;
 | 
			
		||||
    );
 | 
			
		||||
    builder.set_hop_count(private_route.hop_count);
 | 
			
		||||
    let mut h_builder = builder.reborrow().init_hops();
 | 
			
		||||
    match &private_route.hops {
 | 
			
		||||
@@ -125,16 +128,17 @@ pub fn encode_private_route(
 | 
			
		||||
 | 
			
		||||
pub fn decode_private_route(
 | 
			
		||||
    reader: &veilid_capnp::private_route::Reader,
 | 
			
		||||
    crypto: Crypto,
 | 
			
		||||
) -> Result<PrivateRoute, RPCError> {
 | 
			
		||||
    let public_key = decode_key256(&reader.get_public_key().map_err(RPCError::map_protocol(
 | 
			
		||||
        "invalid public key in private route",
 | 
			
		||||
    ))?);
 | 
			
		||||
    let public_key = decode_typed_key(&reader.get_public_key().map_err(
 | 
			
		||||
        RPCError::map_protocol("invalid public key in private route"),
 | 
			
		||||
    )?)?;
 | 
			
		||||
    let hop_count = reader.get_hop_count();
 | 
			
		||||
 | 
			
		||||
    let hops = match reader.get_hops().which().map_err(RPCError::protocol)? {
 | 
			
		||||
        veilid_capnp::private_route::hops::Which::FirstHop(rh_reader) => {
 | 
			
		||||
            let rh_reader = rh_reader.map_err(RPCError::protocol)?;
 | 
			
		||||
            PrivateRouteHops::FirstHop(decode_route_hop(&rh_reader)?)
 | 
			
		||||
            PrivateRouteHops::FirstHop(decode_route_hop(&rh_reader, crypto)?)
 | 
			
		||||
        }
 | 
			
		||||
        veilid_capnp::private_route::hops::Which::Data(rhd_reader) => {
 | 
			
		||||
            let rhd_reader = rhd_reader.map_err(RPCError::protocol)?;
 | 
			
		||||
@@ -156,10 +160,10 @@ pub fn encode_safety_route(
 | 
			
		||||
    safety_route: &SafetyRoute,
 | 
			
		||||
    builder: &mut veilid_capnp::safety_route::Builder,
 | 
			
		||||
) -> Result<(), RPCError> {
 | 
			
		||||
    encode_key256(
 | 
			
		||||
    encode_typed_key(
 | 
			
		||||
        &safety_route.public_key,
 | 
			
		||||
        &mut builder.reborrow().init_public_key(),
 | 
			
		||||
    )?;
 | 
			
		||||
    );
 | 
			
		||||
    builder.set_hop_count(safety_route.hop_count);
 | 
			
		||||
    let h_builder = builder.reborrow().init_hops();
 | 
			
		||||
    match &safety_route.hops {
 | 
			
		||||
@@ -178,12 +182,13 @@ pub fn encode_safety_route(
 | 
			
		||||
 | 
			
		||||
pub fn decode_safety_route(
 | 
			
		||||
    reader: &veilid_capnp::safety_route::Reader,
 | 
			
		||||
    crypto: Crypto,
 | 
			
		||||
) -> Result<SafetyRoute, RPCError> {
 | 
			
		||||
    let public_key = decode_key256(
 | 
			
		||||
    let public_key = decode_typed_key(
 | 
			
		||||
        &reader
 | 
			
		||||
            .get_public_key()
 | 
			
		||||
            .map_err(RPCError::map_protocol("invalid public key in safety route"))?,
 | 
			
		||||
    );
 | 
			
		||||
    )?;
 | 
			
		||||
    let hop_count = reader.get_hop_count();
 | 
			
		||||
    let hops = match reader.get_hops().which().map_err(RPCError::protocol)? {
 | 
			
		||||
        veilid_capnp::safety_route::hops::Which::Data(rhd_reader) => {
 | 
			
		||||
@@ -192,7 +197,7 @@ pub fn decode_safety_route(
 | 
			
		||||
        }
 | 
			
		||||
        veilid_capnp::safety_route::hops::Which::Private(pr_reader) => {
 | 
			
		||||
            let pr_reader = pr_reader.map_err(RPCError::protocol)?;
 | 
			
		||||
            SafetyRouteHops::Private(decode_private_route(&pr_reader)?)
 | 
			
		||||
            SafetyRouteHops::Private(decode_private_route(&pr_reader, crypto)?)
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -162,8 +162,9 @@ impl RPCProcessor {
 | 
			
		||||
                }
 | 
			
		||||
                SafetySelection::Safe(safety_spec) => {
 | 
			
		||||
                    // Sent directly but with a safety route, respond to private route
 | 
			
		||||
                    let ck = target.best_node_id().kind;
 | 
			
		||||
                    let Some(pr_key) = rss
 | 
			
		||||
                            .get_private_route_for_safety_spec(safety_spec, &target.node_ids())
 | 
			
		||||
                            .get_private_route_for_safety_spec(ck, safety_spec, &target.node_ids().keys())
 | 
			
		||||
                            .map_err(RPCError::internal)? else {
 | 
			
		||||
                                return Ok(NetworkResult::no_connection_other("no private route for response at this time"));
 | 
			
		||||
                            };
 | 
			
		||||
@@ -187,10 +188,12 @@ impl RPCProcessor {
 | 
			
		||||
                }
 | 
			
		||||
                SafetySelection::Safe(safety_spec) => {
 | 
			
		||||
                    // Sent via a relay but with a safety route, respond to private route
 | 
			
		||||
                    let ck = target.best_node_id().kind;
 | 
			
		||||
 | 
			
		||||
                    let mut avoid_nodes = relay.node_ids();
 | 
			
		||||
                    avoid_nodes.add_all(&target.node_ids());
 | 
			
		||||
                    let Some(pr_key) = rss
 | 
			
		||||
                        .get_private_route_for_safety_spec(safety_spec, &avoid_nodes)
 | 
			
		||||
                        .get_private_route_for_safety_spec(ck, safety_spec, &avoid_nodes.keys())
 | 
			
		||||
                        .map_err(RPCError::internal)? else {
 | 
			
		||||
                            return Ok(NetworkResult::no_connection_other("no private route for response at this time"));
 | 
			
		||||
                        };
 | 
			
		||||
@@ -219,13 +222,13 @@ impl RPCProcessor {
 | 
			
		||||
 | 
			
		||||
                        // Determine if we can use optimized nodeinfo
 | 
			
		||||
                        let route_node = match rss
 | 
			
		||||
                            .has_remote_private_route_seen_our_node_info(&private_route.public_key)
 | 
			
		||||
                            .has_remote_private_route_seen_our_node_info(&private_route.public_key.key)
 | 
			
		||||
                        {
 | 
			
		||||
                            true => {
 | 
			
		||||
                                if !routing_table.has_valid_own_node_info(RoutingDomain::PublicInternet) {
 | 
			
		||||
                                    return Ok(NetworkResult::no_connection_other("Own node info must be valid to use private route"));
 | 
			
		||||
                                }
 | 
			
		||||
                                RouteNode::NodeId(routing_table.node_id(crypto_kind))
 | 
			
		||||
                                RouteNode::NodeId(routing_table.node_id(crypto_kind).key)
 | 
			
		||||
                            }
 | 
			
		||||
                            false => {
 | 
			
		||||
                                let Some(own_peer_info) = 
 | 
			
		||||
@@ -245,14 +248,14 @@ impl RPCProcessor {
 | 
			
		||||
 | 
			
		||||
                        // Check for loopback test
 | 
			
		||||
                        let pr_key = if safety_spec.preferred_route
 | 
			
		||||
                            == Some(private_route.public_key)
 | 
			
		||||
                            == Some(private_route.public_key.key)
 | 
			
		||||
                        {
 | 
			
		||||
                            // Private route is also safety route during loopback test
 | 
			
		||||
                            private_route.public_key
 | 
			
		||||
                            private_route.public_key.key
 | 
			
		||||
                        } else {
 | 
			
		||||
                            // Get the privat route to respond to that matches the safety route spec we sent the request with
 | 
			
		||||
                            // Get the private route to respond to that matches the safety route spec we sent the request with
 | 
			
		||||
                            let Some(pr_key) = rss
 | 
			
		||||
                                .get_private_route_for_safety_spec(safety_spec, &[avoid_node_id])
 | 
			
		||||
                                .get_private_route_for_safety_spec(crypto_kind, safety_spec, &[avoid_node_id])
 | 
			
		||||
                                .map_err(RPCError::internal)? else {
 | 
			
		||||
                                    return Ok(NetworkResult::no_connection_other("no private route for response at this time"));
 | 
			
		||||
                                };
 | 
			
		||||
@@ -300,18 +303,25 @@ impl RPCProcessor {
 | 
			
		||||
                };
 | 
			
		||||
 | 
			
		||||
                // Reply directly to the request's source
 | 
			
		||||
                let sender_id = TypedKey::new(detail.envelope.get_crypto_kind(), detail.envelope.get_sender_id();
 | 
			
		||||
                let sender_node_id = TypedKey::new(detail.envelope.get_crypto_kind(), 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
 | 
			
		||||
                xxx continue here, make sure respond to semantics are correct
 | 
			
		||||
                if peer_noderef.node_id() == sender_id {
 | 
			
		||||
                if peer_noderef.node_ids().contains(&sender_node_id) {
 | 
			
		||||
                    NetworkResult::value(Destination::direct(peer_noderef))
 | 
			
		||||
                } else {
 | 
			
		||||
                    NetworkResult::value(Destination::relay(peer_noderef, sender_id))
 | 
			
		||||
                    // Look up the sender node, we should have added it via senderNodeInfo before getting here.
 | 
			
		||||
                    if let Some(sender_noderef) = self.routing_table.lookup_node_ref(sender_node_id) {
 | 
			
		||||
                        NetworkResult::value(Destination::relay(peer_noderef, sender_noderef))    
 | 
			
		||||
                    } else {
 | 
			
		||||
                        return NetworkResult::invalid_message(
 | 
			
		||||
                            "not responding to sender that has no node info",
 | 
			
		||||
                        );
 | 
			
		||||
                    }
 | 
			
		||||
                    
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            RespondTo::PrivateRoute(pr) => {
 | 
			
		||||
 
 | 
			
		||||
@@ -179,22 +179,22 @@ struct RenderedOperation {
 | 
			
		||||
 | 
			
		||||
/// Node information exchanged during every RPC message
 | 
			
		||||
#[derive(Default, Debug, Clone)]
 | 
			
		||||
pub struct SenderSignedNodeInfo {
 | 
			
		||||
    /// The current signed node info of the sender if required
 | 
			
		||||
    signed_node_info: Option<SignedNodeInfo>,
 | 
			
		||||
pub struct SenderPeerInfo {
 | 
			
		||||
    /// The current peer info of the sender if required
 | 
			
		||||
    opt_sender_peer_info: Option<PeerInfo>,
 | 
			
		||||
    /// The last timestamp of the target's node info to assist remote node with sending its latest node info
 | 
			
		||||
    target_node_info_ts: Timestamp,
 | 
			
		||||
}
 | 
			
		||||
impl SenderSignedNodeInfo {
 | 
			
		||||
    pub fn new_no_sni(target_node_info_ts: Timestamp) -> Self {
 | 
			
		||||
impl SenderPeerInfo {
 | 
			
		||||
    pub fn new_no_peer_info(target_node_info_ts: Timestamp) -> Self {
 | 
			
		||||
        Self {
 | 
			
		||||
            signed_node_info: None,
 | 
			
		||||
            opt_sender_peer_info: None,
 | 
			
		||||
            target_node_info_ts,
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    pub fn new(sender_signed_node_info: SignedNodeInfo, target_node_info_ts: Timestamp) -> Self {
 | 
			
		||||
    pub fn new(sender_peer_info: PeerInfo, target_node_info_ts: Timestamp) -> Self {
 | 
			
		||||
        Self {
 | 
			
		||||
            signed_node_info: Some(sender_signed_node_info),
 | 
			
		||||
            opt_sender_peer_info: Some(sender_peer_info),
 | 
			
		||||
            target_node_info_ts,
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
@@ -686,17 +686,14 @@ impl RPCProcessor {
 | 
			
		||||
    /// Get signed node info to package with RPC messages to improve
 | 
			
		||||
    /// routing table caching when it is okay to do so
 | 
			
		||||
    #[instrument(level = "trace", skip(self), ret, err)]
 | 
			
		||||
    fn get_sender_signed_node_info(
 | 
			
		||||
        &self,
 | 
			
		||||
        dest: &Destination,
 | 
			
		||||
    ) -> Result<SenderSignedNodeInfo, RPCError> {
 | 
			
		||||
    fn get_sender_signed_node_info(&self, dest: &Destination) -> Result<SenderPeerInfo, RPCError> {
 | 
			
		||||
        // Don't do this if the sender is to remain private
 | 
			
		||||
        // Otherwise we would be attaching the original sender's identity to the final destination,
 | 
			
		||||
        // thus defeating the purpose of the safety route entirely :P
 | 
			
		||||
        match dest.get_safety_selection() {
 | 
			
		||||
            SafetySelection::Unsafe(_) => {}
 | 
			
		||||
            SafetySelection::Safe(_) => {
 | 
			
		||||
                return Ok(SenderSignedNodeInfo::default());
 | 
			
		||||
                return Ok(SenderPeerInfo::default());
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -716,14 +713,14 @@ impl RPCProcessor {
 | 
			
		||||
                    target
 | 
			
		||||
                } else {
 | 
			
		||||
                    // Target was not in our routing table
 | 
			
		||||
                    return Ok(SenderSignedNodeInfo::default());
 | 
			
		||||
                    return Ok(SenderPeerInfo::default());
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            Destination::PrivateRoute {
 | 
			
		||||
                private_route: _,
 | 
			
		||||
                safety_selection: _,
 | 
			
		||||
            } => {
 | 
			
		||||
                return Ok(SenderSignedNodeInfo::default());
 | 
			
		||||
                return Ok(SenderPeerInfo::default());
 | 
			
		||||
            }
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
@@ -737,7 +734,7 @@ impl RPCProcessor {
 | 
			
		||||
 | 
			
		||||
        // Don't return our node info if it's not valid yet
 | 
			
		||||
        let Some(own_peer_info) = routing_table.get_own_peer_info(routing_domain) else {
 | 
			
		||||
            return Ok(SenderSignedNodeInfo::new_no_sni(target_node_info_ts));
 | 
			
		||||
            return Ok(SenderPeerInfo::new_no_peer_info(target_node_info_ts));
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        // Get our node info timestamp
 | 
			
		||||
@@ -745,10 +742,10 @@ impl RPCProcessor {
 | 
			
		||||
 | 
			
		||||
        // If the target has seen our node info already don't send it again
 | 
			
		||||
        if target.has_seen_our_node_info_ts(routing_domain, our_node_info_ts) {
 | 
			
		||||
            return Ok(SenderSignedNodeInfo::new_no_sni(target_node_info_ts));
 | 
			
		||||
            return Ok(SenderPeerInfo::new_no_peer_info(target_node_info_ts));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Ok(SenderSignedNodeInfo::new(
 | 
			
		||||
        Ok(SenderPeerInfo::new(
 | 
			
		||||
            own_peer_info.signed_node_info,
 | 
			
		||||
            target_node_info_ts,
 | 
			
		||||
        ))
 | 
			
		||||
@@ -1205,19 +1202,20 @@ impl RPCProcessor {
 | 
			
		||||
                    RPCOperation::decode(&op_reader, Some(&sender_node_id))?
 | 
			
		||||
                };
 | 
			
		||||
 | 
			
		||||
                // Get the sender noderef, incorporating and 'sender node info'
 | 
			
		||||
                // Get the sender noderef, incorporating sender's peer info
 | 
			
		||||
                let mut opt_sender_nr: Option<NodeRef> = None;
 | 
			
		||||
                if let Some(sender_node_info) = operation.sender_node_info() {
 | 
			
		||||
                    // Sender NodeInfo was specified, update our routing table with it
 | 
			
		||||
                    if !self.filter_node_info(routing_domain, &sender_node_info) {
 | 
			
		||||
                if let Some(sender_peer_info) = operation.sender_peer_info() {
 | 
			
		||||
                    // Ensure the sender peer info is for the actual sender specified in the envelope
 | 
			
		||||
 | 
			
		||||
                    // Sender PeerInfo was specified, update our routing table with it
 | 
			
		||||
                    if !self.filter_node_info(routing_domain, &sender_peer_info) {
 | 
			
		||||
                        return Err(RPCError::invalid_format(
 | 
			
		||||
                            "sender signednodeinfo has invalid peer scope",
 | 
			
		||||
                            "sender peerinfo has invalid peer scope",
 | 
			
		||||
                        ));
 | 
			
		||||
                    }
 | 
			
		||||
                    opt_sender_nr = self.routing_table().register_node_with_signed_node_info(
 | 
			
		||||
                    opt_sender_nr = self.routing_table().register_node_with_peer_info(
 | 
			
		||||
                        routing_domain,
 | 
			
		||||
                        sender_node_id,
 | 
			
		||||
                        sender_node_info.clone(),
 | 
			
		||||
                        sender_peer_info,
 | 
			
		||||
                        false,
 | 
			
		||||
                    );
 | 
			
		||||
                }
 | 
			
		||||
 
 | 
			
		||||
@@ -116,7 +116,7 @@ impl VeilidAPI {
 | 
			
		||||
    ////////////////////////////////////////////////////////////////
 | 
			
		||||
    // Attach/Detach
 | 
			
		||||
 | 
			
		||||
    // get a full copy of the current state
 | 
			
		||||
    /// Get a full copy of the current state
 | 
			
		||||
    pub async fn get_state(&self) -> Result<VeilidState, VeilidAPIError> {
 | 
			
		||||
        let attachment_manager = self.attachment_manager()?;
 | 
			
		||||
        let network_manager = attachment_manager.network_manager();
 | 
			
		||||
@@ -133,9 +133,7 @@ impl VeilidAPI {
 | 
			
		||||
        })
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // get network connectedness
 | 
			
		||||
 | 
			
		||||
    // connect to the network
 | 
			
		||||
    /// Connect to the network
 | 
			
		||||
    #[instrument(level = "debug", err, skip_all)]
 | 
			
		||||
    pub async fn attach(&self) -> Result<(), VeilidAPIError> {
 | 
			
		||||
        let attachment_manager = self.attachment_manager()?;
 | 
			
		||||
@@ -145,7 +143,7 @@ impl VeilidAPI {
 | 
			
		||||
        Ok(())
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // disconnect from the network
 | 
			
		||||
    /// Disconnect from the network
 | 
			
		||||
    #[instrument(level = "debug", err, skip_all)]
 | 
			
		||||
    pub async fn detach(&self) -> Result<(), VeilidAPIError> {
 | 
			
		||||
        let attachment_manager = self.attachment_manager()?;
 | 
			
		||||
@@ -166,8 +164,12 @@ impl VeilidAPI {
 | 
			
		||||
    ////////////////////////////////////////////////////////////////
 | 
			
		||||
    // Private route allocation
 | 
			
		||||
 | 
			
		||||
    /// Allocate a new private route set with default cryptography and network options
 | 
			
		||||
    /// Returns a list of the public key and published 'blob' pairs. Publishing as many of these
 | 
			
		||||
    /// pairs as possible to the network is desirable as support for multiple cryptography
 | 
			
		||||
    /// systems will require choosing a compatible route
 | 
			
		||||
    #[instrument(level = "debug", skip(self))]
 | 
			
		||||
    pub async fn new_private_route(&self) -> Result<(TypedKeySet, Vec<u8>), VeilidAPIError> {
 | 
			
		||||
    pub async fn new_private_route(&self) -> Result<Vec<(PublicKey, Vec<u8>)>, VeilidAPIError> {
 | 
			
		||||
        self.new_custom_private_route(
 | 
			
		||||
            &VALID_CRYPTO_KINDS,
 | 
			
		||||
            Stability::default(),
 | 
			
		||||
@@ -176,13 +178,14 @@ impl VeilidAPI {
 | 
			
		||||
        .await
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ///
 | 
			
		||||
    #[instrument(level = "debug", skip(self))]
 | 
			
		||||
    pub async fn new_custom_private_route(
 | 
			
		||||
        &self,
 | 
			
		||||
        crypto_kinds: &[CryptoKind],
 | 
			
		||||
        stability: Stability,
 | 
			
		||||
        sequencing: Sequencing,
 | 
			
		||||
    ) -> Result<(TypedKeySet, Vec<u8>), VeilidAPIError> {
 | 
			
		||||
    ) -> Result<Vec<(PublicKey, Vec<u8>)>, VeilidAPIError> {
 | 
			
		||||
        let default_route_hop_count: usize = {
 | 
			
		||||
            let config = self.config()?;
 | 
			
		||||
            let c = config.get();
 | 
			
		||||
@@ -229,14 +232,14 @@ impl VeilidAPI {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[instrument(level = "debug", skip(self))]
 | 
			
		||||
    pub fn import_remote_private_route(&self, blob: Vec<u8>) -> Result<TypedKey, VeilidAPIError> {
 | 
			
		||||
    pub fn import_remote_private_route(&self, blob: Vec<u8>) -> Result<PublicKey, VeilidAPIError> {
 | 
			
		||||
        let rss = self.routing_table()?.route_spec_store();
 | 
			
		||||
        rss.import_remote_private_route(blob)
 | 
			
		||||
            .map_err(|e| VeilidAPIError::invalid_argument(e, "blob", "private route blob"))
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[instrument(level = "debug", skip(self))]
 | 
			
		||||
    pub fn release_private_route(&self, key: &TypedKey) -> Result<(), VeilidAPIError> {
 | 
			
		||||
    pub fn release_private_route(&self, key: &PublicKey) -> Result<(), VeilidAPIError> {
 | 
			
		||||
        let rss = self.routing_table()?.route_spec_store();
 | 
			
		||||
        if rss.release_route(key) {
 | 
			
		||||
            Ok(())
 | 
			
		||||
 
 | 
			
		||||
@@ -147,7 +147,7 @@ impl VeilidAPIError {
 | 
			
		||||
    pub fn shutdown() -> Self {
 | 
			
		||||
        Self::Shutdown
 | 
			
		||||
    }
 | 
			
		||||
    pub fn key_not_found(key: TypedKey) -> Self {
 | 
			
		||||
    pub fn key_not_found(key: PublicKey) -> Self {
 | 
			
		||||
        Self::KeyNotFound { key }
 | 
			
		||||
    }
 | 
			
		||||
    pub fn no_connection<T: ToString>(msg: T) -> Self {
 | 
			
		||||
 
 | 
			
		||||
@@ -4,8 +4,8 @@ use super::*;
 | 
			
		||||
 | 
			
		||||
#[derive(Clone, Debug)]
 | 
			
		||||
pub enum Target {
 | 
			
		||||
    NodeId(TypedKey),
 | 
			
		||||
    PrivateRoute(TypedKey),
 | 
			
		||||
    NodeId(PublicKey),
 | 
			
		||||
    PrivateRoute(PublicKey),
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub struct RoutingContextInner {}
 | 
			
		||||
@@ -225,11 +225,11 @@ impl RoutingContext {
 | 
			
		||||
    ///////////////////////////////////
 | 
			
		||||
    /// Block Store
 | 
			
		||||
 | 
			
		||||
    pub async fn find_block(&self, _block_id: TypedKey) -> Result<Vec<u8>, VeilidAPIError> {
 | 
			
		||||
    pub async fn find_block(&self, _block_id: PublicKey) -> Result<Vec<u8>, VeilidAPIError> {
 | 
			
		||||
        panic!("unimplemented");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub async fn supply_block(&self, _block_id: TypedKey) -> Result<bool, VeilidAPIError> {
 | 
			
		||||
    pub async fn supply_block(&self, _block_id: PublicKey) -> Result<bool, VeilidAPIError> {
 | 
			
		||||
        panic!("unimplemented");
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -159,7 +159,7 @@ pub struct VeilidLog {
 | 
			
		||||
pub struct VeilidAppMessage {
 | 
			
		||||
    /// Some(sender) if the message was sent directly, None if received via a private/safety route
 | 
			
		||||
    #[serde(with = "opt_json_as_string")]
 | 
			
		||||
    pub sender: Option<TypedKey>,
 | 
			
		||||
    pub sender: Option<PublicKey>,
 | 
			
		||||
    /// The content of the message to deliver to the application
 | 
			
		||||
    #[serde(with = "json_as_base64")]
 | 
			
		||||
    pub message: Vec<u8>,
 | 
			
		||||
@@ -173,7 +173,7 @@ pub struct VeilidAppMessage {
 | 
			
		||||
pub struct VeilidAppCall {
 | 
			
		||||
    /// Some(sender) if the request was sent directly, None if received via a private/safety route
 | 
			
		||||
    #[serde(with = "opt_json_as_string")]
 | 
			
		||||
    pub sender: Option<TypedKey>,
 | 
			
		||||
    pub sender: Option<PublicKey>,
 | 
			
		||||
    /// The content of the request to deliver to the application
 | 
			
		||||
    #[serde(with = "json_as_base64")]
 | 
			
		||||
    pub message: Vec<u8>,
 | 
			
		||||
@@ -513,7 +513,7 @@ impl SafetySelection {
 | 
			
		||||
#[archive_attr(repr(C), derive(CheckBytes))]
 | 
			
		||||
pub struct SafetySpec {
 | 
			
		||||
    /// preferred safety route if it still exists
 | 
			
		||||
    pub preferred_route: Option<TypedKey>,
 | 
			
		||||
    pub preferred_route: Option<PublicKey>,
 | 
			
		||||
    /// must be greater than 0
 | 
			
		||||
    pub hop_count: usize,
 | 
			
		||||
    /// prefer reliability over speed
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user