protocol level capabilities
This commit is contained in:
parent
8f721c428b
commit
907075411d
@ -273,7 +273,8 @@ struct OperationReturnReceipt @0xeb0fb5b5a9160eeb {
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct OperationFindNodeQ @0xfdef788fe9623bcd {
|
struct OperationFindNodeQ @0xfdef788fe9623bcd {
|
||||||
nodeId @0 :TypedKey; # node id to locate
|
nodeId @0 :TypedKey; # node id to locate
|
||||||
|
capabilities @1 :List(Capability); # required capabilities returned peers must have
|
||||||
}
|
}
|
||||||
|
|
||||||
struct OperationFindNodeA @0xa84cf2fb40c77089 {
|
struct OperationFindNodeA @0xa84cf2fb40c77089 {
|
||||||
|
@ -170,6 +170,13 @@ impl BucketEntryInner {
|
|||||||
common_crypto_kinds(&self.validated_node_ids.kinds(), other)
|
common_crypto_kinds(&self.validated_node_ids.kinds(), other)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Capability check
|
||||||
|
pub fn has_capabilities(&self, routing_domain: RoutingDomain, capabilities: &[Capability]) -> bool {
|
||||||
|
let Some(ni) = self.node_info(routing_domain) else {
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
ni.has_capabilities(capabilities)
|
||||||
|
}
|
||||||
|
|
||||||
// Less is faster
|
// Less is faster
|
||||||
pub fn cmp_fastest(e1: &Self, e2: &Self) -> std::cmp::Ordering {
|
pub fn cmp_fastest(e1: &Self, e2: &Self) -> std::cmp::Ordering {
|
||||||
|
@ -2,7 +2,11 @@ use super::*;
|
|||||||
|
|
||||||
impl RoutingTable {
|
impl RoutingTable {
|
||||||
/// Utility to find all closest nodes to a particular key, including possibly our own node and nodes further away from the key than our own, returning their peer info
|
/// Utility to find all closest nodes to a particular key, including possibly our own node and nodes further away from the key than our own, returning their peer info
|
||||||
pub fn find_all_closest_peers(&self, key: TypedKey) -> NetworkResult<Vec<PeerInfo>> {
|
pub fn find_all_closest_peers(
|
||||||
|
&self,
|
||||||
|
key: TypedKey,
|
||||||
|
capabilities: &[Capability],
|
||||||
|
) -> NetworkResult<Vec<PeerInfo>> {
|
||||||
let Some(own_peer_info) = self.get_own_peer_info(RoutingDomain::PublicInternet) else {
|
let Some(own_peer_info) = self.get_own_peer_info(RoutingDomain::PublicInternet) else {
|
||||||
// Our own node info is not yet available, drop this request.
|
// Our own node info is not yet available, drop this request.
|
||||||
return NetworkResult::service_unavailable("Not finding closest peers because our peer info is not yet available");
|
return NetworkResult::service_unavailable("Not finding closest peers because our peer info is not yet available");
|
||||||
@ -12,11 +16,27 @@ impl RoutingTable {
|
|||||||
let filter = Box::new(
|
let filter = Box::new(
|
||||||
move |rti: &RoutingTableInner, opt_entry: Option<Arc<BucketEntry>>| {
|
move |rti: &RoutingTableInner, opt_entry: Option<Arc<BucketEntry>>| {
|
||||||
// Ensure only things that are valid/signed in the PublicInternet domain are returned
|
// Ensure only things that are valid/signed in the PublicInternet domain are returned
|
||||||
rti.filter_has_valid_signed_node_info(
|
if !rti.filter_has_valid_signed_node_info(
|
||||||
RoutingDomain::PublicInternet,
|
RoutingDomain::PublicInternet,
|
||||||
true,
|
true,
|
||||||
opt_entry,
|
opt_entry.clone(),
|
||||||
)
|
) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// Ensure capabilities are met
|
||||||
|
match opt_entry {
|
||||||
|
Some(entry) => entry.with(rti, |_rti, e| {
|
||||||
|
e.has_capabilities(RoutingDomain::PublicInternet, capabilities)
|
||||||
|
}),
|
||||||
|
None => rti
|
||||||
|
.get_own_peer_info(RoutingDomain::PublicInternet)
|
||||||
|
.map(|pi| {
|
||||||
|
pi.signed_node_info()
|
||||||
|
.node_info()
|
||||||
|
.has_capabilities(capabilities)
|
||||||
|
})
|
||||||
|
.unwrap_or(false),
|
||||||
|
}
|
||||||
},
|
},
|
||||||
) as RoutingTableEntryFilter;
|
) as RoutingTableEntryFilter;
|
||||||
let filters = VecDeque::from([filter]);
|
let filters = VecDeque::from([filter]);
|
||||||
@ -40,7 +60,12 @@ impl RoutingTable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Utility to find nodes that are closer to a key than our own node, returning their peer info
|
/// Utility to find nodes that are closer to a key than our own node, returning their peer info
|
||||||
pub fn find_peers_closer_to_key(&self, key: TypedKey) -> NetworkResult<Vec<PeerInfo>> {
|
/// Can filter based on a particular set of capabiltiies
|
||||||
|
pub fn find_peers_closer_to_key(
|
||||||
|
&self,
|
||||||
|
key: TypedKey,
|
||||||
|
required_capabilities: Vec<Capability>,
|
||||||
|
) -> NetworkResult<Vec<PeerInfo>> {
|
||||||
// add node information for the requesting node to our routing table
|
// add node information for the requesting node to our routing table
|
||||||
let crypto_kind = key.kind;
|
let crypto_kind = key.kind;
|
||||||
let own_node_id = self.node_id(crypto_kind);
|
let own_node_id = self.node_id(crypto_kind);
|
||||||
@ -59,24 +84,29 @@ impl RoutingTable {
|
|||||||
let Some(entry) = opt_entry else {
|
let Some(entry) = opt_entry else {
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
// Ensure only things that are valid/signed in the PublicInternet domain are returned
|
// Ensure only things that have a minimum set of capabilities are returned
|
||||||
if !rti.filter_has_valid_signed_node_info(
|
entry.with(rti, |rti, e| {
|
||||||
RoutingDomain::PublicInternet,
|
if !e.has_capabilities(RoutingDomain::PublicInternet, &required_capabilities) {
|
||||||
true,
|
return false;
|
||||||
Some(entry.clone()),
|
}
|
||||||
) {
|
// Ensure only things that are valid/signed in the PublicInternet domain are returned
|
||||||
return false;
|
if !rti.filter_has_valid_signed_node_info(
|
||||||
}
|
RoutingDomain::PublicInternet,
|
||||||
// Ensure things further from the key than our own node are not included
|
true,
|
||||||
let Some(entry_node_id) = entry.with(rti, |_rti, e| e.node_ids().get(crypto_kind)) else {
|
Some(entry.clone()),
|
||||||
return false;
|
) {
|
||||||
};
|
return false;
|
||||||
let entry_distance = vcrypto.distance(&entry_node_id.value, &key.value);
|
}
|
||||||
if entry_distance >= own_distance {
|
// Ensure things further from the key than our own node are not included
|
||||||
return false;
|
let Some(entry_node_id) = e.node_ids().get(crypto_kind) else {
|
||||||
}
|
return false;
|
||||||
|
};
|
||||||
true
|
let entry_distance = vcrypto.distance(&entry_node_id.value, &key.value);
|
||||||
|
if entry_distance >= own_distance {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
true
|
||||||
|
})
|
||||||
},
|
},
|
||||||
) as RoutingTableEntryFilter;
|
) as RoutingTableEntryFilter;
|
||||||
let filters = VecDeque::from([filter]);
|
let filters = VecDeque::from([filter]);
|
||||||
|
@ -1072,7 +1072,7 @@ impl RoutingTable {
|
|||||||
let res = network_result_try!(
|
let res = network_result_try!(
|
||||||
rpc_processor
|
rpc_processor
|
||||||
.clone()
|
.clone()
|
||||||
.rpc_call_find_node(Destination::direct(node_ref), node_id)
|
.rpc_call_find_node(Destination::direct(node_ref), node_id, vec![])
|
||||||
.await?
|
.await?
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -258,7 +258,7 @@ impl RouteSpecStore {
|
|||||||
// Exclude nodes with no publicinternet nodeinfo, or incompatible nodeinfo or node status won't route
|
// Exclude nodes with no publicinternet nodeinfo, or incompatible nodeinfo or node status won't route
|
||||||
entry.with_inner(|e| {
|
entry.with_inner(|e| {
|
||||||
e.signed_node_info(RoutingDomain::PublicInternet).map(|sni|
|
e.signed_node_info(RoutingDomain::PublicInternet).map(|sni|
|
||||||
sni.has_sequencing_matched_dial_info(sequencing) && sni.node_info().can_route()
|
sni.has_sequencing_matched_dial_info(sequencing) && sni.node_info().has_capability(CAP_ROUTE)
|
||||||
).unwrap_or(false)
|
).unwrap_or(false)
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
@ -9,7 +9,7 @@ const BACKGROUND_SAFETY_ROUTE_COUNT: usize = 2;
|
|||||||
impl RoutingTable {
|
impl RoutingTable {
|
||||||
fn get_background_safety_route_count(&self) -> usize {
|
fn get_background_safety_route_count(&self) -> usize {
|
||||||
let c = self.config.get();
|
let c = self.config.get();
|
||||||
if c.capabilities.disable.contains(&CAP_WILL_ROUTE) {
|
if c.capabilities.disable.contains(&CAP_ROUTE) {
|
||||||
0
|
0
|
||||||
} else {
|
} else {
|
||||||
BACKGROUND_SAFETY_ROUTE_COUNT
|
BACKGROUND_SAFETY_ROUTE_COUNT
|
||||||
|
@ -100,6 +100,11 @@ impl RoutingTable {
|
|||||||
let can_serve_as_relay = e
|
let can_serve_as_relay = e
|
||||||
.node_info(RoutingDomain::PublicInternet)
|
.node_info(RoutingDomain::PublicInternet)
|
||||||
.map(|n| {
|
.map(|n| {
|
||||||
|
if !(n.has_capability(CAP_RELAY) && n.is_signal_capable()) {
|
||||||
|
// Needs to be able to signal and relay
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
let dids = n.all_filtered_dial_info_details(DialInfoDetail::NO_SORT, |did| {
|
let dids = n.all_filtered_dial_info_details(DialInfoDetail::NO_SORT, |did| {
|
||||||
did.matches_filter(&outbound_dif)
|
did.matches_filter(&outbound_dif)
|
||||||
});
|
});
|
||||||
@ -145,26 +150,23 @@ impl RoutingTable {
|
|||||||
inner.with_entries(cur_ts, BucketEntryState::Unreliable, |rti, entry| {
|
inner.with_entries(cur_ts, BucketEntryState::Unreliable, |rti, entry| {
|
||||||
let entry2 = entry.clone();
|
let entry2 = entry.clone();
|
||||||
entry.with(rti, |rti, e| {
|
entry.with(rti, |rti, e| {
|
||||||
// Ensure we have the node's status
|
// Filter this node
|
||||||
if let Some(node_info) = e.node_info(routing_domain) {
|
if relay_node_filter(e) {
|
||||||
// Ensure the node will relay
|
// Compare against previous candidate
|
||||||
if node_info.can_inbound_relay() {
|
if let Some(best_inbound_relay) = best_inbound_relay.as_mut() {
|
||||||
// Compare against previous candidate
|
// Less is faster
|
||||||
if let Some(best_inbound_relay) = best_inbound_relay.as_mut() {
|
let better = best_inbound_relay.with(rti, |_rti, best| {
|
||||||
// Less is faster
|
// choose low latency stability for relays
|
||||||
let better = best_inbound_relay.with(rti, |_rti, best| {
|
BucketEntryInner::cmp_fastest_reliable(cur_ts, e, best)
|
||||||
// choose low latency stability for relays
|
== std::cmp::Ordering::Less
|
||||||
BucketEntryInner::cmp_fastest_reliable(cur_ts, e, best)
|
});
|
||||||
== std::cmp::Ordering::Less
|
// Now apply filter function and see if this node should be included
|
||||||
});
|
if better {
|
||||||
// Now apply filter function and see if this node should be included
|
*best_inbound_relay = entry2;
|
||||||
if better && relay_node_filter(e) {
|
|
||||||
*best_inbound_relay = entry2;
|
|
||||||
}
|
|
||||||
} else if relay_node_filter(e) {
|
|
||||||
// Always store the first candidate
|
|
||||||
best_inbound_relay = Some(entry2);
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
// Always store the first candidate
|
||||||
|
best_inbound_relay = Some(entry2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -1,16 +1,16 @@
|
|||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
pub type Capability = FourCC;
|
pub type Capability = FourCC;
|
||||||
pub const CAP_WILL_ROUTE: Capability = FourCC(*b"ROUT");
|
pub const CAP_ROUTE: Capability = FourCC(*b"ROUT");
|
||||||
#[cfg(feature = "unstable-tunnels")]
|
#[cfg(feature = "unstable-tunnels")]
|
||||||
pub const CAP_WILL_TUNNEL: Capability = FourCC(*b"TUNL");
|
pub const CAP_TUNNEL: Capability = FourCC(*b"TUNL");
|
||||||
pub const CAP_WILL_SIGNAL: Capability = FourCC(*b"SGNL");
|
pub const CAP_SIGNAL: Capability = FourCC(*b"SGNL");
|
||||||
pub const CAP_WILL_RELAY: Capability = FourCC(*b"RLAY");
|
pub const CAP_RELAY: Capability = FourCC(*b"RLAY");
|
||||||
pub const CAP_WILL_VALIDATE_DIAL_INFO: Capability = FourCC(*b"DIAL");
|
pub const CAP_VALIDATE_DIAL_INFO: Capability = FourCC(*b"DIAL");
|
||||||
pub const CAP_WILL_DHT: Capability = FourCC(*b"DHTV");
|
pub const CAP_DHT: Capability = FourCC(*b"DHTV");
|
||||||
pub const CAP_WILL_APPMESSAGE: Capability = FourCC(*b"APPM");
|
pub const CAP_APPMESSAGE: Capability = FourCC(*b"APPM");
|
||||||
#[cfg(feature = "unstable-blockstore")]
|
#[cfg(feature = "unstable-blockstore")]
|
||||||
pub const CAP_WILL_BLOCKSTORE: Capability = FourCC(*b"BLOC");
|
pub const CAP_BLOCKSTORE: Capability = FourCC(*b"BLOC");
|
||||||
|
|
||||||
cfg_if! {
|
cfg_if! {
|
||||||
if #[cfg(all(feature = "unstable-blockstore", feature="unstable-tunnels"))] {
|
if #[cfg(all(feature = "unstable-blockstore", feature="unstable-tunnels"))] {
|
||||||
@ -22,16 +22,16 @@ cfg_if! {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub const PUBLIC_INTERNET_CAPABILITIES: [Capability; PUBLIC_INTERNET_CAPABILITIES_LEN] = [
|
pub const PUBLIC_INTERNET_CAPABILITIES: [Capability; PUBLIC_INTERNET_CAPABILITIES_LEN] = [
|
||||||
CAP_WILL_ROUTE,
|
CAP_ROUTE,
|
||||||
#[cfg(feature = "unstable-tunnels")]
|
#[cfg(feature = "unstable-tunnels")]
|
||||||
CAP_WILL_TUNNEL,
|
CAP_TUNNEL,
|
||||||
CAP_WILL_SIGNAL,
|
CAP_SIGNAL,
|
||||||
CAP_WILL_RELAY,
|
CAP_RELAY,
|
||||||
CAP_WILL_VALIDATE_DIAL_INFO,
|
CAP_VALIDATE_DIAL_INFO,
|
||||||
CAP_WILL_DHT,
|
CAP_DHT,
|
||||||
CAP_WILL_APPMESSAGE,
|
CAP_APPMESSAGE,
|
||||||
#[cfg(feature = "unstable-blockstore")]
|
#[cfg(feature = "unstable-blockstore")]
|
||||||
CAP_WILL_BLOCKSTORE,
|
CAP_BLOCKSTORE,
|
||||||
];
|
];
|
||||||
|
|
||||||
#[cfg(feature = "unstable-blockstore")]
|
#[cfg(feature = "unstable-blockstore")]
|
||||||
@ -40,11 +40,11 @@ const LOCAL_NETWORK_CAPABILITIES_LEN: usize = 4;
|
|||||||
const LOCAL_NETWORK_CAPABILITIES_LEN: usize = 3;
|
const LOCAL_NETWORK_CAPABILITIES_LEN: usize = 3;
|
||||||
|
|
||||||
pub const LOCAL_NETWORK_CAPABILITIES: [Capability; LOCAL_NETWORK_CAPABILITIES_LEN] = [
|
pub const LOCAL_NETWORK_CAPABILITIES: [Capability; LOCAL_NETWORK_CAPABILITIES_LEN] = [
|
||||||
CAP_WILL_RELAY,
|
CAP_RELAY,
|
||||||
CAP_WILL_DHT,
|
CAP_DHT,
|
||||||
CAP_WILL_APPMESSAGE,
|
CAP_APPMESSAGE,
|
||||||
#[cfg(feature = "unstable-blockstore")]
|
#[cfg(feature = "unstable-blockstore")]
|
||||||
CAP_WILL_BLOCKSTORE,
|
CAP_BLOCKSTORE,
|
||||||
];
|
];
|
||||||
|
|
||||||
pub const MAX_CAPABILITIES: usize = 64;
|
pub const MAX_CAPABILITIES: usize = 64;
|
||||||
@ -199,14 +199,24 @@ impl NodeInfo {
|
|||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
fn has_capability(&self, cap: Capability) -> bool {
|
pub fn has_capability(&self, cap: Capability) -> bool {
|
||||||
self.capabilities.contains(&cap)
|
self.capabilities.contains(&cap)
|
||||||
}
|
}
|
||||||
|
pub fn has_capabilities(&self, capabilities: &[Capability]) -> bool {
|
||||||
|
for cap in capabilities {
|
||||||
|
if !self.has_capability(*cap) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
/// Can this node assist with signalling? Yes but only if it doesn't require signalling, itself.
|
/// Can this node assist with signalling? Yes but only if it doesn't require signalling, itself.
|
||||||
pub fn can_signal(&self) -> bool {
|
/// Also used to determine if nodes are capable of validation of dial info, as that operation
|
||||||
|
/// has the same requirements, inbound capability and a dial info that requires no assistance
|
||||||
|
pub fn is_signal_capable(&self) -> bool {
|
||||||
// Has capability?
|
// Has capability?
|
||||||
if !self.has_capability(CAP_WILL_SIGNAL) {
|
if !self.has_capability(CAP_SIGNAL) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -222,47 +232,4 @@ impl NodeInfo {
|
|||||||
}
|
}
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Can this node relay be an inbound relay?
|
|
||||||
pub fn can_inbound_relay(&self) -> bool {
|
|
||||||
// Has capability?
|
|
||||||
if !self.has_capability(CAP_WILL_RELAY) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// For now this is the same
|
|
||||||
self.can_signal()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Is this node capable of validating dial info
|
|
||||||
pub fn can_validate_dial_info(&self) -> bool {
|
|
||||||
// Has capability?
|
|
||||||
if !self.has_capability(CAP_WILL_VALIDATE_DIAL_INFO) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
// For now this is the same
|
|
||||||
self.can_signal()
|
|
||||||
}
|
|
||||||
/// Is this node capable of private routing
|
|
||||||
pub fn can_route(&self) -> bool {
|
|
||||||
self.has_capability(CAP_WILL_ROUTE)
|
|
||||||
}
|
|
||||||
/// Is this node capable of dht operations
|
|
||||||
pub fn can_dht(&self) -> bool {
|
|
||||||
self.has_capability(CAP_WILL_DHT)
|
|
||||||
}
|
|
||||||
/// Is this node capable of app_message and app_call
|
|
||||||
pub fn can_appmessage(&self) -> bool {
|
|
||||||
self.has_capability(CAP_WILL_APPMESSAGE)
|
|
||||||
}
|
|
||||||
/// Is this node capable of tunneling
|
|
||||||
#[cfg(feature = "unstable-tunnels")]
|
|
||||||
pub fn can_tunnel(&self) -> bool {
|
|
||||||
self.has_capability(CAP_WILL_TUNNEL)
|
|
||||||
}
|
|
||||||
/// Is this node capable of block storage
|
|
||||||
#[cfg(feature = "unstable-blockstore")]
|
|
||||||
pub fn can_blockstore(&self) -> bool {
|
|
||||||
self.has_capability(CAP_WILL_BLOCKSTORE)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -5,11 +5,15 @@ const MAX_FIND_NODE_A_PEERS_LEN: usize = 20;
|
|||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct RPCOperationFindNodeQ {
|
pub struct RPCOperationFindNodeQ {
|
||||||
node_id: TypedKey,
|
node_id: TypedKey,
|
||||||
|
capabilities: Vec<Capability>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RPCOperationFindNodeQ {
|
impl RPCOperationFindNodeQ {
|
||||||
pub fn new(node_id: TypedKey) -> Self {
|
pub fn new(node_id: TypedKey, capabilities: Vec<Capability>) -> Self {
|
||||||
Self { node_id }
|
Self {
|
||||||
|
node_id,
|
||||||
|
capabilities,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
pub fn validate(&mut self, _validate_context: &RPCValidateContext) -> Result<(), RPCError> {
|
pub fn validate(&mut self, _validate_context: &RPCValidateContext) -> Result<(), RPCError> {
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -18,15 +22,33 @@ impl RPCOperationFindNodeQ {
|
|||||||
// pub fn node_id(&self) -> &TypedKey {
|
// pub fn node_id(&self) -> &TypedKey {
|
||||||
// &self.node_id
|
// &self.node_id
|
||||||
// }
|
// }
|
||||||
|
// pub fn capabilities(&self) -> &[Capability] {
|
||||||
|
// &self.capabilities
|
||||||
|
// }
|
||||||
|
|
||||||
pub fn destructure(self) -> TypedKey {
|
pub fn destructure(self) -> (TypedKey, Vec<Capability>) {
|
||||||
self.node_id
|
(self.node_id, self.capabilities)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn decode(reader: &veilid_capnp::operation_find_node_q::Reader) -> Result<Self, RPCError> {
|
pub fn decode(reader: &veilid_capnp::operation_find_node_q::Reader) -> Result<Self, RPCError> {
|
||||||
let ni_reader = reader.get_node_id().map_err(RPCError::protocol)?;
|
let ni_reader = reader.get_node_id().map_err(RPCError::protocol)?;
|
||||||
let node_id = decode_typed_key(&ni_reader)?;
|
let node_id = decode_typed_key(&ni_reader)?;
|
||||||
Ok(Self { node_id })
|
let cap_reader = reader
|
||||||
|
.reborrow()
|
||||||
|
.get_capabilities()
|
||||||
|
.map_err(RPCError::protocol)?;
|
||||||
|
if cap_reader.len() as usize > MAX_CAPABILITIES {
|
||||||
|
return Err(RPCError::protocol("too many capabilities"));
|
||||||
|
}
|
||||||
|
let capabilities = cap_reader
|
||||||
|
.as_slice()
|
||||||
|
.map(|s| s.iter().map(|x| FourCC::from(x.to_be_bytes())).collect())
|
||||||
|
.unwrap_or_default();
|
||||||
|
|
||||||
|
Ok(Self {
|
||||||
|
node_id,
|
||||||
|
capabilities,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
pub fn encode(
|
pub fn encode(
|
||||||
&self,
|
&self,
|
||||||
@ -34,6 +56,19 @@ impl RPCOperationFindNodeQ {
|
|||||||
) -> Result<(), RPCError> {
|
) -> Result<(), RPCError> {
|
||||||
let mut ni_builder = builder.reborrow().init_node_id();
|
let mut ni_builder = builder.reborrow().init_node_id();
|
||||||
encode_typed_key(&self.node_id, &mut ni_builder);
|
encode_typed_key(&self.node_id, &mut ni_builder);
|
||||||
|
|
||||||
|
let mut cap_builder = builder
|
||||||
|
.reborrow()
|
||||||
|
.init_capabilities(self.capabilities.len() as u32);
|
||||||
|
if let Some(s) = cap_builder.as_slice() {
|
||||||
|
let capvec: Vec<u32> = self
|
||||||
|
.capabilities
|
||||||
|
.iter()
|
||||||
|
.map(|x| u32::from_be_bytes(x.0))
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
s.clone_from_slice(&capvec);
|
||||||
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -442,9 +442,11 @@ impl RPCProcessor {
|
|||||||
&self,
|
&self,
|
||||||
routing_domain: RoutingDomain,
|
routing_domain: RoutingDomain,
|
||||||
signed_node_info: &SignedNodeInfo,
|
signed_node_info: &SignedNodeInfo,
|
||||||
|
capabilities: &[Capability],
|
||||||
) -> bool {
|
) -> bool {
|
||||||
let routing_table = self.routing_table();
|
let routing_table = self.routing_table();
|
||||||
routing_table.signed_node_info_is_valid_in_routing_domain(routing_domain, &signed_node_info)
|
routing_table.signed_node_info_is_valid_in_routing_domain(routing_domain, &signed_node_info)
|
||||||
|
&& signed_node_info.node_info().has_capabilities(capabilities)
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////
|
||||||
@ -470,6 +472,7 @@ impl RPCProcessor {
|
|||||||
.rpc_call_find_node(
|
.rpc_call_find_node(
|
||||||
Destination::direct(next_node).with_safety(safety_selection),
|
Destination::direct(next_node).with_safety(safety_selection),
|
||||||
node_id,
|
node_id,
|
||||||
|
vec![],
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
{
|
{
|
||||||
@ -1474,7 +1477,11 @@ impl RPCProcessor {
|
|||||||
// Ensure the sender peer info is for the actual sender specified in the envelope
|
// Ensure the sender peer info is for the actual sender specified in the envelope
|
||||||
|
|
||||||
// Sender PeerInfo was specified, update our routing table with it
|
// Sender PeerInfo was specified, update our routing table with it
|
||||||
if !self.verify_node_info(routing_domain, sender_peer_info.signed_node_info()) {
|
if !self.verify_node_info(
|
||||||
|
routing_domain,
|
||||||
|
sender_peer_info.signed_node_info(),
|
||||||
|
&[],
|
||||||
|
) {
|
||||||
return Ok(NetworkResult::invalid_message(
|
return Ok(NetworkResult::invalid_message(
|
||||||
"sender peerinfo has invalid peer scope",
|
"sender peerinfo has invalid peer scope",
|
||||||
));
|
));
|
||||||
|
@ -57,7 +57,11 @@ impl RPCProcessor {
|
|||||||
let routing_table = self.routing_table();
|
let routing_table = self.routing_table();
|
||||||
{
|
{
|
||||||
if let Some(opi) = routing_table.get_own_peer_info(msg.header.routing_domain()) {
|
if let Some(opi) = routing_table.get_own_peer_info(msg.header.routing_domain()) {
|
||||||
if !opi.signed_node_info().node_info().can_appmessage() {
|
if !opi
|
||||||
|
.signed_node_info()
|
||||||
|
.node_info()
|
||||||
|
.has_capability(CAP_APPMESSAGE)
|
||||||
|
{
|
||||||
return Ok(NetworkResult::service_unavailable(
|
return Ok(NetworkResult::service_unavailable(
|
||||||
"app call is not available",
|
"app call is not available",
|
||||||
));
|
));
|
||||||
|
@ -28,7 +28,11 @@ impl RPCProcessor {
|
|||||||
let routing_table = self.routing_table();
|
let routing_table = self.routing_table();
|
||||||
{
|
{
|
||||||
if let Some(opi) = routing_table.get_own_peer_info(msg.header.routing_domain()) {
|
if let Some(opi) = routing_table.get_own_peer_info(msg.header.routing_domain()) {
|
||||||
if !opi.signed_node_info().node_info().can_appmessage() {
|
if !opi
|
||||||
|
.signed_node_info()
|
||||||
|
.node_info()
|
||||||
|
.has_capability(CAP_APPMESSAGE)
|
||||||
|
{
|
||||||
return Ok(NetworkResult::service_unavailable(
|
return Ok(NetworkResult::service_unavailable(
|
||||||
"app message is not available",
|
"app message is not available",
|
||||||
));
|
));
|
||||||
|
@ -12,7 +12,11 @@ impl RPCProcessor {
|
|||||||
let routing_table = self.routing_table();
|
let routing_table = self.routing_table();
|
||||||
{
|
{
|
||||||
if let Some(opi) = routing_table.get_own_peer_info(msg.header.routing_domain()) {
|
if let Some(opi) = routing_table.get_own_peer_info(msg.header.routing_domain()) {
|
||||||
if !opi.signed_node_info().node_info().can_tunnel() {
|
if !opi
|
||||||
|
.signed_node_info()
|
||||||
|
.node_info()
|
||||||
|
.has_capability(CAP_TUNNEL)
|
||||||
|
{
|
||||||
return Ok(NetworkResult::service_unavailable(
|
return Ok(NetworkResult::service_unavailable(
|
||||||
"tunnel is not available",
|
"tunnel is not available",
|
||||||
));
|
));
|
||||||
|
@ -12,7 +12,11 @@ impl RPCProcessor {
|
|||||||
let routing_table = self.routing_table();
|
let routing_table = self.routing_table();
|
||||||
{
|
{
|
||||||
if let Some(opi) = routing_table.get_own_peer_info(msg.header.routing_domain()) {
|
if let Some(opi) = routing_table.get_own_peer_info(msg.header.routing_domain()) {
|
||||||
if !opi.signed_node_info().node_info().can_tunnel() {
|
if !opi
|
||||||
|
.signed_node_info()
|
||||||
|
.node_info()
|
||||||
|
.has_capability(CAP_TUNNEL)
|
||||||
|
{
|
||||||
return Ok(NetworkResult::service_unavailable(
|
return Ok(NetworkResult::service_unavailable(
|
||||||
"tunnel is not available",
|
"tunnel is not available",
|
||||||
));
|
));
|
||||||
|
@ -15,6 +15,7 @@ impl RPCProcessor {
|
|||||||
self,
|
self,
|
||||||
dest: Destination,
|
dest: Destination,
|
||||||
node_id: TypedKey,
|
node_id: TypedKey,
|
||||||
|
capabilities: Vec<Capability>,
|
||||||
) -> Result<NetworkResult<Answer<Vec<PeerInfo>>>, RPCError> {
|
) -> Result<NetworkResult<Answer<Vec<PeerInfo>>>, RPCError> {
|
||||||
// Ensure destination never has a private route
|
// Ensure destination never has a private route
|
||||||
if matches!(
|
if matches!(
|
||||||
@ -29,7 +30,8 @@ impl RPCProcessor {
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
let find_node_q_detail = RPCQuestionDetail::FindNodeQ(RPCOperationFindNodeQ::new(node_id));
|
let find_node_q_detail =
|
||||||
|
RPCQuestionDetail::FindNodeQ(RPCOperationFindNodeQ::new(node_id, capabilities.clone()));
|
||||||
let find_node_q = RPCQuestion::new(
|
let find_node_q = RPCQuestion::new(
|
||||||
network_result_try!(self.get_destination_respond_to(&dest)?),
|
network_result_try!(self.get_destination_respond_to(&dest)?),
|
||||||
find_node_q_detail,
|
find_node_q_detail,
|
||||||
@ -60,9 +62,13 @@ impl RPCProcessor {
|
|||||||
let peers = find_node_a.destructure();
|
let peers = find_node_a.destructure();
|
||||||
|
|
||||||
for peer_info in &peers {
|
for peer_info in &peers {
|
||||||
if !self.verify_node_info(RoutingDomain::PublicInternet, peer_info.signed_node_info()) {
|
if !self.verify_node_info(
|
||||||
|
RoutingDomain::PublicInternet,
|
||||||
|
peer_info.signed_node_info(),
|
||||||
|
&capabilities,
|
||||||
|
) {
|
||||||
return Ok(NetworkResult::invalid_message(
|
return Ok(NetworkResult::invalid_message(
|
||||||
"find_node response has invalid peer scope",
|
"find_node response does not meet peer criteria",
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -94,11 +100,12 @@ impl RPCProcessor {
|
|||||||
},
|
},
|
||||||
_ => panic!("not a question"),
|
_ => panic!("not a question"),
|
||||||
};
|
};
|
||||||
let node_id = find_node_q.destructure();
|
let (node_id, capabilities) = find_node_q.destructure();
|
||||||
|
|
||||||
// Get a chunk of the routing table near the requested node id
|
// Get a chunk of the routing table near the requested node id
|
||||||
let routing_table = self.routing_table();
|
let routing_table = self.routing_table();
|
||||||
let closest_nodes = network_result_try!(routing_table.find_all_closest_peers(node_id));
|
let closest_nodes =
|
||||||
|
network_result_try!(routing_table.find_all_closest_peers(node_id, &capabilities));
|
||||||
|
|
||||||
// Make FindNode answer
|
// Make FindNode answer
|
||||||
let find_node_a = RPCOperationFindNodeA::new(closest_nodes)?;
|
let find_node_a = RPCOperationFindNodeA::new(closest_nodes)?;
|
||||||
|
@ -177,7 +177,7 @@ impl RPCProcessor {
|
|||||||
let routing_table = self.routing_table();
|
let routing_table = self.routing_table();
|
||||||
{
|
{
|
||||||
if let Some(opi) = routing_table.get_own_peer_info(msg.header.routing_domain()) {
|
if let Some(opi) = routing_table.get_own_peer_info(msg.header.routing_domain()) {
|
||||||
if !opi.signed_node_info().node_info().can_dht() {
|
if !opi.signed_node_info().node_info().has_capability(CAP_DHT) {
|
||||||
return Ok(NetworkResult::service_unavailable(
|
return Ok(NetworkResult::service_unavailable(
|
||||||
"dht is not available",
|
"dht is not available",
|
||||||
));
|
));
|
||||||
@ -199,7 +199,7 @@ impl RPCProcessor {
|
|||||||
|
|
||||||
// Get the nodes that we know about that are closer to the the key than our own node
|
// Get the nodes that we know about that are closer to the the key than our own node
|
||||||
let routing_table = self.routing_table();
|
let routing_table = self.routing_table();
|
||||||
let closer_to_key_peers = network_result_try!(routing_table.find_peers_closer_to_key(key));
|
let closer_to_key_peers = network_result_try!(routing_table.find_peers_closer_to_key(key, vec![CAP_DHT]));
|
||||||
|
|
||||||
let debug_string = format!(
|
let debug_string = format!(
|
||||||
"IN <=== GetValueQ({} #{}{}) <== {}",
|
"IN <=== GetValueQ({} #{}{}) <== {}",
|
||||||
|
@ -369,7 +369,7 @@ impl RPCProcessor {
|
|||||||
let routing_table = self.routing_table();
|
let routing_table = self.routing_table();
|
||||||
{
|
{
|
||||||
if let Some(opi) = routing_table.get_own_peer_info(msg.header.routing_domain()) {
|
if let Some(opi) = routing_table.get_own_peer_info(msg.header.routing_domain()) {
|
||||||
if !opi.signed_node_info().node_info().can_route() {
|
if !opi.signed_node_info().node_info().has_capability(CAP_ROUTE) {
|
||||||
return Ok(NetworkResult::service_unavailable(
|
return Ok(NetworkResult::service_unavailable(
|
||||||
"route is not available",
|
"route is not available",
|
||||||
));
|
));
|
||||||
|
@ -179,7 +179,7 @@ impl RPCProcessor {
|
|||||||
let routing_table = self.routing_table();
|
let routing_table = self.routing_table();
|
||||||
{
|
{
|
||||||
if let Some(opi) = routing_table.get_own_peer_info(msg.header.routing_domain()) {
|
if let Some(opi) = routing_table.get_own_peer_info(msg.header.routing_domain()) {
|
||||||
if !opi.signed_node_info().node_info().can_dht() {
|
if !opi.signed_node_info().node_info().has_capability(CAP_DHT) {
|
||||||
return Ok(NetworkResult::service_unavailable(
|
return Ok(NetworkResult::service_unavailable(
|
||||||
"dht is not available",
|
"dht is not available",
|
||||||
));
|
));
|
||||||
@ -211,7 +211,7 @@ impl RPCProcessor {
|
|||||||
|
|
||||||
// Get the nodes that we know about that are closer to the the key than our own node
|
// Get the nodes that we know about that are closer to the the key than our own node
|
||||||
let routing_table = self.routing_table();
|
let routing_table = self.routing_table();
|
||||||
let closer_to_key_peers = network_result_try!(routing_table.find_peers_closer_to_key(key));
|
let closer_to_key_peers = network_result_try!(routing_table.find_peers_closer_to_key(key, vec![CAP_DHT]));
|
||||||
|
|
||||||
let debug_string = format!(
|
let debug_string = format!(
|
||||||
"IN <=== SetValueQ({} #{} len={} seq={} writer={}{}) <== {}",
|
"IN <=== SetValueQ({} #{} len={} seq={} writer={}{}) <== {}",
|
||||||
|
@ -41,7 +41,7 @@ impl RPCProcessor {
|
|||||||
let routing_table = self.routing_table();
|
let routing_table = self.routing_table();
|
||||||
{
|
{
|
||||||
if let Some(opi) = routing_table.get_own_peer_info(msg.header.routing_domain()) {
|
if let Some(opi) = routing_table.get_own_peer_info(msg.header.routing_domain()) {
|
||||||
if !opi.signed_node_info().node_info().can_signal() {
|
if !opi.signed_node_info().node_info().is_signal_capable() {
|
||||||
return Ok(NetworkResult::service_unavailable(
|
return Ok(NetworkResult::service_unavailable(
|
||||||
"signal is not available",
|
"signal is not available",
|
||||||
));
|
));
|
||||||
|
@ -12,7 +12,11 @@ impl RPCProcessor {
|
|||||||
let routing_table = self.routing_table();
|
let routing_table = self.routing_table();
|
||||||
{
|
{
|
||||||
if let Some(opi) = routing_table.get_own_peer_info(msg.header.routing_domain()) {
|
if let Some(opi) = routing_table.get_own_peer_info(msg.header.routing_domain()) {
|
||||||
if !opi.signed_node_info().node_info().can_tunnel() {
|
if !opi
|
||||||
|
.signed_node_info()
|
||||||
|
.node_info()
|
||||||
|
.has_capability(CAP_TUNNEL)
|
||||||
|
{
|
||||||
return Ok(NetworkResult::service_unavailable(
|
return Ok(NetworkResult::service_unavailable(
|
||||||
"tunnel is not available",
|
"tunnel is not available",
|
||||||
));
|
));
|
||||||
|
@ -71,7 +71,8 @@ impl RPCProcessor {
|
|||||||
let routing_table = self.routing_table();
|
let routing_table = self.routing_table();
|
||||||
{
|
{
|
||||||
if let Some(opi) = routing_table.get_own_peer_info(detail.routing_domain) {
|
if let Some(opi) = routing_table.get_own_peer_info(detail.routing_domain) {
|
||||||
if !opi.signed_node_info().node_info().can_validate_dial_info() {
|
let ni = opi.signed_node_info().node_info();
|
||||||
|
if !ni.has_capability(CAP_VALIDATE_DIAL_INFO) || !ni.is_signal_capable() {
|
||||||
return Ok(NetworkResult::service_unavailable(
|
return Ok(NetworkResult::service_unavailable(
|
||||||
"validate dial info is not available",
|
"validate dial info is not available",
|
||||||
));
|
));
|
||||||
@ -116,7 +117,9 @@ impl RPCProcessor {
|
|||||||
let entry = v.unwrap();
|
let entry = v.unwrap();
|
||||||
entry.with(rti, move |_rti, e| {
|
entry.with(rti, move |_rti, e| {
|
||||||
e.node_info(routing_domain)
|
e.node_info(routing_domain)
|
||||||
.map(|ni| ni.can_validate_dial_info())
|
.map(|ni| {
|
||||||
|
ni.has_capability(CAP_VALIDATE_DIAL_INFO) && ni.is_signal_capable()
|
||||||
|
})
|
||||||
.unwrap_or(false)
|
.unwrap_or(false)
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
@ -10,7 +10,7 @@ impl RPCProcessor {
|
|||||||
let routing_table = self.routing_table();
|
let routing_table = self.routing_table();
|
||||||
{
|
{
|
||||||
if let Some(opi) = routing_table.get_own_peer_info(msg.header.routing_domain()) {
|
if let Some(opi) = routing_table.get_own_peer_info(msg.header.routing_domain()) {
|
||||||
if !opi.signed_node_info().node_info().can_dht() {
|
if !opi.signed_node_info().node_info().has_capability(CAP_DHT) {
|
||||||
return Ok(NetworkResult::service_unavailable("dht is not available"));
|
return Ok(NetworkResult::service_unavailable("dht is not available"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,7 @@ impl RPCProcessor {
|
|||||||
let routing_table = self.routing_table();
|
let routing_table = self.routing_table();
|
||||||
{
|
{
|
||||||
if let Some(opi) = routing_table.get_own_peer_info(msg.header.routing_domain()) {
|
if let Some(opi) = routing_table.get_own_peer_info(msg.header.routing_domain()) {
|
||||||
if !opi.signed_node_info().node_info().can_dht() {
|
if !opi.signed_node_info().node_info().has_capability(CAP_DHT) {
|
||||||
return Ok(NetworkResult::service_unavailable("dht is not available"));
|
return Ok(NetworkResult::service_unavailable("dht is not available"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -54,13 +54,13 @@ class CryptoKind(StrEnum):
|
|||||||
|
|
||||||
class Capability(StrEnum):
|
class Capability(StrEnum):
|
||||||
CAP_WILL_ROUTE = "ROUT"
|
CAP_WILL_ROUTE = "ROUT"
|
||||||
CAP_WILL_TUNNEL = "TUNL"
|
CAP_TUNNEL = "TUNL"
|
||||||
CAP_WILL_SIGNAL = "SGNL"
|
CAP_WILL_SIGNAL = "SGNL"
|
||||||
CAP_WILL_RELAY = "RLAY"
|
CAP_WILL_RELAY = "RLAY"
|
||||||
CAP_WILL_VALIDATE_DIAL_INFO = "DIAL"
|
CAP_WILL_VALIDATE_DIAL_INFO = "DIAL"
|
||||||
CAP_WILL_DHT = "DHTV"
|
CAP_WILL_DHT = "DHTV"
|
||||||
CAP_WILL_APPMESSAGE = "APPM"
|
CAP_WILL_APPMESSAGE = "APPM"
|
||||||
CAP_WILL_BLOCKSTORE = "BLOC"
|
CAP_BLOCKSTORE = "BLOC"
|
||||||
|
|
||||||
|
|
||||||
class Stability(StrEnum):
|
class Stability(StrEnum):
|
||||||
|
Loading…
Reference in New Issue
Block a user