mirror of
https://gitlab.com/veilid/veilid.git
synced 2024-10-01 01:26:08 -04:00
more refactor
This commit is contained in:
parent
7962d3fe11
commit
4bc3f950df
@ -41,6 +41,9 @@ pub const SHARED_SECRET_LENGTH: usize = 32;
|
|||||||
/// Length of a shared secret in bytes after encoding to base64url
|
/// Length of a shared secret in bytes after encoding to base64url
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub const SHARED_SECRET_LENGTH_ENCODED: usize = 43;
|
pub const SHARED_SECRET_LENGTH_ENCODED: usize = 43;
|
||||||
|
/// Length of a route id in bytes
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub const ROUTE_ID_LENGTH: usize = 32;
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
@ -260,3 +263,4 @@ byte_array_type!(Signature, SIGNATURE_LENGTH);
|
|||||||
byte_array_type!(PublicKeyDistance, PUBLIC_KEY_LENGTH);
|
byte_array_type!(PublicKeyDistance, PUBLIC_KEY_LENGTH);
|
||||||
byte_array_type!(Nonce, NONCE_LENGTH);
|
byte_array_type!(Nonce, NONCE_LENGTH);
|
||||||
byte_array_type!(SharedSecret, SHARED_SECRET_LENGTH);
|
byte_array_type!(SharedSecret, SHARED_SECRET_LENGTH);
|
||||||
|
byte_array_type!(RouteId, ROUTE_ID_LENGTH);
|
||||||
|
@ -11,6 +11,7 @@ use rkyv::{Archive as RkyvArchive, Deserialize as RkyvDeserialize, Serialize as
|
|||||||
pub type CryptoKind = FourCC;
|
pub type CryptoKind = FourCC;
|
||||||
|
|
||||||
/// Sort best crypto kinds first
|
/// Sort best crypto kinds first
|
||||||
|
/// Better crypto kinds are 'less', ordered toward the front of a list
|
||||||
pub fn compare_crypto_kind(a: &CryptoKind, b: &CryptoKind) -> cmp::Ordering {
|
pub fn compare_crypto_kind(a: &CryptoKind, b: &CryptoKind) -> cmp::Ordering {
|
||||||
let a_idx = VALID_CRYPTO_KINDS.iter().position(|k| k == a);
|
let a_idx = VALID_CRYPTO_KINDS.iter().position(|k| k == a);
|
||||||
let b_idx = VALID_CRYPTO_KINDS.iter().position(|k| k == b);
|
let b_idx = VALID_CRYPTO_KINDS.iter().position(|k| k == b);
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
|
mod permutation;
|
||||||
mod remote_private_route_info;
|
mod remote_private_route_info;
|
||||||
mod route_set_spec_detail;
|
mod route_set_spec_detail;
|
||||||
mod route_spec_store;
|
mod route_spec_store;
|
||||||
@ -7,6 +8,7 @@ mod route_spec_store_cache;
|
|||||||
mod route_spec_store_content;
|
mod route_spec_store_content;
|
||||||
mod route_stats;
|
mod route_stats;
|
||||||
|
|
||||||
|
pub use permutation::*;
|
||||||
pub use remote_private_route_info::*;
|
pub use remote_private_route_info::*;
|
||||||
pub use route_set_spec_detail::*;
|
pub use route_set_spec_detail::*;
|
||||||
pub use route_spec_store::*;
|
pub use route_spec_store::*;
|
||||||
@ -27,9 +29,3 @@ const REMOTE_PRIVATE_ROUTE_CACHE_EXPIRY: TimestampDuration = TimestampDuration::
|
|||||||
const ROUTE_MIN_IDLE_TIME_MS: u32 = 30_000;
|
const ROUTE_MIN_IDLE_TIME_MS: u32 = 30_000;
|
||||||
/// The size of the compiled route cache
|
/// The size of the compiled route cache
|
||||||
const COMPILED_ROUTE_CACHE_SIZE: usize = 256;
|
const COMPILED_ROUTE_CACHE_SIZE: usize = 256;
|
||||||
|
|
||||||
/// The type of an allocated route set id
|
|
||||||
pub type RouteSetSpecId = String;
|
|
||||||
|
|
||||||
/// Type type of an imported remote route set id
|
|
||||||
pub type RemotePrivateRouteId = String;
|
|
||||||
|
@ -0,0 +1,70 @@
|
|||||||
|
use super::*;
|
||||||
|
|
||||||
|
/// number of route permutations is the number of unique orderings
|
||||||
|
/// for a set of nodes, given that the first node is fixed
|
||||||
|
fn _get_route_permutation_count(hop_count: usize) -> usize {
|
||||||
|
if hop_count == 0 {
|
||||||
|
unreachable!();
|
||||||
|
}
|
||||||
|
// a single node or two nodes is always fixed
|
||||||
|
if hop_count == 1 || hop_count == 2 {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
// more than two nodes has factorial permutation
|
||||||
|
// hop_count = 3 -> 2! -> 2
|
||||||
|
// hop_count = 4 -> 3! -> 6
|
||||||
|
(3..hop_count).into_iter().fold(2usize, |acc, x| acc * x)
|
||||||
|
}
|
||||||
|
pub type PermReturnType = (Vec<usize>, bool);
|
||||||
|
pub type PermFunc<'t> = Box<dyn Fn(&[usize]) -> Option<PermReturnType> + Send + 't>;
|
||||||
|
|
||||||
|
/// get the route permutation at particular 'perm' index, starting at the 'start' index
|
||||||
|
/// for a set of 'hop_count' nodes. the first node is always fixed, and the maximum
|
||||||
|
/// number of permutations is given by get_route_permutation_count()
|
||||||
|
|
||||||
|
pub fn with_route_permutations(
|
||||||
|
hop_count: usize,
|
||||||
|
start: usize,
|
||||||
|
f: &PermFunc,
|
||||||
|
) -> Option<PermReturnType> {
|
||||||
|
if hop_count == 0 {
|
||||||
|
unreachable!();
|
||||||
|
}
|
||||||
|
// initial permutation
|
||||||
|
let mut permutation: Vec<usize> = Vec::with_capacity(hop_count);
|
||||||
|
for n in 0..hop_count {
|
||||||
|
permutation.push(start + n);
|
||||||
|
}
|
||||||
|
// if we have one hop or two, then there's only one permutation
|
||||||
|
if hop_count == 1 || hop_count == 2 {
|
||||||
|
return f(&permutation);
|
||||||
|
}
|
||||||
|
|
||||||
|
// heaps algorithm, but skipping the first element
|
||||||
|
fn heaps_permutation(
|
||||||
|
permutation: &mut [usize],
|
||||||
|
size: usize,
|
||||||
|
f: &PermFunc,
|
||||||
|
) -> Option<PermReturnType> {
|
||||||
|
if size == 1 {
|
||||||
|
return f(&permutation);
|
||||||
|
}
|
||||||
|
|
||||||
|
for i in 0..size {
|
||||||
|
let out = heaps_permutation(permutation, size - 1, f);
|
||||||
|
if out.is_some() {
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
if size % 2 == 1 {
|
||||||
|
permutation.swap(1, size);
|
||||||
|
} else {
|
||||||
|
permutation.swap(1 + i, size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
// recurse
|
||||||
|
heaps_permutation(&mut permutation, hop_count - 1, f)
|
||||||
|
}
|
@ -32,6 +32,13 @@ impl RemotePrivateRouteInfo {
|
|||||||
&mut self.stats
|
&mut self.stats
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn has_seen_our_node_info_ts(&mut self, our_node_info_ts: Timestamp) -> bool {
|
||||||
|
self.last_seen_our_node_info_ts == our_node_info_ts
|
||||||
|
}
|
||||||
|
pub fn set_last_seen_our_node_info_ts(&mut self, last_seen_our_node_info_ts: Timestamp) {
|
||||||
|
self.last_seen_our_node_info_ts = last_seen_our_node_info_ts;
|
||||||
|
}
|
||||||
|
|
||||||
// Check to see if this remote private route has expired
|
// Check to see if this remote private route has expired
|
||||||
pub fn did_expire(&self, cur_ts: Timestamp) -> bool {
|
pub fn did_expire(&self, cur_ts: Timestamp) -> bool {
|
||||||
cur_ts.saturating_sub(self.last_touched_ts) >= REMOTE_PRIVATE_ROUTE_CACHE_EXPIRY
|
cur_ts.saturating_sub(self.last_touched_ts) >= REMOTE_PRIVATE_ROUTE_CACHE_EXPIRY
|
||||||
|
@ -49,11 +49,22 @@ impl RouteSetSpecDetail {
|
|||||||
}
|
}
|
||||||
tks
|
tks
|
||||||
}
|
}
|
||||||
|
pub fn get_best_route_set_key(&self) -> Option<PublicKey> {
|
||||||
|
self.get_route_set_keys().best().map(|k| k.key)
|
||||||
|
}
|
||||||
|
pub fn set_hop_node_refs(&mut self, node_refs: Vec<NodeRef>) {
|
||||||
|
self.hop_node_refs = node_refs;
|
||||||
|
}
|
||||||
pub fn iter_route_set(
|
pub fn iter_route_set(
|
||||||
&self,
|
&self,
|
||||||
) -> alloc::collections::btree_map::Iter<PublicKey, RouteSpecDetail> {
|
) -> alloc::collections::btree_map::Iter<PublicKey, RouteSpecDetail> {
|
||||||
self.route_set.iter()
|
self.route_set.iter()
|
||||||
}
|
}
|
||||||
|
pub fn iter_route_set_mut(
|
||||||
|
&self,
|
||||||
|
) -> alloc::collections::btree_map::IterMut<PublicKey, RouteSpecDetail> {
|
||||||
|
self.route_set.iter_mut()
|
||||||
|
}
|
||||||
pub fn get_stats(&self) -> &RouteStats {
|
pub fn get_stats(&self) -> &RouteStats {
|
||||||
&self.stats
|
&self.stats
|
||||||
}
|
}
|
||||||
@ -89,24 +100,4 @@ impl RouteSetSpecDetail {
|
|||||||
}
|
}
|
||||||
cache
|
cache
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Generate a user-facing identifier for this allocated route
|
|
||||||
pub fn make_id(&self) -> RouteSetSpecId {
|
|
||||||
let mut idbytes = [0u8; 16];
|
|
||||||
for (pk, _) in self.route_set.iter() {
|
|
||||||
for (i, x) in pk.bytes.iter().enumerate() {
|
|
||||||
idbytes[i % 16] ^= *x;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let id = format!(
|
|
||||||
"{:08x}-{:04x}-{:04x}-{:04x}-{:08x}{:04x}",
|
|
||||||
u32::from_be_bytes(idbytes[0..4].try_into().expect("32 bits")),
|
|
||||||
u16::from_be_bytes(idbytes[4..6].try_into().expect("16 bits")),
|
|
||||||
u16::from_be_bytes(idbytes[6..8].try_into().expect("16 bits")),
|
|
||||||
u16::from_be_bytes(idbytes[8..10].try_into().expect("16 bits")),
|
|
||||||
u32::from_be_bytes(idbytes[10..14].try_into().expect("32 bits")),
|
|
||||||
u16::from_be_bytes(idbytes[14..16].try_into().expect("16 bits"))
|
|
||||||
);
|
|
||||||
id
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
use super::*;
|
use super::*;
|
||||||
|
use permutation::*;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct RouteSpecStoreInner {
|
pub struct RouteSpecStoreInner {
|
||||||
@ -33,75 +34,6 @@ pub struct RouteSpecStore {
|
|||||||
unlocked_inner: Arc<RouteSpecStoreUnlockedInner>,
|
unlocked_inner: Arc<RouteSpecStoreUnlockedInner>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// number of route permutations is the number of unique orderings
|
|
||||||
/// for a set of nodes, given that the first node is fixed
|
|
||||||
fn _get_route_permutation_count(hop_count: usize) -> usize {
|
|
||||||
if hop_count == 0 {
|
|
||||||
unreachable!();
|
|
||||||
}
|
|
||||||
// a single node or two nodes is always fixed
|
|
||||||
if hop_count == 1 || hop_count == 2 {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
// more than two nodes has factorial permutation
|
|
||||||
// hop_count = 3 -> 2! -> 2
|
|
||||||
// hop_count = 4 -> 3! -> 6
|
|
||||||
(3..hop_count).into_iter().fold(2usize, |acc, x| acc * x)
|
|
||||||
}
|
|
||||||
type PermReturnType = (Vec<usize>, Vec<u8>, bool);
|
|
||||||
type PermFunc<'t> = Box<dyn Fn(&[usize]) -> Option<PermReturnType> + Send + 't>;
|
|
||||||
|
|
||||||
/// get the route permutation at particular 'perm' index, starting at the 'start' index
|
|
||||||
/// for a set of 'hop_count' nodes. the first node is always fixed, and the maximum
|
|
||||||
/// number of permutations is given by get_route_permutation_count()
|
|
||||||
|
|
||||||
fn with_route_permutations(
|
|
||||||
hop_count: usize,
|
|
||||||
start: usize,
|
|
||||||
f: &PermFunc,
|
|
||||||
) -> Option<PermReturnType> {
|
|
||||||
if hop_count == 0 {
|
|
||||||
unreachable!();
|
|
||||||
}
|
|
||||||
// initial permutation
|
|
||||||
let mut permutation: Vec<usize> = Vec::with_capacity(hop_count);
|
|
||||||
for n in 0..hop_count {
|
|
||||||
permutation.push(start + n);
|
|
||||||
}
|
|
||||||
// if we have one hop or two, then there's only one permutation
|
|
||||||
if hop_count == 1 || hop_count == 2 {
|
|
||||||
return f(&permutation);
|
|
||||||
}
|
|
||||||
|
|
||||||
// heaps algorithm, but skipping the first element
|
|
||||||
fn heaps_permutation(
|
|
||||||
permutation: &mut [usize],
|
|
||||||
size: usize,
|
|
||||||
f: &PermFunc,
|
|
||||||
) -> Option<PermReturnType> {
|
|
||||||
if size == 1 {
|
|
||||||
return f(&permutation);
|
|
||||||
}
|
|
||||||
|
|
||||||
for i in 0..size {
|
|
||||||
let out = heaps_permutation(permutation, size - 1, f);
|
|
||||||
if out.is_some() {
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
if size % 2 == 1 {
|
|
||||||
permutation.swap(1, size);
|
|
||||||
} else {
|
|
||||||
permutation.swap(1 + i, size);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
// recurse
|
|
||||||
heaps_permutation(&mut permutation, hop_count - 1, f)
|
|
||||||
}
|
|
||||||
|
|
||||||
impl RouteSpecStore {
|
impl RouteSpecStore {
|
||||||
pub fn new(routing_table: RoutingTable) -> Self {
|
pub fn new(routing_table: RoutingTable) -> Self {
|
||||||
let config = routing_table.network_manager().config();
|
let config = routing_table.network_manager().config();
|
||||||
@ -135,69 +67,7 @@ impl RouteSpecStore {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Get frozen blob from table store
|
// Get frozen blob from table store
|
||||||
let table_store = routing_table.network_manager().table_store();
|
let content = RouteSpecStoreContent::load(routing_table.clone()).await?;
|
||||||
let rsstdb = table_store.open("RouteSpecStore", 1).await?;
|
|
||||||
let mut content: RouteSpecStoreContent =
|
|
||||||
rsstdb.load_rkyv(0, b"content")?.unwrap_or_default();
|
|
||||||
|
|
||||||
// Look up all route hop noderefs since we can't serialize those
|
|
||||||
let mut dead_ids = Vec::new();
|
|
||||||
for (rsid, rssd) in content.iter_details_mut() {
|
|
||||||
// Get first route since they all should resolve
|
|
||||||
let Some((pk, rsd)) = rssd.route_set.first_key_value() else {
|
|
||||||
dead_ids.push(rsid.clone());
|
|
||||||
continue;
|
|
||||||
};
|
|
||||||
// Go through first route
|
|
||||||
for h in &rsd.hops {
|
|
||||||
let Some(nr) = routing_table.lookup_node_ref(TypedKey::new(rsd.crypto_kind, *h)) else {
|
|
||||||
dead_ids.push(rsid.clone());
|
|
||||||
break;
|
|
||||||
};
|
|
||||||
rssd.hop_node_refs.push(nr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for id in dead_ids {
|
|
||||||
log_rtab!(debug "no entry, killing off private route: {}", id);
|
|
||||||
content.remove_detail(&id);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Load secrets from pstore
|
|
||||||
let pstore = routing_table.network_manager().protected_store();
|
|
||||||
let secret_key_map: HashMap<PublicKey, SecretKey> = pstore
|
|
||||||
.load_user_secret_rkyv("RouteSpecStore")
|
|
||||||
.await?
|
|
||||||
.unwrap_or_default();
|
|
||||||
|
|
||||||
// Ensure we got secret keys for all the public keys
|
|
||||||
let mut got_secret_key_ids = HashSet::new();
|
|
||||||
for (rsid, rssd) in content.iter_details_mut() {
|
|
||||||
let mut found_all = true;
|
|
||||||
for (pk, rsd) in &mut rssd.route_set {
|
|
||||||
if let Some(sk) = secret_key_map.get(pk) {
|
|
||||||
rsd.secret_key = *sk;
|
|
||||||
} else {
|
|
||||||
found_all = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if found_all {
|
|
||||||
got_secret_key_ids.insert(rsid.clone());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we missed any, nuke those route ids
|
|
||||||
let dead_ids:Vec<String> = content.keys().filter_map(|id| {
|
|
||||||
if !got_secret_key_ids.contains(id) {
|
|
||||||
Some(id.clone())
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}).collect();
|
|
||||||
for id in dead_ids {
|
|
||||||
log_rtab!(debug "missing secret key, killing off private route: {}", id);
|
|
||||||
content.remove_detail(&id);
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut inner = RouteSpecStoreInner {
|
let mut inner = RouteSpecStoreInner {
|
||||||
content,
|
content,
|
||||||
@ -230,31 +100,8 @@ impl RouteSpecStore {
|
|||||||
inner.content.clone()
|
inner.content.clone()
|
||||||
};
|
};
|
||||||
|
|
||||||
// Save all the fields we care about to the frozen blob in table storage
|
// Save our content
|
||||||
// This skips #[with(Skip)] saving the secret keys, we save them in the protected store instead
|
content.save(self.unlocked_inner.routing_table.clone()).await?;
|
||||||
let table_store = self
|
|
||||||
.unlocked_inner
|
|
||||||
.routing_table
|
|
||||||
.network_manager()
|
|
||||||
.table_store();
|
|
||||||
let rsstdb = table_store.open("RouteSpecStore", 1).await?;
|
|
||||||
rsstdb.store_rkyv(0, b"content", &content).await?;
|
|
||||||
|
|
||||||
// // Keep secrets in protected store as well
|
|
||||||
let pstore = self
|
|
||||||
.unlocked_inner
|
|
||||||
.routing_table
|
|
||||||
.network_manager()
|
|
||||||
.protected_store();
|
|
||||||
|
|
||||||
let mut out: HashMap<PublicKey, SecretKey> = HashMap::new();
|
|
||||||
for (rsid, rssd) in content.iter_details() {
|
|
||||||
for (pk, rsd) in &rssd.route_set {
|
|
||||||
out.insert(*pk, rsd.secret_key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let _ = pstore.save_user_secret_rkyv("RouteSpecStore", &out).await?; // ignore if this previously existed or not
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -263,7 +110,11 @@ impl RouteSpecStore {
|
|||||||
pub fn send_route_update(&self) {
|
pub fn send_route_update(&self) {
|
||||||
let (dead_routes, dead_remote_routes) = {
|
let (dead_routes, dead_remote_routes) = {
|
||||||
let mut inner = self.inner.lock();
|
let mut inner = self.inner.lock();
|
||||||
inner.cache.take_dead_routes()
|
let Some(dr) = inner.cache.take_dead_routes() else {
|
||||||
|
// Nothing to do
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
dr
|
||||||
};
|
};
|
||||||
|
|
||||||
let update = VeilidUpdate::Route(VeilidStateRoute {
|
let update = VeilidUpdate::Route(VeilidStateRoute {
|
||||||
@ -275,8 +126,6 @@ impl RouteSpecStore {
|
|||||||
update_callback(update);
|
update_callback(update);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// Purge the route spec store
|
/// Purge the route spec store
|
||||||
pub async fn purge(&self) -> EyreResult<()> {
|
pub async fn purge(&self) -> EyreResult<()> {
|
||||||
{
|
{
|
||||||
@ -301,7 +150,7 @@ impl RouteSpecStore {
|
|||||||
hop_count: usize,
|
hop_count: usize,
|
||||||
directions: DirectionSet,
|
directions: DirectionSet,
|
||||||
avoid_nodes: &[TypedKey],
|
avoid_nodes: &[TypedKey],
|
||||||
) -> EyreResult<Option<String>> {
|
) -> EyreResult<Option<RouteId>> {
|
||||||
let inner = &mut *self.inner.lock();
|
let inner = &mut *self.inner.lock();
|
||||||
let routing_table = self.unlocked_inner.routing_table.clone();
|
let routing_table = self.unlocked_inner.routing_table.clone();
|
||||||
let rti = &mut *routing_table.inner.write();
|
let rti = &mut *routing_table.inner.write();
|
||||||
@ -329,7 +178,7 @@ impl RouteSpecStore {
|
|||||||
hop_count: usize,
|
hop_count: usize,
|
||||||
directions: DirectionSet,
|
directions: DirectionSet,
|
||||||
avoid_nodes: &[TypedKey],
|
avoid_nodes: &[TypedKey],
|
||||||
) -> EyreResult<Option<String>> {
|
) -> EyreResult<Option<RouteId>> {
|
||||||
use core::cmp::Ordering;
|
use core::cmp::Ordering;
|
||||||
|
|
||||||
if hop_count < 1 {
|
if hop_count < 1 {
|
||||||
@ -625,7 +474,7 @@ impl RouteSpecStore {
|
|||||||
|
|
||||||
for start in 0..(nodes.len() - hop_count) {
|
for start in 0..(nodes.len() - hop_count) {
|
||||||
// Try the permutations available starting with 'start'
|
// Try the permutations available starting with 'start'
|
||||||
if let Some((rn, ck, cds)) = with_route_permutations(hop_count, start, &perm_func) {
|
if let Some((rn, cds)) = with_route_permutations(hop_count, start, &perm_func) {
|
||||||
route_nodes = rn;
|
route_nodes = rn;
|
||||||
can_do_sequenced = cds;
|
can_do_sequenced = cds;
|
||||||
break;
|
break;
|
||||||
@ -666,11 +515,14 @@ impl RouteSpecStore {
|
|||||||
|
|
||||||
drop(perm_func);
|
drop(perm_func);
|
||||||
|
|
||||||
|
// make id
|
||||||
|
let id = self.generate_allocated_route_id(&rssd)?;
|
||||||
|
|
||||||
// Add to cache
|
// Add to cache
|
||||||
inner.cache.add_to_cache(&rssd);
|
inner.cache.add_to_cache(&rssd);
|
||||||
|
|
||||||
// Keep route in spec store
|
// Keep route in spec store
|
||||||
let id = inner.content.add_detail(rssd);
|
inner.content.add_detail(id.clone(), rssd);
|
||||||
|
|
||||||
Ok(Some(id))
|
Ok(Some(id))
|
||||||
}
|
}
|
||||||
@ -737,23 +589,18 @@ impl RouteSpecStore {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[instrument(level = "trace", skip(self), ret, err)]
|
#[instrument(level = "trace", skip(self), ret, err)]
|
||||||
async fn test_allocated_route(&self, id: &String) -> EyreResult<bool> {
|
async fn test_allocated_route(&self, private_route_id: RouteId) -> EyreResult<bool> {
|
||||||
// Make loopback route to test with
|
// Make loopback route to test with
|
||||||
let dest = {
|
let dest = {
|
||||||
|
|
||||||
// Get best route from set
|
|
||||||
// Match the private route's hop length for safety route length
|
// Match the private route's hop length for safety route length
|
||||||
let (key, hop_count) = {
|
let hop_count = {
|
||||||
let inner = &mut *self.inner.lock();
|
let inner = &mut *self.inner.lock();
|
||||||
let Some(rssd) = inner.content.get_detail(id) else {
|
let Some(rssd) = inner.content.get_detail(&private_route_id) else {
|
||||||
bail!("route id not allocated");
|
bail!("route id not allocated");
|
||||||
};
|
};
|
||||||
let Some(tkey) = rssd.get_route_set_keys().best() else {
|
rssd.hop_count()
|
||||||
bail!("route does not have best key");
|
|
||||||
};
|
|
||||||
(tkey.key, rssd.hop_count())
|
|
||||||
};
|
};
|
||||||
let private_route = self.assemble_private_route(&key, None)?;
|
|
||||||
|
|
||||||
// Always test routes with safety routes that are more likely to succeed
|
// Always test routes with safety routes that are more likely to succeed
|
||||||
let stability = Stability::Reliable;
|
let stability = Stability::Reliable;
|
||||||
@ -761,7 +608,7 @@ impl RouteSpecStore {
|
|||||||
let sequencing = Sequencing::NoPreference;
|
let sequencing = Sequencing::NoPreference;
|
||||||
|
|
||||||
let safety_spec = SafetySpec {
|
let safety_spec = SafetySpec {
|
||||||
preferred_route: Some(key.clone()),
|
preferred_route: Some(private_route_id),
|
||||||
hop_count,
|
hop_count,
|
||||||
stability,
|
stability,
|
||||||
sequencing,
|
sequencing,
|
||||||
@ -769,7 +616,7 @@ impl RouteSpecStore {
|
|||||||
let safety_selection = SafetySelection::Safe(safety_spec);
|
let safety_selection = SafetySelection::Safe(safety_spec);
|
||||||
|
|
||||||
Destination::PrivateRoute {
|
Destination::PrivateRoute {
|
||||||
private_route,
|
private_route_id,
|
||||||
safety_selection,
|
safety_selection,
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -788,18 +635,10 @@ impl RouteSpecStore {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[instrument(level = "trace", skip(self), ret, err)]
|
#[instrument(level = "trace", skip(self), ret, err)]
|
||||||
async fn test_remote_route(&self, id: &String) -> EyreResult<bool> {
|
async fn test_remote_route(&self, private_route_id: RouteId) -> EyreResult<bool> {
|
||||||
|
|
||||||
// Make private route test
|
// Make private route test
|
||||||
let dest = {
|
let dest = {
|
||||||
// Get best remote route from imported set
|
|
||||||
|
|
||||||
// Get the route to test
|
|
||||||
let private_route = match self.peek_remote_private_route(id) {
|
|
||||||
Some(pr) => pr,
|
|
||||||
None => return Ok(false),
|
|
||||||
};
|
|
||||||
|
|
||||||
// Get a safety route that is good enough
|
// Get a safety route that is good enough
|
||||||
let safety_spec = SafetySpec {
|
let safety_spec = SafetySpec {
|
||||||
preferred_route: None,
|
preferred_route: None,
|
||||||
@ -811,7 +650,7 @@ impl RouteSpecStore {
|
|||||||
let safety_selection = SafetySelection::Safe(safety_spec);
|
let safety_selection = SafetySelection::Safe(safety_spec);
|
||||||
|
|
||||||
Destination::PrivateRoute {
|
Destination::PrivateRoute {
|
||||||
private_route,
|
private_route_id,
|
||||||
safety_selection,
|
safety_selection,
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -829,52 +668,44 @@ impl RouteSpecStore {
|
|||||||
Ok(true)
|
Ok(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Test an allocated route for continuity
|
|
||||||
#[instrument(level = "trace", skip(self), ret, err)]
|
|
||||||
pub async fn test_route(&self, key: &[TypedKey]) -> EyreResult<bool> {
|
|
||||||
let is_remote = {
|
|
||||||
let inner = &mut *self.inner.lock();
|
|
||||||
let cur_ts = get_aligned_timestamp();
|
|
||||||
Self::with_peek_remote_private_route(inner, cur_ts, key, |_| {}).is_some()
|
|
||||||
};
|
|
||||||
if is_remote {
|
|
||||||
self.test_remote_route(key).await
|
|
||||||
} else {
|
|
||||||
self.test_allocated_route(key).await
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Release an allocated route that is no longer in use
|
/// Release an allocated route that is no longer in use
|
||||||
#[instrument(level = "trace", skip(self), ret)]
|
#[instrument(level = "trace", skip(self), ret)]
|
||||||
fn release_allocated_route(&self, id: &String) -> bool {
|
fn release_allocated_route(&self, id: RouteId) -> bool {
|
||||||
let mut inner = self.inner.lock();
|
let mut inner = self.inner.lock();
|
||||||
let Some(rssd) = inner.content.remove_detail(id) else {
|
let Some(rssd) = inner.content.remove_detail(&id) else {
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Remove from hop cache
|
// Remove from hop cache
|
||||||
if !inner.cache.remove_from_cache(&rssd) {
|
if !inner.cache.remove_from_cache(id, &rssd) {
|
||||||
panic!("hop cache should have contained cache key");
|
panic!("hop cache should have contained cache key");
|
||||||
}
|
}
|
||||||
|
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Check if a route id is remote or not
|
||||||
|
fn is_route_id_remote(&self, id: &RouteId) -> bool {
|
||||||
|
let inner = &mut *self.inner.lock();
|
||||||
|
let cur_ts = get_aligned_timestamp();
|
||||||
|
inner.cache.peek_remote_private_route_mut(cur_ts, &id).is_some()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Test an allocated route for continuity
|
||||||
|
#[instrument(level = "trace", skip(self), ret, err)]
|
||||||
|
pub async fn test_route(&self, id: RouteId) -> EyreResult<bool> {
|
||||||
|
let is_remote = self.is_route_id_remote(&id);
|
||||||
|
if is_remote {
|
||||||
|
self.test_remote_route(id).await
|
||||||
|
} else {
|
||||||
|
self.test_allocated_route(id).await
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Release an allocated or remote route that is no longer in use
|
/// Release an allocated or remote route that is no longer in use
|
||||||
#[instrument(level = "trace", skip(self), ret)]
|
#[instrument(level = "trace", skip(self), ret)]
|
||||||
pub fn release_route(&self, id: &String) -> bool {
|
pub fn release_route(&self, id: RouteId) -> bool {
|
||||||
|
let is_remote = self.is_route_id_remote(&id);
|
||||||
let is_remote = {
|
|
||||||
let inner = &mut *self.inner.lock();
|
|
||||||
|
|
||||||
// Release from compiled route cache if it's used there
|
|
||||||
self.invalidate_compiled_route_cache(inner, id);
|
|
||||||
|
|
||||||
// Check to see if this is a remote route
|
|
||||||
let cur_ts = get_aligned_timestamp();
|
|
||||||
Self::with_peek_remote_private_route(inner, cur_ts, id, |_| {}).is_some()
|
|
||||||
};
|
|
||||||
|
|
||||||
if is_remote {
|
if is_remote {
|
||||||
self.release_remote_private_route(id)
|
self.release_remote_private_route(id)
|
||||||
} else {
|
} else {
|
||||||
@ -943,11 +774,11 @@ impl RouteSpecStore {
|
|||||||
/// List all allocated routes
|
/// List all allocated routes
|
||||||
pub fn list_allocated_routes<F, R>(&self, mut filter: F) -> Vec<R>
|
pub fn list_allocated_routes<F, R>(&self, mut filter: F) -> Vec<R>
|
||||||
where
|
where
|
||||||
F: FnMut(&PublicKey, &RouteSetSpecDetail) -> Option<R>,
|
F: FnMut(&RouteId, &RouteSetSpecDetail) -> Option<R>,
|
||||||
{
|
{
|
||||||
let inner = self.inner.lock();
|
let inner = self.inner.lock();
|
||||||
let mut out = Vec::with_capacity(inner.content.details.len());
|
let mut out = Vec::with_capacity(inner.content.get_detail_count());
|
||||||
for detail in &inner.content.details {
|
for detail in inner.content.iter_details() {
|
||||||
if let Some(x) = filter(detail.0, detail.1) {
|
if let Some(x) = filter(detail.0, detail.1) {
|
||||||
out.push(x);
|
out.push(x);
|
||||||
}
|
}
|
||||||
@ -958,11 +789,11 @@ impl RouteSpecStore {
|
|||||||
/// List all allocated routes
|
/// List all allocated routes
|
||||||
pub fn list_remote_routes<F, R>(&self, mut filter: F) -> Vec<R>
|
pub fn list_remote_routes<F, R>(&self, mut filter: F) -> Vec<R>
|
||||||
where
|
where
|
||||||
F: FnMut(&PublicKey, &RemotePrivateRouteInfo) -> Option<R>,
|
F: FnMut(&RouteId, &RemotePrivateRouteInfo) -> Option<R>,
|
||||||
{
|
{
|
||||||
let inner = self.inner.lock();
|
let inner = self.inner.lock();
|
||||||
let mut out = Vec::with_capacity(inner.cache.remote_private_route_cache.len());
|
let mut out = Vec::with_capacity(inner.cache.get_remote_private_route_count());
|
||||||
for info in &inner.cache.remote_private_route_cache {
|
for info in inner.cache.iter_remote_private_routes() {
|
||||||
if let Some(x) = filter(info.0, info.1) {
|
if let Some(x) = filter(info.0, info.1) {
|
||||||
out.push(x);
|
out.push(x);
|
||||||
}
|
}
|
||||||
@ -971,56 +802,20 @@ impl RouteSpecStore {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Get the debug description of a route
|
/// Get the debug description of a route
|
||||||
pub fn debug_route(&self, key: &PublicKey) -> Option<String> {
|
pub fn debug_route(&self, id: &RouteId) -> Option<String> {
|
||||||
let inner = &mut *self.inner.lock();
|
let inner = &mut *self.inner.lock();
|
||||||
let cur_ts = get_aligned_timestamp();
|
let cur_ts = get_aligned_timestamp();
|
||||||
// If this is a remote route, print it
|
if let Some(rpri) = inner.cache.peek_remote_private_route_mut(cur_ts, &id) {
|
||||||
if let Some(s) =
|
return Some(format!("{:#?}", rpri));
|
||||||
Self::with_peek_remote_private_route(inner, cur_ts, key, |rpi| format!("{:#?}", rpi))
|
|
||||||
{
|
|
||||||
return Some(s);
|
|
||||||
}
|
}
|
||||||
// Otherwise check allocated routes
|
if let Some(rssd) = inner.content.get_detail(id) {
|
||||||
Self::detail(inner, key).map(|rsd| format!("{:#?}", rsd))
|
return Some(format!("{:#?}", rssd));
|
||||||
|
}
|
||||||
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
// Route cache
|
|
||||||
fn add_to_compiled_route_cache(&self, inner: &mut RouteSpecStoreInner, pr_pubkey: PublicKey, safety_route: SafetyRoute)
|
|
||||||
{
|
|
||||||
let key = CompiledRouteCacheKey {
|
|
||||||
sr_pubkey: safety_route.public_key,
|
|
||||||
pr_pubkey,
|
|
||||||
};
|
|
||||||
|
|
||||||
if let Some(v) = inner.cache.compiled_route_cache.insert(key, safety_route) {
|
|
||||||
log_rtab!(error "route cache already contained key: sr_pubkey={:?}, pr_pubkey={:?}", v.public_key, pr_pubkey);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn lookup_compiled_route_cache(&self, inner: &mut RouteSpecStoreInner, sr_pubkey: PublicKey, pr_pubkey: PublicKey) -> Option<SafetyRoute> {
|
|
||||||
|
|
||||||
let key = CompiledRouteCacheKey {
|
|
||||||
sr_pubkey,
|
|
||||||
pr_pubkey,
|
|
||||||
};
|
|
||||||
|
|
||||||
inner.cache.compiled_route_cache.get(&key).cloned()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn invalidate_compiled_route_cache(&self, inner: &mut RouteSpecStoreInner, dead_key: &PublicKey) {
|
|
||||||
let mut dead_entries = Vec::new();
|
|
||||||
for (k, _v) in inner.cache.compiled_route_cache.iter() {
|
|
||||||
if k.sr_pubkey == *dead_key || k.pr_pubkey == *dead_key {
|
|
||||||
dead_entries.push(k.clone());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for d in dead_entries {
|
|
||||||
inner.cache.compiled_route_cache.remove(&d);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Compiles a safety route to the private route, with caching
|
/// Compiles a safety route to the private route, with caching
|
||||||
/// Returns an Err() if the parameters are wrong
|
/// Returns an Err() if the parameters are wrong
|
||||||
/// Returns Ok(None) if no allocation could happen at this time (not an error)
|
/// Returns Ok(None) if no allocation could happen at this time (not an error)
|
||||||
@ -1441,16 +1236,20 @@ impl RouteSpecStore {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Import a remote private route for compilation
|
/// Import a remote private route for compilation
|
||||||
/// returns a route set id
|
/// It is safe to import the same route more than once and it will return the same route id
|
||||||
|
/// Returns a route set id
|
||||||
#[instrument(level = "trace", skip(self, blob), ret, err)]
|
#[instrument(level = "trace", skip(self, blob), ret, err)]
|
||||||
pub fn import_remote_private_route(&self, blob: Vec<u8>) -> EyreResult<String> {
|
pub fn import_remote_private_route(&self, blob: Vec<u8>) -> EyreResult<RouteId> {
|
||||||
|
let cur_ts = get_aligned_timestamp();
|
||||||
|
|
||||||
// decode the pr blob
|
// decode the pr blob
|
||||||
let private_routes = RouteSpecStore::blob_to_private_routes(self.unlocked_inner.routing_table.crypto(), blob)?;
|
let private_routes = RouteSpecStore::blob_to_private_routes(self.unlocked_inner.routing_table.crypto(), blob)?;
|
||||||
|
|
||||||
let inner = &mut *self.inner.lock();
|
// make the route id
|
||||||
|
let id = self.generate_remote_route_id(&private_routes)?;
|
||||||
|
|
||||||
// validate the private routes
|
// validate the private routes
|
||||||
|
let inner = &mut *self.inner.lock();
|
||||||
for private_route in private_routes {
|
for private_route in private_routes {
|
||||||
|
|
||||||
// ensure private route has first hop
|
// ensure private route has first hop
|
||||||
@ -1464,62 +1263,63 @@ impl RouteSpecStore {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let cur_ts = get_aligned_timestamp();
|
inner.cache.cache_remote_private_route(cur_ts, id, private_routes);
|
||||||
let id = inner.cache.import_remote_private_route(cur_ts, private_routes);
|
|
||||||
|
|
||||||
Ok(id)
|
Ok(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Release a remote private route that is no longer in use
|
/// Release a remote private route that is no longer in use
|
||||||
#[instrument(level = "trace", skip(self), ret)]
|
#[instrument(level = "trace", skip(self), ret)]
|
||||||
fn release_remote_private_route(&self, id: &String) -> bool {
|
pub fn release_remote_private_route(&self, id: RouteId) -> bool {
|
||||||
let inner = &mut *self.inner.lock();
|
let inner = &mut *self.inner.lock();
|
||||||
inner.cache.remove_remote_private_route(id)
|
inner.cache.remove_remote_private_route(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Retrieve an imported remote private route by its public key
|
/// Check if a remote private route id is valid
|
||||||
pub fn get_remote_private_route(&self, id: &String) -> Option<PrivateRoute> {
|
#[instrument(level = "trace", skip(self), ret)]
|
||||||
|
pub fn is_valid_remote_private_route(&self, id: &RouteId) -> bool {
|
||||||
let inner = &mut *self.inner.lock();
|
let inner = &mut *self.inner.lock();
|
||||||
let cur_ts = get_aligned_timestamp();
|
let cur_ts = get_aligned_timestamp();
|
||||||
Self::with_get_remote_private_route(inner, cur_ts, key, |r| {
|
inner.cache.peek_remote_private_route_mut(cur_ts, id).is_some()
|
||||||
r.private_route.as_ref().unwrap().clone()
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Retrieve an imported remote private route by its public key but don't 'touch' it
|
// /// Retrieve an imported remote private route by its public key
|
||||||
pub fn peek_remote_private_route(&self, id: &String) -> Option<PrivateRoute> {
|
// pub fn get_remote_private_route(&self, id: &String) -> Option<PrivateRoute> {
|
||||||
xx fix these
|
// let inner = &mut *self.inner.lock();
|
||||||
let inner = &mut *self.inner.lock();
|
// let cur_ts = get_aligned_timestamp();
|
||||||
let cur_ts = get_aligned_timestamp();
|
// Self::with_get_remote_private_route(inner, cur_ts, key, |r| {
|
||||||
Self::with_peek_remote_private_route(inner, cur_ts, key, |r| {
|
// r.private_route.as_ref().unwrap().clone()
|
||||||
r.private_route.as_ref().unwrap().clone()
|
// })
|
||||||
})
|
// }
|
||||||
}
|
|
||||||
|
// /// Retrieve an imported remote private route by its public key but don't 'touch' it
|
||||||
|
// fn peek_remote_private_route(&self, id: &String) -> Option<PrivateRoute> {
|
||||||
|
// let inner = &mut *self.inner.lock();
|
||||||
|
// let cur_ts = get_aligned_timestamp();
|
||||||
|
// inner.cache.with_peek_remote_private_route(cur_ts, id, f)
|
||||||
|
// Self::with_peek_remote_private_route(inner, cur_ts, key, |r| {
|
||||||
|
// r.private_route.as_ref().unwrap().clone()
|
||||||
|
// })
|
||||||
|
// }
|
||||||
|
|
||||||
/// Check to see if this remote (not ours) private route has seen our current node info yet
|
/// 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
|
/// This happens when you communicate with a private route without a safety route
|
||||||
pub fn has_remote_private_route_seen_our_node_info(&self, key: &PublicKey) -> bool {
|
pub fn has_remote_private_route_seen_our_node_info(&self, id: &RouteId) -> bool {
|
||||||
let our_node_info_ts = {
|
let our_node_info_ts = {
|
||||||
let rti = &*self.unlocked_inner.routing_table.inner.read();
|
let rti = &*self.unlocked_inner.routing_table.inner.read();
|
||||||
let Some(ts) = rti.get_own_node_info_ts(RoutingDomain::PublicInternet) else {
|
let Some(ts) = rti.get_own_node_info_ts(RoutingDomain::PublicInternet) else {
|
||||||
|
// Node info is invalid, skip this
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
ts
|
ts
|
||||||
};
|
};
|
||||||
|
|
||||||
let opt_rpr_node_info_ts = {
|
let inner = &mut *self.inner.lock();
|
||||||
let inner = &mut *self.inner.lock();
|
let cur_ts = get_aligned_timestamp();
|
||||||
let cur_ts = get_aligned_timestamp();
|
let Some(rpri) = inner.cache.peek_remote_private_route_mut(cur_ts, &id) else {
|
||||||
Self::with_peek_remote_private_route(inner, cur_ts, key, |rpr| {
|
|
||||||
rpr.last_seen_our_node_info_ts
|
|
||||||
})
|
|
||||||
};
|
|
||||||
|
|
||||||
let Some(rpr_node_info_ts) = opt_rpr_node_info_ts else {
|
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
rpri.has_seen_our_node_info_ts(our_node_info_ts)
|
||||||
our_node_info_ts == rpr_node_info_ts
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Mark a remote private route as having seen our current node info
|
/// Mark a remote private route as having seen our current node info
|
||||||
@ -1543,20 +1343,23 @@ impl RouteSpecStore {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let inner = &mut *self.inner.lock();
|
let inner = &mut *self.inner.lock();
|
||||||
|
|
||||||
// Check for local route. If this is not a remote private route
|
// Check for local route. If this is not a remote private route
|
||||||
// then we just skip the recording. We may be running a test and using
|
// then we just skip the recording. We may be running a test and using
|
||||||
// our own local route as the destination private route.
|
// our own local route as the destination private route.
|
||||||
if let Some(_) = Self::detail_mut(inner, key) {
|
if let Some(_) = inner.content.get_id_by_key(key) {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
if Self::with_get_remote_private_route(inner, cur_ts, key, |rpr| {
|
|
||||||
rpr.last_seen_our_node_info_ts = our_node_info_ts;
|
if let Some(rrid) = inner.cache.get_remote_private_route_id_by_key(key) {
|
||||||
})
|
if let Some(rpri) = inner.cache.peek_remote_private_route_mut(cur_ts, &rrid)
|
||||||
.is_none()
|
{
|
||||||
{
|
rpri.set_last_seen_our_node_info_ts(our_node_info_ts);
|
||||||
bail!("private route is missing from store: {}", key);
|
return Ok(());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
|
||||||
|
bail!("private route is missing from store: {}", key);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the route statistics for any route we know about, local or remote
|
/// Get the route statistics for any route we know about, local or remote
|
||||||
@ -1570,15 +1373,20 @@ impl RouteSpecStore {
|
|||||||
if self.unlocked_inner.routing_table.matches_own_node_id_key(key) {
|
if self.unlocked_inner.routing_table.matches_own_node_id_key(key) {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for local route
|
// Check for local route
|
||||||
if let Some(rsd) = Self::detail_mut(inner, key) {
|
if let Some(rsid) = inner.content.get_id_by_key(key) {
|
||||||
return Some(f(&mut rsd.stats));
|
if let Some(rsd) = inner.content.get_detail_mut(&rsid) {
|
||||||
|
return Some(f(rsd.get_stats_mut()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for remote route
|
// Check for remote route
|
||||||
if let Some(res) =
|
if let Some(rrid) = inner.cache.get_remote_private_route_id_by_key(key) {
|
||||||
Self::with_peek_remote_private_route(inner, cur_ts, key, |rpr| f(&mut rpr.stats))
|
if let Some(rpri) = inner.cache.peek_remote_private_route_mut(cur_ts, &rrid)
|
||||||
{
|
{
|
||||||
return Some(res);
|
return Some(f(rpri.get_stats_mut()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
None
|
None
|
||||||
@ -1613,13 +1421,10 @@ impl RouteSpecStore {
|
|||||||
let inner = &mut *self.inner.lock();
|
let inner = &mut *self.inner.lock();
|
||||||
|
|
||||||
// Roll transfers for locally allocated routes
|
// Roll transfers for locally allocated routes
|
||||||
for rssd in inner.content.details.values_mut() {
|
inner.content.roll_transfers(last_ts, cur_ts);
|
||||||
rssd.stats.roll_transfers(last_ts, cur_ts);
|
|
||||||
}
|
|
||||||
// Roll transfers for remote private routes
|
// Roll transfers for remote private routes
|
||||||
for (_k, v) in inner.cache.remote_private_route_cache.iter_mut() {
|
inner.cache.roll_transfers(last_ts, cur_ts);
|
||||||
v.stats.roll_transfers(last_ts, cur_ts);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Convert private route list to binary blob
|
/// Convert private route list to binary blob
|
||||||
@ -1681,6 +1486,54 @@ impl RouteSpecStore {
|
|||||||
out.push(private_route);
|
out.push(private_route);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Don't trust the order of the blob
|
||||||
|
out.sort_by(|a,b| {
|
||||||
|
a.public_key.cmp(&b.public_key)
|
||||||
|
});
|
||||||
|
|
||||||
Ok(out)
|
Ok(out)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Generate RouteId from typed key set of route public keys
|
||||||
|
fn generate_allocated_route_id(&self, rssd: &RouteSetSpecDetail) -> EyreResult<RouteId> {
|
||||||
|
let route_set_keys = rssd.get_route_set_keys();
|
||||||
|
let crypto = self.unlocked_inner.routing_table.crypto();
|
||||||
|
|
||||||
|
let mut idbytes = Vec::with_capacity(PUBLIC_KEY_LENGTH * route_set_keys.len());
|
||||||
|
let mut best_kind : Option<CryptoKind> = None;
|
||||||
|
for tk in route_set_keys.iter() {
|
||||||
|
if best_kind.is_none() || compare_crypto_kind(&tk.kind, best_kind.as_ref().unwrap()) == cmp::Ordering::Less {
|
||||||
|
best_kind = Some(tk.kind);
|
||||||
|
}
|
||||||
|
idbytes.extend_from_slice(&tk.key.bytes);
|
||||||
|
}
|
||||||
|
let Some(best_kind) = best_kind else {
|
||||||
|
bail!("no compatible crypto kinds in route");
|
||||||
|
};
|
||||||
|
let vcrypto = crypto.get(best_kind).unwrap();
|
||||||
|
|
||||||
|
Ok(RouteId::new(vcrypto.generate_hash(&idbytes).bytes))
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Generate RouteId from set of private routes
|
||||||
|
fn generate_remote_route_id(&self, private_routes: &[PrivateRoute]) -> EyreResult<RouteId> {
|
||||||
|
let crypto = self.unlocked_inner.routing_table.crypto();
|
||||||
|
|
||||||
|
let mut idbytes = Vec::with_capacity(PUBLIC_KEY_LENGTH * private_routes.len());
|
||||||
|
let mut best_kind : Option<CryptoKind> = None;
|
||||||
|
for private_route in private_routes {
|
||||||
|
if best_kind.is_none() || compare_crypto_kind(&private_route.public_key.kind, best_kind.as_ref().unwrap()) == cmp::Ordering::Less {
|
||||||
|
best_kind = Some(private_route.public_key.kind);
|
||||||
|
}
|
||||||
|
idbytes.extend_from_slice(&private_route.public_key.key.bytes);
|
||||||
|
}
|
||||||
|
let Some(best_kind) = best_kind else {
|
||||||
|
bail!("no compatible crypto kinds in route");
|
||||||
|
};
|
||||||
|
let vcrypto = crypto.get(best_kind).unwrap();
|
||||||
|
|
||||||
|
Ok(RouteId::new(vcrypto.generate_hash(&idbytes).bytes))
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -28,15 +28,15 @@ pub struct RouteSpecStoreCache {
|
|||||||
/// Route spec hop cache, used to quickly disqualify routes
|
/// Route spec hop cache, used to quickly disqualify routes
|
||||||
hop_cache: HashSet<Vec<u8>>,
|
hop_cache: HashSet<Vec<u8>>,
|
||||||
/// Remote private routes we've imported and statistics
|
/// Remote private routes we've imported and statistics
|
||||||
remote_private_route_set_cache: LruCache<RemotePrivateRouteId, RemotePrivateRouteInfo>,
|
remote_private_route_set_cache: LruCache<RouteId, RemotePrivateRouteInfo>,
|
||||||
/// Remote private routes indexed by public key
|
/// Remote private routes indexed by public key
|
||||||
remote_private_routes_by_key: HashMap<PublicKey, RemotePrivateRouteId>,
|
remote_private_routes_by_key: HashMap<PublicKey, RouteId>,
|
||||||
/// Compiled route cache
|
/// Compiled route cache
|
||||||
compiled_route_cache: LruCache<CompiledRouteCacheKey, SafetyRoute>,
|
compiled_route_cache: LruCache<CompiledRouteCacheKey, SafetyRoute>,
|
||||||
/// List of dead allocated routes
|
/// List of dead allocated routes
|
||||||
dead_routes: Vec<RouteSetSpecId>,
|
dead_routes: Vec<RouteId>,
|
||||||
/// List of dead remote routes
|
/// List of dead remote routes
|
||||||
dead_remote_routes: Vec<RemotePrivateRouteId>,
|
dead_remote_routes: Vec<RouteId>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RouteSpecStoreCache {
|
impl RouteSpecStoreCache {
|
||||||
@ -66,7 +66,7 @@ impl RouteSpecStoreCache {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// removes an allocated route set from our cache
|
/// removes an allocated route set from our cache
|
||||||
pub fn remove_from_cache(&mut self, rssd: &RouteSetSpecDetail) -> bool {
|
pub fn remove_from_cache(&mut self, id: RouteId, rssd: &RouteSetSpecDetail) -> bool {
|
||||||
let cache_key = rssd.make_cache_key();
|
let cache_key = rssd.make_cache_key();
|
||||||
|
|
||||||
// Remove from hop cache
|
// Remove from hop cache
|
||||||
@ -100,10 +100,13 @@ impl RouteSpecStoreCache {
|
|||||||
panic!("used_end_nodes cache should have contained hop");
|
panic!("used_end_nodes cache should have contained hop");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Invalidate compiled route cache
|
||||||
|
self.invalidate_compiled_route_cache(pk);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mark it as dead for the update
|
// Mark it as dead for the update
|
||||||
self.dead_routes.push(rssd.make_id());
|
self.dead_routes.push(id);
|
||||||
|
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
@ -122,43 +125,27 @@ impl RouteSpecStoreCache {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// generate unique remote private route set id for a remote private route set
|
|
||||||
fn make_remote_private_route_id(private_routes: &[PrivateRoute]) -> String {
|
|
||||||
let mut idbytes = [0u8; 16];
|
|
||||||
for (pk, _) in &rprinfo.private_routes {
|
|
||||||
for (i, x) in pk.bytes.iter().enumerate() {
|
|
||||||
idbytes[i % 16] ^= *x;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let id = format!(
|
|
||||||
"{:08x}-{:04x}-{:04x}-{:04x}-{:08x}{:04x}",
|
|
||||||
u32::from_be_bytes(idbytes[0..4].try_into().expect("32 bits")),
|
|
||||||
u16::from_be_bytes(idbytes[4..6].try_into().expect("16 bits")),
|
|
||||||
u16::from_be_bytes(idbytes[6..8].try_into().expect("16 bits")),
|
|
||||||
u16::from_be_bytes(idbytes[8..10].try_into().expect("16 bits")),
|
|
||||||
u32::from_be_bytes(idbytes[10..14].try_into().expect("32 bits")),
|
|
||||||
u16::from_be_bytes(idbytes[14..16].try_into().expect("16 bits"))
|
|
||||||
);
|
|
||||||
id
|
|
||||||
}
|
|
||||||
|
|
||||||
/// add remote private route to caches
|
/// add remote private route to caches
|
||||||
/// returns a remote private route set id
|
/// returns a remote private route set id
|
||||||
fn add_remote_private_route(
|
fn add_remote_private_route(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
id: RouteId,
|
||||||
rprinfo: RemotePrivateRouteInfo,
|
rprinfo: RemotePrivateRouteInfo,
|
||||||
) -> RemotePrivateRouteId {
|
) -> RouteId {
|
||||||
let id = Self::make_remote_private_route_id(rprinfo.get_private_routes());
|
|
||||||
|
|
||||||
// also store in id by key table
|
// also store in id by key table
|
||||||
for (pk, _) in rprinfo.get_private_routes() {
|
for private_route in rprinfo.get_private_routes() {
|
||||||
self.remote_private_routes_by_key.insert(*pk, id.clone());
|
self.remote_private_routes_by_key
|
||||||
|
.insert(private_route.public_key.key, id.clone());
|
||||||
}
|
}
|
||||||
self.remote_private_route_set_cache
|
self.remote_private_route_set_cache
|
||||||
.insert(id.clone(), rprinfo, |dead_id, dead_rpri| {
|
.insert(id, rprinfo, |dead_id, dead_rpri| {
|
||||||
// If anything LRUs out, remove from the by-key table
|
// If anything LRUs out, remove from the by-key table
|
||||||
for (dead_pk, _) in dead_rpri.get_private_routes() {
|
// Follow the same logic as 'remove_remote_private_route' here
|
||||||
self.remote_private_routes_by_key.remove(&dead_pk).unwrap();
|
for dead_private_route in dead_rpri.get_private_routes() {
|
||||||
|
self.remote_private_routes_by_key
|
||||||
|
.remove(&dead_private_route.public_key.key)
|
||||||
|
.unwrap();
|
||||||
|
self.invalidate_compiled_route_cache(&dead_private_route.public_key.key);
|
||||||
}
|
}
|
||||||
self.dead_remote_routes.push(dead_id);
|
self.dead_remote_routes.push(dead_id);
|
||||||
});
|
});
|
||||||
@ -166,33 +153,68 @@ impl RouteSpecStoreCache {
|
|||||||
id
|
id
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// get count of remote private routes in cache
|
||||||
|
pub fn get_remote_private_route_count(&self) -> usize {
|
||||||
|
self.remote_private_route_set_cache.len()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// iterate all of the remote private routes we have in the cache
|
||||||
|
pub fn iter_remote_private_routes(
|
||||||
|
&self,
|
||||||
|
) -> hashlink::linked_hash_map::Iter<RouteId, RemotePrivateRouteInfo> {
|
||||||
|
self.remote_private_route_set_cache.iter()
|
||||||
|
}
|
||||||
|
|
||||||
/// remote private route cache accessor
|
/// remote private route cache accessor
|
||||||
fn get_remote_private_route(
|
/// will LRU entries and may expire entries and not return them if they are stale
|
||||||
|
pub fn get_remote_private_route(
|
||||||
&mut self,
|
&mut self,
|
||||||
id: &RemotePrivateRouteId,
|
cur_ts: Timestamp,
|
||||||
|
id: &RouteId,
|
||||||
) -> Option<&RemotePrivateRouteInfo> {
|
) -> Option<&RemotePrivateRouteInfo> {
|
||||||
self.remote_private_route_set_cache.get(id)
|
if let Some(rpri) = self.remote_private_route_set_cache.get(id) {
|
||||||
|
if !rpri.did_expire(cur_ts) {
|
||||||
|
rpri.touch(cur_ts);
|
||||||
|
return Some(rpri);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
/// mutable remote private route cache accessor
|
/// mutable remote private route cache accessor
|
||||||
fn get_remote_private_route_mut(
|
/// will LRU entries and may expire entries and not return them if they are stale
|
||||||
|
pub fn get_remote_private_route_mut(
|
||||||
&mut self,
|
&mut self,
|
||||||
id: &RemotePrivateRouteId,
|
cur_ts: Timestamp,
|
||||||
|
id: &RouteId,
|
||||||
) -> Option<&mut RemotePrivateRouteInfo> {
|
) -> Option<&mut RemotePrivateRouteInfo> {
|
||||||
self.remote_private_route_set_cache.get_mut(id)
|
if let Some(rpri) = self.remote_private_route_set_cache.get_mut(id) {
|
||||||
|
if !rpri.did_expire(cur_ts) {
|
||||||
|
rpri.touch(cur_ts);
|
||||||
|
return Some(rpri);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
/// mutable remote private route cache accessor without lru action
|
/// mutable remote private route cache accessor without lru action
|
||||||
fn peek_remote_private_route_mut(
|
/// will not LRU entries but may expire entries and not return them if they are stale
|
||||||
|
pub fn peek_remote_private_route_mut(
|
||||||
&mut self,
|
&mut self,
|
||||||
id: &RemotePrivateRouteId,
|
cur_ts: Timestamp,
|
||||||
|
id: &RouteId,
|
||||||
) -> Option<&mut RemotePrivateRouteInfo> {
|
) -> Option<&mut RemotePrivateRouteInfo> {
|
||||||
self.remote_private_route_set_cache.peek_mut(id)
|
if let Some(rpri) = self.remote_private_route_set_cache.peek_mut(id) {
|
||||||
|
if !rpri.did_expire(cur_ts) {
|
||||||
|
rpri.touch(cur_ts);
|
||||||
|
return Some(rpri);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
/// look up a remote private route id by one of the route public keys
|
/// look up a remote private route id by one of the route public keys
|
||||||
pub fn get_remote_private_route_id_by_key(
|
pub fn get_remote_private_route_id_by_key(&self, key: &PublicKey) -> Option<RouteId> {
|
||||||
&self,
|
|
||||||
key: &PublicKey,
|
|
||||||
) -> Option<RemotePrivateRouteId> {
|
|
||||||
self.remote_private_routes_by_key.get(key).cloned()
|
self.remote_private_routes_by_key.get(key).cloned()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -200,14 +222,14 @@ impl RouteSpecStoreCache {
|
|||||||
/// may LRU and/or expire other cache entries to make room for the new one
|
/// may LRU and/or expire other cache entries to make room for the new one
|
||||||
/// or update an existing entry with the same private route set
|
/// or update an existing entry with the same private route set
|
||||||
/// returns the route set id
|
/// returns the route set id
|
||||||
pub fn import_remote_private_route(
|
pub fn cache_remote_private_route(
|
||||||
&mut self,
|
&mut self,
|
||||||
cur_ts: Timestamp,
|
cur_ts: Timestamp,
|
||||||
|
id: RouteId,
|
||||||
private_routes: Vec<PrivateRoute>,
|
private_routes: Vec<PrivateRoute>,
|
||||||
) -> RemotePrivateRouteId {
|
) {
|
||||||
// get id for this route set
|
// get id for this route set
|
||||||
let id = RouteSpecStoreCache::make_remote_private_route_id(&private_routes);
|
if let Some(rpri) = self.get_remote_private_route_mut(cur_ts, &id) {
|
||||||
let rpri = if let Some(rpri) = self.get_remote_private_route_mut(&id) {
|
|
||||||
if rpri.did_expire(cur_ts) {
|
if rpri.did_expire(cur_ts) {
|
||||||
// Start fresh if this had expired
|
// Start fresh if this had expired
|
||||||
rpri.unexpire(cur_ts);
|
rpri.unexpire(cur_ts);
|
||||||
@ -223,88 +245,95 @@ impl RouteSpecStoreCache {
|
|||||||
last_touched_ts: cur_ts,
|
last_touched_ts: cur_ts,
|
||||||
stats: RouteStats::new(cur_ts),
|
stats: RouteStats::new(cur_ts),
|
||||||
};
|
};
|
||||||
let new_id = self.add_remote_private_route(rpri);
|
self.add_remote_private_route(id, rpri);
|
||||||
assert_eq!(id, new_id);
|
if self.peek_remote_private_route_mut(cur_ts, &id).is_none() {
|
||||||
if self.get_remote_private_route_mut(&id).is_none() {
|
panic!("remote private route should exist");
|
||||||
bail!("remote private route should exist");
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
id
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// remove a remote private route from the cache
|
/// remove a remote private route from the cache
|
||||||
pub fn remove_remote_private_route(&mut self, id: &RemotePrivateRouteId) -> bool {
|
pub fn remove_remote_private_route(&mut self, id: RouteId) -> bool {
|
||||||
let Some(rprinfo) = self.remote_private_route_set_cache.remove(id) else {
|
let Some(rprinfo) = self.remote_private_route_set_cache.remove(&id) else {
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
for (pk, _) in rprinfo.get_private_routes() {
|
for private_route in rprinfo.get_private_routes() {
|
||||||
self.remote_private_routes_by_key.remove(&pk).unwrap();
|
self.remote_private_routes_by_key
|
||||||
|
.remove(&private_route.public_key.key)
|
||||||
|
.unwrap();
|
||||||
|
self.invalidate_compiled_route_cache(&private_route.public_key.key);
|
||||||
}
|
}
|
||||||
self.dead_remote_routes.push(id.clone());
|
self.dead_remote_routes.push(id);
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
/// get an existing remote private route cache entry
|
/// Stores a compiled 'safety + private' route so we don't have to compile it again later
|
||||||
/// will LRU entries and may expire entries and not return them if they are stale
|
pub fn add_to_compiled_route_cache(&self, pr_pubkey: PublicKey, safety_route: SafetyRoute) {
|
||||||
/// calls a callback with the remote private route info if returned
|
let key = CompiledRouteCacheKey {
|
||||||
pub fn with_get_remote_private_route<F, R>(
|
sr_pubkey: safety_route.public_key.key,
|
||||||
&mut self,
|
pr_pubkey,
|
||||||
cur_ts: Timestamp,
|
};
|
||||||
id: &RemotePrivateRouteId,
|
|
||||||
f: F,
|
if let Some(v) = self
|
||||||
) -> Option<R>
|
.compiled_route_cache
|
||||||
where
|
.insert(key, safety_route, |_k, _v| {
|
||||||
F: FnOnce(&mut RemotePrivateRouteInfo) -> R,
|
// Do nothing on LRU evict
|
||||||
{
|
})
|
||||||
if let Some(rpri) = self.get_remote_private_route_mut(&id) {
|
{
|
||||||
if !rpri.did_expire(cur_ts) {
|
log_rtab!(error "route cache already contained key: sr_pubkey={:?}, pr_pubkey={:?}", v.public_key, pr_pubkey);
|
||||||
rpri.touch(cur_ts);
|
|
||||||
return Some(f(rpri));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
self.remove_remote_private_route(&id);
|
|
||||||
None
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// peek a remote private route cache entry
|
/// Looks up an existing compiled route from the safety and private route components
|
||||||
// will not LRU entries but may expire entries and not return them if they are stale
|
pub fn lookup_compiled_route_cache(
|
||||||
/// calls a callback with the remote private route info if returned
|
&self,
|
||||||
pub fn with_peek_remote_private_route<F, R>(
|
sr_pubkey: PublicKey,
|
||||||
&mut self,
|
pr_pubkey: PublicKey,
|
||||||
cur_ts: Timestamp,
|
) -> Option<SafetyRoute> {
|
||||||
id: &RemotePrivateRouteId,
|
let key = CompiledRouteCacheKey {
|
||||||
f: F,
|
sr_pubkey,
|
||||||
) -> Option<R>
|
pr_pubkey,
|
||||||
where
|
};
|
||||||
F: FnOnce(&mut RemotePrivateRouteInfo) -> R,
|
self.compiled_route_cache.get(&key).cloned()
|
||||||
{
|
}
|
||||||
if let Some(rpri) = self.peek_remote_private_route_mut(&id) {
|
|
||||||
if !rpri.did_expire(cur_ts) {
|
/// When routes are dropped, they should be removed from the compiled route cache
|
||||||
rpri.touch(cur_ts);
|
fn invalidate_compiled_route_cache(&self, dead_key: &PublicKey) {
|
||||||
return Some(f(rpri));
|
let mut dead_entries = Vec::new();
|
||||||
|
for (k, _v) in self.compiled_route_cache.iter() {
|
||||||
|
if k.sr_pubkey == *dead_key || k.pr_pubkey == *dead_key {
|
||||||
|
dead_entries.push(k.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.remove_remote_private_route(&id);
|
for d in dead_entries {
|
||||||
None
|
self.compiled_route_cache.remove(&d);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Take the dead local and remote routes so we can update clients
|
/// Take the dead local and remote routes so we can update clients
|
||||||
pub fn take_dead_routes(&mut self) -> (Vec<RouteSetSpecId>, Vec<RemotePrivateRouteId>) {
|
pub fn take_dead_routes(&mut self) -> Option<(Vec<RouteId>, Vec<RouteId>)> {
|
||||||
if self.dead_routes.is_empty() && self.dead_remote_routes.is_empty() {
|
if self.dead_routes.is_empty() && self.dead_remote_routes.is_empty() {
|
||||||
// Nothing to do
|
// Nothing to do
|
||||||
return;
|
return None;
|
||||||
}
|
}
|
||||||
let dead_routes = core::mem::take(&mut self.dead_routes);
|
let dead_routes = core::mem::take(&mut self.dead_routes);
|
||||||
let dead_remote_routes = core::mem::take(&mut self.dead_remote_routes);
|
let dead_remote_routes = core::mem::take(&mut self.dead_remote_routes);
|
||||||
(dead_routes, dead_remote_routes)
|
Some((dead_routes, dead_remote_routes))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Clean up imported remote routes
|
/// Clean up imported remote routes
|
||||||
/// Resets statistics for when our node info changes
|
/// Resets statistics for when our node info changes
|
||||||
pub fn reset_details(&mut self) {
|
pub fn reset_remote_private_routes(&mut self) {
|
||||||
for (_k, v) in self.remote_private_route_cache {
|
// Restart stats for routes so we test the route again
|
||||||
// Restart stats for routes so we test the route again
|
for (_k, v) in self.remote_private_route_set_cache {
|
||||||
v.stats.reset();
|
v.get_stats_mut().reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Roll transfer statistics
|
||||||
|
pub fn roll_transfers(&mut self, last_ts: Timestamp, cur_ts: Timestamp) {
|
||||||
|
for (_k, v) in self.remote_private_route_set_cache {
|
||||||
|
v.get_stats_mut().roll_transfers(last_ts, cur_ts);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,15 +5,116 @@ use super::*;
|
|||||||
#[archive_attr(repr(C, align(8)), derive(CheckBytes))]
|
#[archive_attr(repr(C, align(8)), derive(CheckBytes))]
|
||||||
pub struct RouteSpecStoreContent {
|
pub struct RouteSpecStoreContent {
|
||||||
/// All of the route sets we have allocated so far indexed by key
|
/// All of the route sets we have allocated so far indexed by key
|
||||||
id_by_key: HashMap<PublicKey, RouteSetSpecId>,
|
id_by_key: HashMap<PublicKey, RouteId>,
|
||||||
/// All of the route sets we have allocated so far
|
/// All of the route sets we have allocated so far
|
||||||
details: HashMap<RouteSetSpecId, RouteSetSpecDetail>,
|
details: HashMap<RouteId, RouteSetSpecDetail>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RouteSpecStoreContent {
|
impl RouteSpecStoreContent {
|
||||||
pub fn add_detail(&mut self, detail: RouteSetSpecDetail) -> RouteSetSpecId {
|
pub async fn load(routing_table: RoutingTable) -> EyreResult<RouteSpecStoreContent> {
|
||||||
// generate unique key string
|
// Deserialize what we can
|
||||||
let id = detail.make_id();
|
let table_store = routing_table.network_manager().table_store();
|
||||||
|
let rsstdb = table_store.open("RouteSpecStore", 1).await?;
|
||||||
|
let mut content: RouteSpecStoreContent =
|
||||||
|
rsstdb.load_rkyv(0, b"content")?.unwrap_or_default();
|
||||||
|
|
||||||
|
// Look up all route hop noderefs since we can't serialize those
|
||||||
|
let mut dead_ids = Vec::new();
|
||||||
|
for (rsid, rssd) in content.details.iter_mut() {
|
||||||
|
// Get best route since they all should resolve
|
||||||
|
let Some(pk) = rssd.get_best_route_set_key() else {
|
||||||
|
dead_ids.push(rsid.clone());
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
let Some(rsd) = rssd.get_route_by_key(&pk) else {
|
||||||
|
dead_ids.push(rsid.clone());
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
// Go through best route and resolve noderefs
|
||||||
|
let mut hop_node_refs = Vec::with_capacity(rsd.hops.len());
|
||||||
|
for h in &rsd.hops {
|
||||||
|
let Some(nr) = routing_table.lookup_node_ref(TypedKey::new(rsd.crypto_kind, *h)) else {
|
||||||
|
dead_ids.push(rsid.clone());
|
||||||
|
break;
|
||||||
|
};
|
||||||
|
hop_node_refs.push(nr);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply noderefs
|
||||||
|
rssd.set_hop_node_refs(hop_node_refs);
|
||||||
|
}
|
||||||
|
for id in dead_ids {
|
||||||
|
log_rtab!(debug "no entry, killing off private route: {}", id);
|
||||||
|
content.remove_detail(&id);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load secrets from pstore
|
||||||
|
let pstore = routing_table.network_manager().protected_store();
|
||||||
|
let secret_key_map: HashMap<PublicKey, SecretKey> = pstore
|
||||||
|
.load_user_secret_rkyv("RouteSpecStore")
|
||||||
|
.await?
|
||||||
|
.unwrap_or_default();
|
||||||
|
|
||||||
|
// Ensure we got secret keys for all the public keys
|
||||||
|
let mut got_secret_key_ids = HashSet::new();
|
||||||
|
for (rsid, rssd) in content.details.iter_mut() {
|
||||||
|
let mut found_all = true;
|
||||||
|
for (pk, rsd) in rssd.iter_route_set_mut() {
|
||||||
|
if let Some(sk) = secret_key_map.get(pk) {
|
||||||
|
rsd.secret_key = *sk;
|
||||||
|
} else {
|
||||||
|
found_all = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if found_all {
|
||||||
|
got_secret_key_ids.insert(rsid.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we missed any, nuke those route ids
|
||||||
|
let dead_ids: Vec<RouteId> = content
|
||||||
|
.details
|
||||||
|
.keys()
|
||||||
|
.filter_map(|id| {
|
||||||
|
if !got_secret_key_ids.contains(id) {
|
||||||
|
Some(*id)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
for id in dead_ids {
|
||||||
|
log_rtab!(debug "missing secret key, killing off private route: {}", id);
|
||||||
|
content.remove_detail(&id);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(content)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn save(&self, routing_table: RoutingTable) -> EyreResult<()> {
|
||||||
|
// Save all the fields we care about to the frozen blob in table storage
|
||||||
|
// This skips #[with(Skip)] saving the secret keys, we save them in the protected store instead
|
||||||
|
let table_store = routing_table.network_manager().table_store();
|
||||||
|
let rsstdb = table_store.open("RouteSpecStore", 1).await?;
|
||||||
|
rsstdb.store_rkyv(0, b"content", self).await?;
|
||||||
|
|
||||||
|
// // Keep secrets in protected store as well
|
||||||
|
let pstore = routing_table.network_manager().protected_store();
|
||||||
|
|
||||||
|
let mut out: HashMap<PublicKey, SecretKey> = HashMap::new();
|
||||||
|
for (rsid, rssd) in self.details.iter() {
|
||||||
|
for (pk, rsd) in rssd.iter_route_set() {
|
||||||
|
out.insert(*pk, rsd.secret_key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let _ = pstore.save_user_secret_rkyv("RouteSpecStore", &out).await?; // ignore if this previously existed or not
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_detail(&mut self, id: RouteId, detail: RouteSetSpecDetail) {
|
||||||
assert!(!self.details.contains_key(&id));
|
assert!(!self.details.contains_key(&id));
|
||||||
|
|
||||||
// also store in id by key table
|
// also store in id by key table
|
||||||
@ -21,38 +122,32 @@ impl RouteSpecStoreContent {
|
|||||||
self.id_by_key.insert(*pk, id.clone());
|
self.id_by_key.insert(*pk, id.clone());
|
||||||
}
|
}
|
||||||
self.details.insert(id.clone(), detail);
|
self.details.insert(id.clone(), detail);
|
||||||
|
|
||||||
id
|
|
||||||
}
|
}
|
||||||
pub fn remove_detail(&mut self, id: &RouteSetSpecId) -> Option<RouteSetSpecDetail> {
|
pub fn remove_detail(&mut self, id: &RouteId) -> Option<RouteSetSpecDetail> {
|
||||||
let detail = self.details.remove(id)?;
|
let detail = self.details.remove(id)?;
|
||||||
for (pk, _) in detail.iter_route_set() {
|
for (pk, _) in detail.iter_route_set() {
|
||||||
self.id_by_key.remove(&pk).unwrap();
|
self.id_by_key.remove(&pk).unwrap();
|
||||||
}
|
}
|
||||||
Some(detail)
|
Some(detail)
|
||||||
}
|
}
|
||||||
pub fn get_detail(&self, id: &RouteSetSpecId) -> Option<&RouteSetSpecDetail> {
|
pub fn get_detail_count(&self) -> usize {
|
||||||
|
self.details.len()
|
||||||
|
}
|
||||||
|
pub fn get_detail(&self, id: &RouteId) -> Option<&RouteSetSpecDetail> {
|
||||||
self.details.get(id)
|
self.details.get(id)
|
||||||
}
|
}
|
||||||
pub fn get_detail_mut(&mut self, id: &RouteSetSpecId) -> Option<&mut RouteSetSpecDetail> {
|
pub fn get_detail_mut(&mut self, id: &RouteId) -> Option<&mut RouteSetSpecDetail> {
|
||||||
self.details.get_mut(id)
|
self.details.get_mut(id)
|
||||||
}
|
}
|
||||||
pub fn get_id_by_key(&self, key: &PublicKey) -> Option<RouteSetSpecId> {
|
pub fn get_id_by_key(&self, key: &PublicKey) -> Option<RouteId> {
|
||||||
self.id_by_key.get(key).cloned()
|
self.id_by_key.get(key).cloned()
|
||||||
}
|
}
|
||||||
pub fn iter_ids(&self) -> std::collections::hash_map::Keys<RouteSetSpecId, RouteSetSpecDetail> {
|
pub fn iter_ids(&self) -> std::collections::hash_map::Keys<RouteId, RouteSetSpecDetail> {
|
||||||
self.details.keys()
|
self.details.keys()
|
||||||
}
|
}
|
||||||
pub fn iter_details(
|
pub fn iter_details(&self) -> std::collections::hash_map::Iter<RouteId, RouteSetSpecDetail> {
|
||||||
&self,
|
|
||||||
) -> std::collections::hash_map::Iter<RouteSetSpecId, RouteSetSpecDetail> {
|
|
||||||
self.details.iter()
|
self.details.iter()
|
||||||
}
|
}
|
||||||
pub fn iter_details_mut(
|
|
||||||
&mut self,
|
|
||||||
) -> std::collections::hash_map::IterMut<RouteSetSpecId, RouteSetSpecDetail> {
|
|
||||||
self.details.iter_mut()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Clean up local allocated routes
|
/// Clean up local allocated routes
|
||||||
/// Resets publication status and statistics for when our node info changes
|
/// Resets publication status and statistics for when our node info changes
|
||||||
@ -65,4 +160,11 @@ impl RouteSpecStoreContent {
|
|||||||
v.get_stats_mut().reset();
|
v.get_stats_mut().reset();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Roll transfer statistics
|
||||||
|
pub fn roll_transfers(&mut self, last_ts: Timestamp, cur_ts: Timestamp) {
|
||||||
|
for rssd in self.details.values_mut() {
|
||||||
|
rssd.get_stats_mut().roll_transfers(last_ts, cur_ts);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@ const BACKGROUND_SAFETY_ROUTE_COUNT: usize = 2;
|
|||||||
|
|
||||||
impl RoutingTable {
|
impl RoutingTable {
|
||||||
/// Fastest routes sort
|
/// Fastest routes sort
|
||||||
fn route_sort_latency_fn(a: &(TypedKey, u64), b: &(TypedKey, u64)) -> cmp::Ordering {
|
fn route_sort_latency_fn(a: &(RouteId, u64), b: &(RouteId, u64)) -> cmp::Ordering {
|
||||||
let mut al = a.1;
|
let mut al = a.1;
|
||||||
let mut bl = b.1;
|
let mut bl = b.1;
|
||||||
// Treat zero latency as uncalculated
|
// Treat zero latency as uncalculated
|
||||||
@ -35,14 +35,14 @@ impl RoutingTable {
|
|||||||
///
|
///
|
||||||
/// If a route doesn't 'need_testing', then we neither test nor drop it
|
/// If a route doesn't 'need_testing', then we neither test nor drop it
|
||||||
#[instrument(level = "trace", skip(self))]
|
#[instrument(level = "trace", skip(self))]
|
||||||
fn get_allocated_routes_to_test(&self, cur_ts: Timestamp) -> Vec<TypedKey> {
|
fn get_allocated_routes_to_test(&self, cur_ts: Timestamp) -> Vec<RouteId> {
|
||||||
let default_route_hop_count =
|
let default_route_hop_count =
|
||||||
self.with_config(|c| c.network.rpc.default_route_hop_count as usize);
|
self.with_config(|c| c.network.rpc.default_route_hop_count as usize);
|
||||||
|
|
||||||
let rss = self.route_spec_store();
|
let rss = self.route_spec_store();
|
||||||
let mut must_test_routes = Vec::<TypedKey>::new();
|
let mut must_test_routes = Vec::<RouteId>::new();
|
||||||
let mut unpublished_routes = Vec::<(TypedKey, u64)>::new();
|
let mut unpublished_routes = Vec::<(RouteId, u64)>::new();
|
||||||
let mut expired_routes = Vec::<TypedKey>::new();
|
let mut expired_routes = Vec::<RouteId>::new();
|
||||||
rss.list_allocated_routes(|k, v| {
|
rss.list_allocated_routes(|k, v| {
|
||||||
let stats = v.get_stats();
|
let stats = v.get_stats();
|
||||||
// Ignore nodes that don't need testing
|
// Ignore nodes that don't need testing
|
||||||
@ -81,7 +81,7 @@ impl RoutingTable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Process dead routes
|
// Process dead routes
|
||||||
for r in &expired_routes {
|
for r in expired_routes {
|
||||||
log_rtab!(debug "Expired route: {}", r);
|
log_rtab!(debug "Expired route: {}", r);
|
||||||
rss.release_route(r);
|
rss.release_route(r);
|
||||||
}
|
}
|
||||||
@ -95,7 +95,7 @@ impl RoutingTable {
|
|||||||
async fn test_route_set(
|
async fn test_route_set(
|
||||||
&self,
|
&self,
|
||||||
stop_token: StopToken,
|
stop_token: StopToken,
|
||||||
routes_needing_testing: Vec<TypedKey>,
|
routes_needing_testing: Vec<RouteId>,
|
||||||
) -> EyreResult<()> {
|
) -> EyreResult<()> {
|
||||||
if routes_needing_testing.is_empty() {
|
if routes_needing_testing.is_empty() {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
@ -107,43 +107,45 @@ impl RoutingTable {
|
|||||||
#[derive(Default, Debug)]
|
#[derive(Default, Debug)]
|
||||||
struct TestRouteContext {
|
struct TestRouteContext {
|
||||||
failed: bool,
|
failed: bool,
|
||||||
dead_routes: Vec<TypedKey>,
|
dead_routes: Vec<RouteId>,
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut unord = FuturesUnordered::new();
|
|
||||||
let ctx = Arc::new(Mutex::new(TestRouteContext::default()));
|
let ctx = Arc::new(Mutex::new(TestRouteContext::default()));
|
||||||
for r in routes_needing_testing {
|
{
|
||||||
let rss = rss.clone();
|
let mut unord = FuturesUnordered::new();
|
||||||
let ctx = ctx.clone();
|
for r in routes_needing_testing {
|
||||||
unord.push(
|
let rss = rss.clone();
|
||||||
async move {
|
let ctx = ctx.clone();
|
||||||
let success = match rss.test_route(&r).await {
|
unord.push(
|
||||||
Ok(v) => v,
|
async move {
|
||||||
Err(e) => {
|
let success = match rss.test_route(r).await {
|
||||||
log_rtab!(error "Test route failed: {}", e);
|
Ok(v) => v,
|
||||||
ctx.lock().failed = true;
|
Err(e) => {
|
||||||
|
log_rtab!(error "Test route failed: {}", e);
|
||||||
|
ctx.lock().failed = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if success {
|
||||||
|
// Route is okay, leave it alone
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
};
|
// Route test failed
|
||||||
if success {
|
ctx.lock().dead_routes.push(r);
|
||||||
// Route is okay, leave it alone
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
// Route test failed
|
.instrument(Span::current())
|
||||||
ctx.lock().dead_routes.push(r);
|
.boxed(),
|
||||||
}
|
);
|
||||||
.instrument(Span::current())
|
}
|
||||||
.boxed(),
|
|
||||||
);
|
// Wait for test_route futures to complete in parallel
|
||||||
|
while let Ok(Some(_)) = unord.next().timeout_at(stop_token.clone()).await {}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wait for test_route futures to complete in parallel
|
|
||||||
while let Ok(Some(_)) = unord.next().timeout_at(stop_token.clone()).await {}
|
|
||||||
|
|
||||||
// Process failed routes
|
// Process failed routes
|
||||||
let ctx = &mut *ctx.lock();
|
let ctx = Arc::try_unwrap(ctx).unwrap().into_inner();
|
||||||
for r in &ctx.dead_routes {
|
for r in ctx.dead_routes {
|
||||||
log_rtab!(debug "Dead route failed to test: {}", &r);
|
log_rtab!(debug "Dead route failed to test: {}", r);
|
||||||
rss.release_route(r);
|
rss.release_route(r);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -176,13 +178,16 @@ impl RoutingTable {
|
|||||||
.await?;
|
.await?;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure we have a minimum of N allocated local, unpublished routes with the default number of hops
|
// Ensure we have a minimum of N allocated local, unpublished routes with the default number of hops and all our supported crypto kinds
|
||||||
let default_route_hop_count =
|
let default_route_hop_count =
|
||||||
self.with_config(|c| c.network.rpc.default_route_hop_count as usize);
|
self.with_config(|c| c.network.rpc.default_route_hop_count as usize);
|
||||||
let mut local_unpublished_route_count = 0usize;
|
let mut local_unpublished_route_count = 0usize;
|
||||||
let rss = self.route_spec_store();
|
let rss = self.route_spec_store();
|
||||||
rss.list_allocated_routes(|_k, v| {
|
rss.list_allocated_routes(|_k, v| {
|
||||||
if !v.is_published() && v.hop_count() == default_route_hop_count {
|
if !v.is_published()
|
||||||
|
&& v.hop_count() == default_route_hop_count
|
||||||
|
&& v.get_route_set_keys().kinds() == VALID_CRYPTO_KINDS
|
||||||
|
{
|
||||||
local_unpublished_route_count += 1;
|
local_unpublished_route_count += 1;
|
||||||
}
|
}
|
||||||
Option::<()>::None
|
Option::<()>::None
|
||||||
@ -196,6 +201,7 @@ impl RoutingTable {
|
|||||||
// Parameters here must be the default safety route spec
|
// Parameters here must be the default safety route spec
|
||||||
// These will be used by test_remote_route as well
|
// These will be used by test_remote_route as well
|
||||||
if let Some(k) = rss.allocate_route(
|
if let Some(k) = rss.allocate_route(
|
||||||
|
&VALID_CRYPTO_KINDS,
|
||||||
Stability::default(),
|
Stability::default(),
|
||||||
Sequencing::default(),
|
Sequencing::default(),
|
||||||
default_route_hop_count,
|
default_route_hop_count,
|
||||||
|
@ -22,7 +22,7 @@ pub enum Destination {
|
|||||||
/// Send to private route (privateroute)
|
/// Send to private route (privateroute)
|
||||||
PrivateRoute {
|
PrivateRoute {
|
||||||
/// A private route set id to send to
|
/// A private route set id to send to
|
||||||
private_route: String,
|
private_route_id: RouteId,
|
||||||
/// Require safety route or not
|
/// Require safety route or not
|
||||||
safety_selection: SafetySelection,
|
safety_selection: SafetySelection,
|
||||||
},
|
},
|
||||||
@ -44,9 +44,9 @@ impl Destination {
|
|||||||
safety_selection: SafetySelection::Unsafe(sequencing),
|
safety_selection: SafetySelection::Unsafe(sequencing),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn private_route(private_route: PrivateRoute, safety_selection: SafetySelection) -> Self {
|
pub fn private_route(private_route_id: RouteId, safety_selection: SafetySelection) -> Self {
|
||||||
Self::PrivateRoute {
|
Self::PrivateRoute {
|
||||||
private_route,
|
private_route_id,
|
||||||
safety_selection,
|
safety_selection,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -70,10 +70,10 @@ impl Destination {
|
|||||||
safety_selection,
|
safety_selection,
|
||||||
},
|
},
|
||||||
Destination::PrivateRoute {
|
Destination::PrivateRoute {
|
||||||
private_route,
|
private_route_id,
|
||||||
safety_selection: _,
|
safety_selection: _,
|
||||||
} => Self::PrivateRoute {
|
} => Self::PrivateRoute {
|
||||||
private_route,
|
private_route_id,
|
||||||
safety_selection,
|
safety_selection,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@ -91,7 +91,7 @@ impl Destination {
|
|||||||
safety_selection,
|
safety_selection,
|
||||||
} => safety_selection,
|
} => safety_selection,
|
||||||
Destination::PrivateRoute {
|
Destination::PrivateRoute {
|
||||||
private_route: _,
|
private_route_id: _,
|
||||||
safety_selection,
|
safety_selection,
|
||||||
} => safety_selection,
|
} => safety_selection,
|
||||||
}
|
}
|
||||||
@ -127,7 +127,7 @@ impl fmt::Display for Destination {
|
|||||||
write!(f, "{}@{}{}", target, relay, sr)
|
write!(f, "{}@{}{}", target, relay, sr)
|
||||||
}
|
}
|
||||||
Destination::PrivateRoute {
|
Destination::PrivateRoute {
|
||||||
private_route,
|
private_route_id,
|
||||||
safety_selection,
|
safety_selection,
|
||||||
} => {
|
} => {
|
||||||
let sr = if matches!(safety_selection, SafetySelection::Safe(_)) {
|
let sr = if matches!(safety_selection, SafetySelection::Safe(_)) {
|
||||||
@ -136,7 +136,7 @@ impl fmt::Display for Destination {
|
|||||||
""
|
""
|
||||||
};
|
};
|
||||||
|
|
||||||
write!(f, "{}{}", private_route, sr)
|
write!(f, "{}{}", private_route_id, sr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -207,7 +207,7 @@ impl RPCProcessor {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
Destination::PrivateRoute {
|
Destination::PrivateRoute {
|
||||||
private_route,
|
private_route_id,
|
||||||
safety_selection,
|
safety_selection,
|
||||||
} => {
|
} => {
|
||||||
let Some(avoid_node_id) = private_route.first_hop_node_id() else {
|
let Some(avoid_node_id) = private_route.first_hop_node_id() else {
|
||||||
|
@ -674,7 +674,7 @@ impl RPCProcessor {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
Destination::PrivateRoute {
|
Destination::PrivateRoute {
|
||||||
private_route,
|
private_route_id,
|
||||||
safety_selection,
|
safety_selection,
|
||||||
} => {
|
} => {
|
||||||
// Send to private route
|
// Send to private route
|
||||||
@ -726,7 +726,7 @@ impl RPCProcessor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Destination::PrivateRoute {
|
Destination::PrivateRoute {
|
||||||
private_route: _,
|
private_route_id: _,
|
||||||
safety_selection: _,
|
safety_selection: _,
|
||||||
} => {
|
} => {
|
||||||
return Ok(SenderPeerInfo::default());
|
return Ok(SenderPeerInfo::default());
|
||||||
|
@ -17,7 +17,7 @@ impl RPCProcessor {
|
|||||||
if matches!(
|
if matches!(
|
||||||
dest,
|
dest,
|
||||||
Destination::PrivateRoute {
|
Destination::PrivateRoute {
|
||||||
private_route: _,
|
private_route_id: _,
|
||||||
safety_selection: _
|
safety_selection: _
|
||||||
}
|
}
|
||||||
) {
|
) {
|
||||||
|
@ -13,7 +13,7 @@ impl RPCProcessor {
|
|||||||
if matches!(
|
if matches!(
|
||||||
dest,
|
dest,
|
||||||
Destination::PrivateRoute {
|
Destination::PrivateRoute {
|
||||||
private_route: _,
|
private_route_id: _,
|
||||||
safety_selection: _
|
safety_selection: _
|
||||||
}
|
}
|
||||||
) {
|
) {
|
||||||
|
@ -53,7 +53,7 @@ impl RPCProcessor {
|
|||||||
(Some(target.clone()), routing_domain)
|
(Some(target.clone()), routing_domain)
|
||||||
}
|
}
|
||||||
Destination::PrivateRoute {
|
Destination::PrivateRoute {
|
||||||
private_route: _,
|
private_route_id: _,
|
||||||
safety_selection: _,
|
safety_selection: _,
|
||||||
} => (None, RoutingDomain::PublicInternet),
|
} => (None, RoutingDomain::PublicInternet),
|
||||||
};
|
};
|
||||||
@ -169,7 +169,7 @@ impl RPCProcessor {
|
|||||||
safety_selection: _,
|
safety_selection: _,
|
||||||
}
|
}
|
||||||
| Destination::PrivateRoute {
|
| Destination::PrivateRoute {
|
||||||
private_route: _,
|
private_route_id: _,
|
||||||
safety_selection: _,
|
safety_selection: _,
|
||||||
} => {
|
} => {
|
||||||
// sender info is irrelevant over relays and routes
|
// sender info is irrelevant over relays and routes
|
||||||
|
@ -4,8 +4,8 @@ use super::*;
|
|||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub enum Target {
|
pub enum Target {
|
||||||
NodeId(PublicKey), // Node by any of its public keys
|
NodeId(PublicKey), // Node by any of its public keys
|
||||||
PrivateRoute(String), // Private route by its route set id
|
PrivateRoute(RouteId), // Remote private route by its id
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct RoutingContextInner {}
|
pub struct RoutingContextInner {}
|
||||||
@ -121,14 +121,13 @@ impl RoutingContext {
|
|||||||
Target::PrivateRoute(rsid) => {
|
Target::PrivateRoute(rsid) => {
|
||||||
// Get remote private route
|
// Get remote private route
|
||||||
let rss = self.api.routing_table()?.route_spec_store();
|
let rss = self.api.routing_table()?.route_spec_store();
|
||||||
let Some(private_route) = rss
|
if !rss.is_valid_remote_private_route(&rsid)
|
||||||
.get_remote_private_route(&rsid)
|
|
||||||
else {
|
else {
|
||||||
apibail_key_not_found!(pr);
|
apibail_key_not_found!(pr);
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(rpc_processor::Destination::PrivateRoute {
|
Ok(rpc_processor::Destination::PrivateRoute {
|
||||||
private_route: rsid,
|
private_route_id: rsid,
|
||||||
safety_selection: self.unlocked_inner.safety_selection,
|
safety_selection: self.unlocked_inner.safety_selection,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -279,8 +279,8 @@ pub struct VeilidStateNetwork {
|
|||||||
)]
|
)]
|
||||||
#[archive_attr(repr(C), derive(CheckBytes))]
|
#[archive_attr(repr(C), derive(CheckBytes))]
|
||||||
pub struct VeilidStateRoute {
|
pub struct VeilidStateRoute {
|
||||||
pub dead_routes: Vec<PublicKey>,
|
pub dead_routes: Vec<RouteId>,
|
||||||
pub dead_remote_routes: Vec<PublicKey>,
|
pub dead_remote_routes: Vec<RouteId>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(
|
#[derive(
|
||||||
@ -513,7 +513,7 @@ impl SafetySelection {
|
|||||||
#[archive_attr(repr(C), derive(CheckBytes))]
|
#[archive_attr(repr(C), derive(CheckBytes))]
|
||||||
pub struct SafetySpec {
|
pub struct SafetySpec {
|
||||||
/// preferred safety route set id if it still exists
|
/// preferred safety route set id if it still exists
|
||||||
pub preferred_route: Option<String>,
|
pub preferred_route: Option<RouteId>,
|
||||||
/// must be greater than 0
|
/// must be greater than 0
|
||||||
pub hop_count: usize,
|
pub hop_count: usize,
|
||||||
/// prefer reliability over speed
|
/// prefer reliability over speed
|
||||||
|
Loading…
Reference in New Issue
Block a user