checkpoint

This commit is contained in:
John Smith
2023-02-20 20:37:52 -05:00
parent 05be3099c8
commit ae991334d3
25 changed files with 357 additions and 163 deletions

View File

@@ -891,11 +891,20 @@ impl RoutingTable {
}
#[instrument(level = "trace", skip(self), ret)]
pub fn register_find_node_answer(&self, peers: Vec<PeerInfo>) -> Vec<NodeRef> {
// register nodes we'd found
pub fn register_find_node_answer(
&self,
crypto_kind: CryptoKind,
peers: Vec<PeerInfo>,
) -> Vec<NodeRef> {
// Register nodes we'd found
let mut out = Vec::<NodeRef>::with_capacity(peers.len());
for p in peers {
// register the node if it's new
// Ensure we're getting back nodes we asked for
if !p.node_ids.kinds().contains(&crypto_kind) {
continue;
}
// Register the node if it's new
if let Some(nr) =
self.register_node_with_peer_info(RoutingDomain::PublicInternet, p, false)
{
@@ -922,29 +931,41 @@ impl RoutingTable {
// register nodes we'd found
Ok(NetworkResult::value(
self.register_find_node_answer(res.answer),
self.register_find_node_answer(node_id.kind, res.answer),
))
}
/// Ask a remote node to list the nodes it has around the current node
#[instrument(level = "trace", skip(self), ret, err)]
pub async fn find_self(&self, node_ref: NodeRef) -> EyreResult<NetworkResult<Vec<NodeRef>>> {
let self_node_id = self.node_id();
pub async fn find_self(
&self,
crypto_kind: CryptoKind,
node_ref: NodeRef,
) -> EyreResult<NetworkResult<Vec<NodeRef>>> {
let self_node_id = self.node_id(crypto_kind);
self.find_node(node_ref, self_node_id).await
}
/// Ask a remote node to list the nodes it has around itself
#[instrument(level = "trace", skip(self), ret, err)]
pub async fn find_target(&self, node_ref: NodeRef) -> EyreResult<NetworkResult<Vec<NodeRef>>> {
let target_node_id = node_ref.node_id();
pub async fn find_target(
&self,
crypto_kind: CryptoKind,
node_ref: NodeRef,
) -> EyreResult<NetworkResult<Vec<NodeRef>>> {
let Some(target_node_id) = node_ref.node_ids().get(crypto_kind) else {
bail!("no target node ids for this crypto kind");
};
self.find_node(node_ref, target_node_id).await
}
#[instrument(level = "trace", skip(self))]
pub async fn reverse_find_node(&self, node_ref: NodeRef, wide: bool) {
// Ask bootstrap node to 'find' our own node so we can get some more nodes near ourselves
pub async fn reverse_find_node(&self, crypto_kind: CryptoKind, node_ref: NodeRef, wide: bool) {
// Ask node to 'find node' on own node so we can get some more nodes near ourselves
// and then contact those nodes to inform -them- that we exist
// Ask bootstrap server for nodes closest to our own node
let closest_nodes = network_result_value_or_log!(match self.find_self(node_ref.clone()).await {
// Ask node for nodes closest to our own node
let closest_nodes = network_result_value_or_log!(match self.find_self(crypto_kind, node_ref.clone()).await {
Err(e) => {
log_rtab!(error
"find_self failed for {:?}: {:?}",
@@ -960,7 +981,7 @@ impl RoutingTable {
// Ask each node near us to find us as well
if wide {
for closest_nr in closest_nodes {
network_result_value_or_log!(match self.find_self(closest_nr.clone()).await {
network_result_value_or_log!(match self.find_self(crypto_kind, closest_nr.clone()).await {
Err(e) => {
log_rtab!(error
"find_self failed for {:?}: {:?}",

View File

@@ -168,7 +168,7 @@ pub struct RouteSpecDetail {
/// Secret key
#[with(Skip)]
secret_key: SecretKey,
/// Route hops
/// Route hops (node id keys)
hops: Vec<PublicKey>,
/// Route noderefs
#[with(Skip)]
@@ -444,7 +444,7 @@ impl RouteSpecStore {
let mut dead_keys = Vec::new();
for (k, rsd) in &mut content.details {
for h in &rsd.hops {
let Some(nr) = routing_table.lookup_node_ref(*h) else {
let Some(nr) = routing_table.lookup_node_ref(TypedKey::new(rsd.crypto_kind, *h)) else {
dead_keys.push(*k);
break;
};
@@ -582,13 +582,13 @@ impl RouteSpecStore {
fn detail<'a>(
inner: &'a RouteSpecStoreInner,
route_spec_key: &TypedKey,
route_spec_key: &PublicKey,
) -> Option<&'a RouteSpecDetail> {
inner.content.details.get(route_spec_key)
}
fn detail_mut<'a>(
inner: &'a mut RouteSpecStoreInner,
route_spec_key: &TypedKey,
route_spec_key: &PublicKey,
) -> Option<&'a mut RouteSpecDetail> {
inner.content.details.get_mut(route_spec_key)
}
@@ -1594,9 +1594,10 @@ impl RouteSpecStore {
&self,
inner: &mut RouteSpecStoreInner,
rti: &RoutingTableInner,
crypto_kind: CryptoKind,
safety_spec: &SafetySpec,
direction: DirectionSet,
avoid_nodes: &[PublicKey],
avoid_nodes: &[TypedKey],
) -> 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;
@@ -1610,9 +1611,12 @@ impl RouteSpecStore {
// See if the preferred route is here
if let Some(preferred_route) = safety_spec.preferred_route {
if let Some(preferred_rsd) = inner.content.details.get(&preferred_route) {
// Only use the preferred route if it doesn't end with the avoid nodes
if !avoid_node_ids.contains(preferred_rsd.hops.last().unwrap()) {
return Ok(Some(preferred_route));
// Only use the preferred route if it has the desire crypto kind
if preferred_rsd.crypto_kind == crypto_kind {
// Only use the preferred route if it doesn't end with the avoid nodes
if !avoid_nodes.contains(&TypedKey::new(crypto_kind, preferred_rsd.hops.last().cloned().unwrap())) {
return Ok(Some(preferred_route));
}
}
}
}
@@ -1657,7 +1661,7 @@ impl RouteSpecStore {
&self,
crypto_kind: CryptoKind,
safety_spec: &SafetySpec,
avoid_nodes: &[PublicKey],
avoid_nodes: &[TypedKey],
) -> EyreResult<Option<PublicKey>> {
let inner = &mut *self.inner.lock();
let routing_table = self.unlocked_inner.routing_table.clone();
@@ -1666,6 +1670,7 @@ impl RouteSpecStore {
Ok(self.get_route_for_safety_spec_inner(
inner,
rti,
crypto_kind,
safety_spec,
Direction::Inbound.into(),
avoid_nodes,
@@ -1673,6 +1678,7 @@ impl RouteSpecStore {
}
/// Assemble private route for publication
/// Returns a PrivateRoute object for an allocated private route
#[instrument(level = "trace", skip(self), err)]
pub fn assemble_private_route(
&self,
@@ -1683,8 +1689,15 @@ impl RouteSpecStore {
let routing_table = self.unlocked_inner.routing_table.clone();
let rti = &*routing_table.inner.read();
// Get the route spec detail for the requested private route
let rsd = Self::detail(inner, key).ok_or_else(|| eyre!("route does not exist"))?;
// Ensure we get the crypto for it
let crypto = routing_table.network_manager().crypto();
let Some(vcrypto) = crypto.get(rsd.crypto_kind) else {
bail!("crypto not supported for route");
};
// See if we can optimize this compilation yet
// We don't want to include full nodeinfo if we don't have to
let optimized = optimized
@@ -1696,7 +1709,10 @@ impl RouteSpecStore {
if !rti.has_valid_own_node_info(RoutingDomain::PublicInternet) {
bail!("can't make private routes until our node info is valid");
}
RouteNode::NodeId(NodeId::new(routing_table.node_id()))
let Some(node_id) = routing_table.node_ids().get(rsd.crypto_kind) else {
bail!("missing node id for crypto kind");
};
RouteNode::NodeId(node_id.key)
} else {
let Some(pi) = rti.get_own_peer_info(RoutingDomain::PublicInternet) else {
bail!("can't make private routes until our node info is valid");
@@ -1706,12 +1722,11 @@ impl RouteSpecStore {
next_hop: None,
};
let crypto = routing_table.network_manager().crypto();
// Loop for each hop
let hop_count = rsd.hops.len();
// iterate hops in private route order (reverse, but inside out)
for h in 0..hop_count {
let nonce = Crypto::get_random_nonce();
let nonce = vcrypto.random_nonce();
let blob_data = {
let mut rh_message = ::capnp::message::Builder::new_default();
@@ -1721,10 +1736,10 @@ impl RouteSpecStore {
};
// Encrypt the previous blob ENC(nonce, DH(PKhop,SKpr))
let dh_secret = crypto
let dh_secret = vcrypto
.cached_dh(&rsd.hops[h], &rsd.secret_key)
.wrap_err("dh failed")?;
let enc_msg_data = Crypto::encrypt_aead(blob_data.as_slice(), &nonce, &dh_secret, None)
let enc_msg_data = vcrypto.encrypt_aead(blob_data.as_slice(), &nonce, &dh_secret, None)
.wrap_err("encryption failed")?;
let route_hop_data = RouteHopData {
nonce,
@@ -1734,14 +1749,14 @@ impl RouteSpecStore {
route_hop = RouteHop {
node: if optimized {
// Optimized, no peer info, just the dht key
RouteNode::NodeId(NodeId::new(rsd.hops[h]))
RouteNode::NodeId(rsd.hops[h])
} else {
// Full peer info, required until we are sure the route has been fully established
let node_id = rsd.hops[h];
let node_id = TypedKey::new(rsd.crypto_kind, rsd.hops[h]);
let pi = rti
.with_node_entry(node_id, |entry| {
entry.with(rti, |_rti, e| {
e.make_peer_info(node_id, RoutingDomain::PublicInternet)
e.make_peer_info(RoutingDomain::PublicInternet)
})
})
.flatten();
@@ -1755,7 +1770,7 @@ impl RouteSpecStore {
}
let private_route = PrivateRoute {
public_key: key.clone(),
public_key: TypedKey::new(rsd.crypto_kind, key.clone()),
// add hop for 'FirstHop'
hop_count: (hop_count + 1).try_into().unwrap(),
hops: PrivateRouteHops::FirstHop(route_hop),
@@ -1765,27 +1780,35 @@ 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<PublicKey> {
pub fn import_remote_private_route(&self, blob: Vec<u8>) -> EyreResult<TypedKeySet> {
// decode the pr blob
let private_route = RouteSpecStore::blob_to_private_route(blob)?;
let private_routes = RouteSpecStore::blob_to_private_routes(blob)?;
// ensure private route has first hop
if !matches!(private_route.hops, PrivateRouteHops::FirstHop(_)) {
bail!("private route must have first hop");
}
// ensure this isn't also an allocated route
let mut out = TypedKeySet::new();
let inner = &mut *self.inner.lock();
if Self::detail(inner, &private_route.public_key).is_some() {
bail!("should not import allocated route");
for private_route in private_routes {
// ensure private route has first hop
if !matches!(private_route.hops, PrivateRouteHops::FirstHop(_)) {
bail!("private route must have first hop");
}
// ensure this isn't also an allocated route
if Self::detail(inner, &private_route.public_key.key).is_some() {
bail!("should not import allocated route");
}
// store the private route in our cache
let cur_ts = get_aligned_timestamp();
let key = Self::with_create_remote_private_route(inner, cur_ts, private_route, |r| {
r.private_route.as_ref().unwrap().public_key.clone()
});
out.add(key);
}
// store the private route in our cache
let cur_ts = get_aligned_timestamp();
let key = Self::with_create_remote_private_route(inner, cur_ts, private_route, |r| {
r.private_route.as_ref().unwrap().public_key.clone()
});
Ok(key)
Ok(out)
}
/// Release a remote private route that is no longer in use
@@ -1829,7 +1852,7 @@ impl RouteSpecStore {
where
F: FnOnce(&mut RemotePrivateRouteInfo) -> R,
{
let pr_pubkey = private_route.public_key;
let pr_pubkey = private_route.public_key.key;
let rpr = inner
.cache
@@ -2045,33 +2068,64 @@ impl RouteSpecStore {
}
}
/// Convert private route to binary blob
pub fn private_route_to_blob(private_route: &PrivateRoute) -> EyreResult<Vec<u8>> {
/// Convert private route list to binary blob
pub fn private_routes_to_blob(private_routes: &[PrivateRoute]) -> EyreResult<Vec<u8>> {
let mut pr_message = ::capnp::message::Builder::new_default();
let mut pr_builder = pr_message.init_root::<veilid_capnp::private_route::Builder>();
encode_private_route(&private_route, &mut pr_builder)
.wrap_err("failed to encode private route")?;
let mut buffer = vec![];
capnp::serialize_packed::write_message(&mut buffer, &pr_message)
.map_err(RPCError::internal)
.wrap_err("failed to convert builder to vec")?;
// Serialize count
let pr_count = private_routes.len();
if pr_count > MAX_CRYPTO_KINDS {
bail!("too many crypto kinds to encode blob");
}
let pr_count = pr_count as u8;
buffer.push(pr_count);
// Serialize stream of private routes
for private_route in private_routes {
encode_private_route(private_route, &mut pr_builder)
.wrap_err("failed to encode private route")?;
capnp::serialize_packed::write_message(&mut buffer, &pr_message)
.map_err(RPCError::internal)
.wrap_err("failed to convert builder to vec")?;
}
Ok(buffer)
}
/// Convert binary blob to private route
pub fn blob_to_private_route(blob: Vec<u8>) -> EyreResult<PrivateRoute> {
let reader = capnp::serialize_packed::read_message(
blob.as_slice(),
capnp::message::ReaderOptions::new(),
)
.map_err(RPCError::internal)
.wrap_err("failed to make message reader")?;
pub fn blob_to_private_routes(blob: Vec<u8>) -> EyreResult<Vec<PrivateRoute>> {
let pr_reader = reader
.get_root::<veilid_capnp::private_route::Reader>()
// Deserialize count
if blob.is_empty() {
bail!("not deserializing empty private route blob");
}
let pr_count = blob[0] as usize;
if pr_count > MAX_CRYPTO_KINDS {
bail!("too many crypto kinds to decode blob");
}
// Deserialize stream of private routes
let pr_slice = &blob[1..];
let mut out = Vec::with_capacity(pr_count);
for _ in 0..pr_count {
let reader = capnp::serialize_packed::read_message(
&mut pr_slice,
capnp::message::ReaderOptions::new(),
)
.map_err(RPCError::internal)
.wrap_err("failed to make reader for private_route")?;
decode_private_route(&pr_reader).wrap_err("failed to decode private route")
.wrap_err("failed to make message reader")?;
let pr_reader = reader
.get_root::<veilid_capnp::private_route::Reader>()
.map_err(RPCError::internal)
.wrap_err("failed to make reader for private_route")?;
let private_route = decode_private_route(&pr_reader).wrap_err("failed to decode private route")?;
out.push(private_route);
}
Ok(out)
}
}

View File

@@ -413,6 +413,7 @@ impl RoutingTableInner {
&self,
routing_domain_set: RoutingDomainSet,
min_state: BucketEntryState,
crypto_kinds: &[CryptoKind], xxx finish this and peer minimum refresh and bootstrap tick, then both routines
) -> usize {
let mut count = 0usize;
let cur_ts = get_aligned_timestamp();
@@ -451,7 +452,7 @@ impl RoutingTableInner {
mut f: F,
) -> Option<T> {
for entry in self.all_entries {
if entry.with(self, |_rti, e| e.state(cur_ts) >= min_state) {
if entry.with_inner(|e| e.state(cur_ts) >= min_state) {
if let Some(out) = f(self, entry) {
return Some(out);
}
@@ -474,7 +475,7 @@ impl RoutingTableInner {
// Collect all entries that are 'needs_ping' and have some node info making them reachable somehow
let mut node_refs = Vec::<NodeRef>::with_capacity(self.bucket_entry_count());
self.with_entries(cur_ts, BucketEntryState::Unreliable, |rti, entry| {
if entry.with(rti, |rti, e| {
if entry.with_inner(|e| {
// If this isn't in the routing domain we are checking, don't include it
if !e.exists_in_routing_domain(rti, routing_domain) {
return false;
@@ -757,7 +758,7 @@ impl RoutingTableInner {
let cur_ts = get_aligned_timestamp();
for entry in self.all_entries {
match entry.with(self, |_rti, e| e.state(cur_ts)) {
match entry.with_inner(|e| e.state(cur_ts)) {
BucketEntryState::Reliable => {
reliable_entry_count += 1;
}
@@ -807,7 +808,7 @@ impl RoutingTableInner {
) -> Vec<NodeRef> {
let public_node_filter = Box::new(|rti: &RoutingTableInner, v: Option<Arc<BucketEntry>>| {
let entry = v.unwrap();
entry.with(rti, |_rti, e| {
entry.with_inner(|e| {
// skip nodes on local network
if e.node_info(RoutingDomain::LocalNetwork).is_some() {
return false;
@@ -838,7 +839,7 @@ impl RoutingTableInner {
) -> bool {
match entry {
None => has_valid_own_node_info,
Some(entry) => entry.with(self, |_rti, e| {
Some(entry) => entry.with_inner(|e| {
e.signed_node_info(routing_domain.into())
.map(|sni| sni.has_any_signature())
.unwrap_or(false)
@@ -854,7 +855,7 @@ impl RoutingTableInner {
) -> PeerInfo {
match entry {
None => own_peer_info.clone(),
Some(entry) => entry.with(self, |_rti, e| e.make_peer_info(routing_domain).unwrap()),
Some(entry) => entry.with_inner(|e| e.make_peer_info(routing_domain).unwrap()),
}
}
@@ -932,7 +933,7 @@ impl RoutingTableInner {
move |rti: &RoutingTableInner, v: Option<Arc<BucketEntry>>| {
if let Some(entry) = &v {
// always filter out dead nodes
if entry.with(rti, |_rti, e| e.state(cur_ts) == BucketEntryState::Dead) {
if entry.with_inner(|e| e.state(cur_ts) == BucketEntryState::Dead) {
false
} else {
true
@@ -970,8 +971,8 @@ impl RoutingTableInner {
// reliable nodes come first
let ae = a_entry.as_ref().unwrap();
let be = b_entry.as_ref().unwrap();
ae.with(rti, |rti, ae| {
be.with(rti, |_rti, be| {
ae.with_inner(|ae| {
be.with_inner(|be| {
let ra = ae.check_reliable(cur_ts);
let rb = be.check_reliable(cur_ts);
if ra != rb {
@@ -1020,7 +1021,25 @@ impl RoutingTableInner {
{
let cur_ts = get_aligned_timestamp();
// closest sort
// Get the crypto kind
let crypto_kind = node_id.kind;
let vcrypto = self.unlocked_inner.crypto().get(crypto_kind).unwrap();
// Filter to ensure entries support the crypto kind in use
let filter = Box::new(
move |rti: &RoutingTableInner, opt_entry: Option<Arc<BucketEntry>>| {
if let Some(entry) = opt_entry {
entry.with_inner(|e| e.crypto_kinds().contains(&crypto_kind))
} else {
VALID_CRYPTO_KINDS.contains(&crypto_kind)
}
},
) as RoutingTableEntryFilter;
filters.push_front(filter);
// Closest sort
// Distance is done using the node id's distance metric which may vary based on crypto system
let sort = |rti: &RoutingTableInner,
a_entry: &Option<Arc<BucketEntry>>,
b_entry: &Option<Arc<BucketEntry>>| {
@@ -1038,10 +1057,10 @@ impl RoutingTableInner {
// reliable nodes come first, pessimistically treating our own node as unreliable
let ra = a_entry
.as_ref()
.map_or(false, |x| x.with(rti, |_rti, x| x.check_reliable(cur_ts)));
.map_or(false, |x| x.with_inner(|x| x.check_reliable(cur_ts)));
let rb = b_entry
.as_ref()
.map_or(false, |x| x.with(rti, |_rti, x| x.check_reliable(cur_ts)));
.map_or(false, |x| x.with_inner(|x| x.check_reliable(cur_ts)));
if ra != rb {
if ra {
return core::cmp::Ordering::Less;
@@ -1050,9 +1069,24 @@ impl RoutingTableInner {
}
}
// get keys
let a_key = if let Some(a_entry) = a_entry {
a_entry.with_inner(|e| e.node_ids().get(crypto_kind).unwrap())
} else {
self.unlocked_inner.node_id(crypto_kind)
};
let b_key = if let Some(b_entry) = b_entry {
b_entry.with_inner(|e| e.node_ids().get(crypto_kind).unwrap())
} else {
self.unlocked_inner.node_id(crypto_kind)
};
// distance is the next metric, closer nodes first
let da = distance(a_key, &node_id);
let db = distance(b_key, &node_id);
// since multiple cryptosystems are in use, the distance for a key is the shortest
// distance to that key over all supported cryptosystems
let da = vcrypto.distance(&a_key.key, &node_id.key);
let db = vcrypto.distance(&b_key.key, &node_id.key);
da.cmp(&db)
};

View File

@@ -262,12 +262,15 @@ impl RoutingTable {
self.register_node_with_peer_info(RoutingDomain::PublicInternet, pi, false)
{
// Add this our futures to process in parallel
let routing_table = self.clone();
unord.push(
// lets ask bootstrap to find ourselves now
async move { routing_table.reverse_find_node(nr, true).await }
.instrument(Span::current()),
);
for crypto_kind in VALID_CRYPTO_KINDS {
let routing_table = self.clone();
let nr = nr.clone();
unord.push(
// lets ask bootstrap to find ourselves now
async move { routing_table.reverse_find_node(crypto_kind, nr, true).await }
.instrument(Span::current()),
);
}
}
}
}
@@ -337,27 +340,32 @@ impl RoutingTable {
self.register_node_with_peer_info(RoutingDomain::PublicInternet, pi, true)
{
// Add this our futures to process in parallel
let routing_table = self.clone();
unord.push(
async move {
// Need VALID signed peer info, so ask bootstrap to find_node of itself
// which will ensure it has the bootstrap's signed peer info as part of the response
let _ = routing_table.find_target(nr.clone()).await;
for crypto_kind in VALID_CRYPTO_KINDS {
let nr = nr.clone();
let routing_table = self.clone();
unord.push(
async move {
// Need VALID signed peer info, so ask bootstrap to find_node of itself
// which will ensure it has the bootstrap's signed peer info as part of the response
let _ = routing_table.find_target(crypto_kind, nr.clone()).await;
// Ensure we got the signed peer info
if !nr.signed_node_info_has_valid_signature(RoutingDomain::PublicInternet) {
log_rtab!(warn
"bootstrap at {:?} did not return valid signed node info",
nr
);
// If this node info is invalid, it will time out after being unpingable
} else {
// otherwise this bootstrap is valid, lets ask it to find ourselves now
routing_table.reverse_find_node(nr, true).await
// Ensure we got the signed peer info
if !nr
.signed_node_info_has_valid_signature(RoutingDomain::PublicInternet)
{
log_rtab!(warn
"bootstrap at {:?} did not return valid signed node info",
nr
);
// If this node info is invalid, it will time out after being unpingable
} else {
// otherwise this bootstrap is valid, lets ask it to find ourselves now
routing_table.reverse_find_node(crypto_kind, nr, true).await
}
}
}
.instrument(Span::current()),
);
.instrument(Span::current()),
);
}
}
}

View File

@@ -20,22 +20,39 @@ impl RoutingTable {
// For the PublicInternet routing domain, get list of all peers we know about
// even the unreliable ones, and ask them to find nodes close to our node too
let routing_table = self.clone();
let noderefs = routing_table.find_fastest_nodes(
min_peer_count,
VecDeque::new(),
|_rti, entry: Option<Arc<BucketEntry>>| {
NodeRef::new(routing_table.clone(), entry.unwrap().clone(), None)
},
);
let mut ord = FuturesOrdered::new();
for nr in noderefs {
for crypto_kind in VALID_CRYPTO_KINDS {
let routing_table = self.clone();
ord.push_back(
async move { routing_table.reverse_find_node(nr, false).await }
.instrument(Span::current()),
let mut filters = VecDeque::new();
let filter = Box::new(
move |rti: &RoutingTableInner, opt_entry: Option<Arc<BucketEntry>>| {
if let Some(entry) = opt_entry {
entry.with_inner(|e| e.crypto_kinds().contains(&crypto_kind))
} else {
VALID_CRYPTO_KINDS.contains(&crypto_kind)
}
},
) as RoutingTableEntryFilter;
filters.push_front(filter);
let noderefs = routing_table.find_fastest_nodes(
min_peer_count,
filters,
|_rti, entry: Option<Arc<BucketEntry>>| {
NodeRef::new(routing_table.clone(), entry.unwrap().clone(), None)
},
);
for nr in noderefs {
let routing_table = self.clone();
ord.push_back(
async move { routing_table.reverse_find_node(nr, false).await }
.instrument(Span::current()),
);
}
}
// do peer minimum search in order from fastest to slowest