checkpoint
This commit is contained in:
parent
064e6c018c
commit
1ba0cdb9cf
@ -230,8 +230,8 @@ struct NodeInfo @0xe125d847e3f9f419 {
|
||||
networkClass @0 :NetworkClass; # network class of this node
|
||||
outboundProtocols @1 :ProtocolTypeSet; # protocols that can go outbound
|
||||
addressTypes @2 :AddressTypeSet; # address types supported
|
||||
envelopeSupport @3 :List(UInt8); # supported envelope versions
|
||||
cryptoSupport @4 :List(CryptoKind); # maximum protocol version for rpc
|
||||
envelopeSupport @3 :List(UInt8); # supported rpc envelope/receipt versions
|
||||
cryptoSupport @4 :List(CryptoKind); # cryptography systems supported
|
||||
dialInfoDetailList @5 :List(DialInfoDetail); # inbound dial info details for this node
|
||||
}
|
||||
|
||||
|
45
veilid-core/src/crypto/dh_cache.rs
Normal file
45
veilid-core/src/crypto/dh_cache.rs
Normal file
@ -0,0 +1,45 @@
|
||||
use super::*;
|
||||
use crate::*;
|
||||
|
||||
// Diffie-Hellman key exchange cache
|
||||
#[derive(Serialize, Deserialize, PartialEq, Eq, Hash)]
|
||||
pub struct DHCacheKey {
|
||||
pub key: PublicKey,
|
||||
pub secret: SecretKey,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct DHCacheValue {
|
||||
pub shared_secret: SharedSecret,
|
||||
}
|
||||
|
||||
pub type DHCache = LruCache<DHCacheKey, DHCacheValue>;
|
||||
pub const DH_CACHE_SIZE: usize = 4096;
|
||||
|
||||
pub fn cache_to_bytes(cache: &DHCache) -> Vec<u8> {
|
||||
let cnt: usize = cache.len();
|
||||
let mut out: Vec<u8> = Vec::with_capacity(cnt * (32 + 32 + 32));
|
||||
for e in cache.iter() {
|
||||
out.extend(&e.0.key.bytes);
|
||||
out.extend(&e.0.secret.bytes);
|
||||
out.extend(&e.1.shared_secret.bytes);
|
||||
}
|
||||
let mut rev: Vec<u8> = Vec::with_capacity(out.len());
|
||||
for d in out.chunks(32 + 32 + 32).rev() {
|
||||
rev.extend(d);
|
||||
}
|
||||
rev
|
||||
}
|
||||
|
||||
pub fn bytes_to_cache(bytes: &[u8], cache: &mut DHCache) {
|
||||
for d in bytes.chunks(32 + 32 + 32) {
|
||||
let k = DHCacheKey {
|
||||
key: PublicKey::new(d[0..32].try_into().expect("asdf")),
|
||||
secret: SecretKey::new(d[32..64].try_into().expect("asdf")),
|
||||
};
|
||||
let v = DHCacheValue {
|
||||
shared_secret: SharedSecret::new(d[64..96].try_into().expect("asdf")),
|
||||
};
|
||||
cache.insert(k, v);
|
||||
}
|
||||
}
|
@ -37,7 +37,7 @@ pub const ENVELOPE_MAGIC: &[u8; 3] = b"VLD";
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Default)]
|
||||
pub struct Envelope {
|
||||
version: u8,
|
||||
version: EnvelopeVersion,
|
||||
crypto_kind: CryptoKind,
|
||||
timestamp: Timestamp,
|
||||
nonce: Nonce,
|
||||
@ -47,15 +47,14 @@ pub struct Envelope {
|
||||
|
||||
impl Envelope {
|
||||
pub fn new(
|
||||
version: u8,
|
||||
version: EnvelopeVersion,
|
||||
crypto_kind: CryptoKind,
|
||||
timestamp: Timestamp,
|
||||
nonce: Nonce,
|
||||
sender_id: PublicKey,
|
||||
recipient_id: PublicKey,
|
||||
) -> Self {
|
||||
assert!(version >= MIN_ENVELOPE_VERSION);
|
||||
assert!(version <= MAX_ENVELOPE_VERSION);
|
||||
assert!(VALID_ENVELOPE_VERSIONS.contains(&version));
|
||||
assert!(VALID_CRYPTO_KINDS.contains(&crypto_kind));
|
||||
Self {
|
||||
version,
|
||||
@ -84,7 +83,7 @@ impl Envelope {
|
||||
|
||||
// Check envelope version
|
||||
let version = data[0x03];
|
||||
if version > MAX_ENVELOPE_VERSION || version < MIN_ENVELOPE_VERSION {
|
||||
if !VALID_ENVELOPE_VERSIONS.contains(&version) {
|
||||
apibail_parse_error!("unsupported envelope version", version);
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
mod byte_array_types;
|
||||
mod dh_cache;
|
||||
mod envelope;
|
||||
mod receipt;
|
||||
mod types;
|
||||
@ -10,6 +11,7 @@ pub mod vld0;
|
||||
|
||||
pub use byte_array_types::*;
|
||||
pub use crypto_system::*;
|
||||
pub use dh_cache::*;
|
||||
pub use envelope::*;
|
||||
pub use receipt::*;
|
||||
pub use types::*;
|
||||
@ -22,52 +24,20 @@ use hashlink::linked_hash_map::Entry;
|
||||
use hashlink::LruCache;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
// Handle to a particular cryptosystem
|
||||
pub type CryptoSystemVersion = Arc<dyn CryptoSystem + Send + Sync>;
|
||||
|
||||
/// Crypto kinds in order of preference, best cryptosystem is the first one, worst is the last one
|
||||
pub const VALID_CRYPTO_KINDS: [CryptoKind; 1] = [CRYPTO_KIND_VLD0];
|
||||
|
||||
pub const MIN_ENVELOPE_VERSION: u8 = 0u8;
|
||||
pub const MAX_ENVELOPE_VERSION: u8 = 0u8;
|
||||
|
||||
const DH_CACHE_SIZE: usize = 4096;
|
||||
|
||||
#[derive(Serialize, Deserialize, PartialEq, Eq, Hash)]
|
||||
struct DHCacheKey {
|
||||
key: PublicKey,
|
||||
secret: SecretKey,
|
||||
pub fn best_crypto_kind() -> CryptoKind {
|
||||
VALID_CRYPTO_KINDS[0]
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
struct DHCacheValue {
|
||||
shared_secret: SharedSecret,
|
||||
}
|
||||
type DHCache = LruCache<DHCacheKey, DHCacheValue>;
|
||||
|
||||
fn cache_to_bytes(cache: &DHCache) -> Vec<u8> {
|
||||
let cnt: usize = cache.len();
|
||||
let mut out: Vec<u8> = Vec::with_capacity(cnt * (32 + 32 + 32));
|
||||
for e in cache.iter() {
|
||||
out.extend(&e.0.key.bytes);
|
||||
out.extend(&e.0.secret.bytes);
|
||||
out.extend(&e.1.shared_secret.bytes);
|
||||
}
|
||||
let mut rev: Vec<u8> = Vec::with_capacity(out.len());
|
||||
for d in out.chunks(32 + 32 + 32).rev() {
|
||||
rev.extend(d);
|
||||
}
|
||||
rev
|
||||
}
|
||||
|
||||
fn bytes_to_cache(bytes: &[u8], cache: &mut DHCache) {
|
||||
for d in bytes.chunks(32 + 32 + 32) {
|
||||
let k = DHCacheKey {
|
||||
key: PublicKey::new(d[0..32].try_into().expect("asdf")),
|
||||
secret: SecretKey::new(d[32..64].try_into().expect("asdf")),
|
||||
};
|
||||
let v = DHCacheValue {
|
||||
shared_secret: SharedSecret::new(d[64..96].try_into().expect("asdf")),
|
||||
};
|
||||
cache.insert(k, v);
|
||||
}
|
||||
/// Envelope versions in order of preference, best envelope version is the first one, worst is the last one
|
||||
pub type EnvelopeVersion = u8;
|
||||
pub const VALID_ENVELOPE_VERSIONS: [EnvelopeVersion; 1] = [0u8];
|
||||
pub fn best_envelope_version() -> EnvelopeVersion {
|
||||
VALID_ENVELOPE_VERSIONS[0]
|
||||
}
|
||||
|
||||
struct CryptoInner {
|
||||
@ -227,6 +197,11 @@ impl Crypto {
|
||||
}
|
||||
}
|
||||
|
||||
// Factory method to get the best crypto version
|
||||
pub fn best(&self) -> CryptoSystemVersion {
|
||||
self.get(best_crypto_kind()).unwrap()
|
||||
}
|
||||
|
||||
/// Signature set verification
|
||||
/// Returns the set of signature cryptokinds that validate and are supported
|
||||
/// If any cryptokinds are supported and do not validate, the whole operation
|
||||
|
@ -50,8 +50,7 @@ impl Receipt {
|
||||
sender_id: PublicKey,
|
||||
extra_data: D,
|
||||
) -> Result<Self, VeilidAPIError> {
|
||||
assert!(version >= MIN_ENVELOPE_VERSION);
|
||||
assert!(version <= MAX_ENVELOPE_VERSION);
|
||||
assert!(VALID_ENVELOPE_VERSIONS.contains(&version));
|
||||
assert!(VALID_CRYPTO_KINDS.contains(&crypto_kind));
|
||||
|
||||
if extra_data.as_ref().len() > MAX_EXTRA_DATA_SIZE {
|
||||
@ -85,7 +84,7 @@ impl Receipt {
|
||||
|
||||
// Check version
|
||||
let version = data[0x03];
|
||||
if version > MAX_ENVELOPE_VERSION || version < MIN_ENVELOPE_VERSION {
|
||||
if !VALID_ENVELOPE_VERSIONS.contains(&version) {
|
||||
apibail_parse_error!("unsupported envelope version", version);
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,9 @@
|
||||
use super::*;
|
||||
|
||||
pub async fn test_envelope_round_trip(vcrypto: CryptoSystemVersion) {
|
||||
pub async fn test_envelope_round_trip(
|
||||
envelope_version: EnvelopeVersion,
|
||||
vcrypto: CryptoSystemVersion,
|
||||
) {
|
||||
info!("--- test envelope round trip ---");
|
||||
|
||||
// Create envelope
|
||||
@ -9,7 +12,7 @@ pub async fn test_envelope_round_trip(vcrypto: CryptoSystemVersion) {
|
||||
let (sender_id, sender_secret) = vcrypto.generate_keypair();
|
||||
let (recipient_id, recipient_secret) = vcrypto.generate_keypair();
|
||||
let envelope = Envelope::new(
|
||||
MAX_ENVELOPE_VERSION,
|
||||
envelope_version,
|
||||
vcrypto.kind(),
|
||||
ts,
|
||||
nonce,
|
||||
@ -53,7 +56,10 @@ pub async fn test_envelope_round_trip(vcrypto: CryptoSystemVersion) {
|
||||
);
|
||||
}
|
||||
|
||||
pub async fn test_receipt_round_trip(vcrypto: CryptoSystemVersion) {
|
||||
pub async fn test_receipt_round_trip(
|
||||
envelope_version: EnvelopeVersion,
|
||||
vcrypto: CryptoSystemVersion,
|
||||
) {
|
||||
info!("--- test receipt round trip ---");
|
||||
// Create arbitrary body
|
||||
let body = b"This is an arbitrary body";
|
||||
@ -61,7 +67,7 @@ pub async fn test_receipt_round_trip(vcrypto: CryptoSystemVersion) {
|
||||
// Create receipt
|
||||
let nonce = vcrypto.random_nonce();
|
||||
let (sender_id, sender_secret) = vcrypto.generate_keypair();
|
||||
let receipt = Receipt::try_new(MAX_ENVELOPE_VERSION, vcrypto.kind(), nonce, sender_id, body)
|
||||
let receipt = Receipt::try_new(envelope_version, vcrypto.kind(), nonce, sender_id, body)
|
||||
.expect("should not fail");
|
||||
|
||||
// Serialize to bytes
|
||||
@ -87,11 +93,13 @@ pub async fn test_all() {
|
||||
let crypto = api.crypto().unwrap();
|
||||
|
||||
// Test versions
|
||||
for v in VALID_CRYPTO_KINDS {
|
||||
let vcrypto = crypto.get(v).unwrap();
|
||||
for ev in VALID_ENVELOPE_VERSIONS {
|
||||
for v in VALID_CRYPTO_KINDS {
|
||||
let vcrypto = crypto.get(v).unwrap();
|
||||
|
||||
test_envelope_round_trip(vcrypto.clone()).await;
|
||||
test_receipt_round_trip(vcrypto).await;
|
||||
test_envelope_round_trip(ev, vcrypto.clone()).await;
|
||||
test_receipt_round_trip(ev, vcrypto).await;
|
||||
}
|
||||
}
|
||||
|
||||
crypto_tests_shutdown(api.clone()).await;
|
||||
|
@ -10,6 +10,23 @@ use rkyv::{Archive as RkyvArchive, Deserialize as RkyvDeserialize, Serialize as
|
||||
/// Cryptography version fourcc code
|
||||
pub type CryptoKind = FourCC;
|
||||
|
||||
/// Sort best crypto kinds first
|
||||
pub fn compare_crypto_kind(a: CryptoKind, b: CryptoKind) -> cmp::Ordering {
|
||||
let a_idx = VALID_CRYPTO_KINDS.iter().position(|&k| k == a);
|
||||
let b_idx = VALID_CRYPTO_KINDS.iter().position(|&k| k == b);
|
||||
if let Some(a_idx) = a_idx {
|
||||
if let Some(b_idx) = b_idx {
|
||||
a_idx.cmp(&b_idx)
|
||||
} else {
|
||||
cmp::Ordering::Less
|
||||
}
|
||||
} else if let Some(b_idx) = b_idx {
|
||||
cmp::Ordering::Greater
|
||||
} else {
|
||||
a.cmp(&b)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(
|
||||
Clone,
|
||||
Copy,
|
||||
@ -43,8 +60,6 @@ impl KeyPair {
|
||||
Debug,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
PartialOrd,
|
||||
Ord,
|
||||
PartialEq,
|
||||
Eq,
|
||||
Hash,
|
||||
@ -63,6 +78,21 @@ impl TypedKey {
|
||||
Self { kind, key }
|
||||
}
|
||||
}
|
||||
impl PartialOrd for TypedKey {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
}
|
||||
|
||||
impl Ord for TypedKey {
|
||||
fn cmp(&self, other: &Self) -> cmp::Ordering {
|
||||
let x = compare_crypto_kind(self.kind, other.kind);
|
||||
if x != cmp::Ordering::Equal {
|
||||
return x;
|
||||
}
|
||||
self.key.cmp(&other.key)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for TypedKey {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
|
||||
@ -84,13 +114,121 @@ impl FromStr for TypedKey {
|
||||
|
||||
#[derive(
|
||||
Clone,
|
||||
Copy,
|
||||
Debug,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
PartialOrd,
|
||||
Ord,
|
||||
PartialEq,
|
||||
Eq,
|
||||
Hash,
|
||||
RkyvArchive,
|
||||
RkyvSerialize,
|
||||
RkyvDeserialize,
|
||||
)]
|
||||
#[archive_attr(repr(C), derive(CheckBytes))]
|
||||
pub struct TypedKeySet {
|
||||
items: Vec<TypedKey>,
|
||||
}
|
||||
|
||||
impl TypedKeySet {
|
||||
pub fn new() -> Self {
|
||||
Self { items: Vec::new() }
|
||||
}
|
||||
pub fn with_capacity(cap: usize) -> Self {
|
||||
Self {
|
||||
items: Vec::with_capacity(cap),
|
||||
}
|
||||
}
|
||||
pub fn get(&self, kind: CryptoKind) -> Option<TypedKey> {
|
||||
self.items.iter().find(|x| x.kind == kind).copied()
|
||||
}
|
||||
pub fn add(&mut self, typed_key: TypedKey) {
|
||||
for x in &mut self.items {
|
||||
if x.kind == typed_key.kind {
|
||||
*x = typed_key;
|
||||
return;
|
||||
}
|
||||
}
|
||||
self.items.push(typed_key);
|
||||
self.items.sort()
|
||||
}
|
||||
pub fn remove(&self, kind: CryptoKind) {
|
||||
if let Some(idx) = self.items.iter().position(|x| x.kind == kind) {
|
||||
self.items.remove(idx);
|
||||
}
|
||||
}
|
||||
pub fn best(&self) -> Option<TypedKey> {
|
||||
self.items.first().copied()
|
||||
}
|
||||
pub fn len(&self) -> usize {
|
||||
self.items.len()
|
||||
}
|
||||
pub fn iter(&self) -> core::slice::Iter<'_, TypedKey> {
|
||||
self.items.iter()
|
||||
}
|
||||
pub fn contains(&self, typed_key: &TypedKey) -> bool {
|
||||
self.items.contains(typed_key)
|
||||
}
|
||||
pub fn contains_any(&self, typed_keys: &[TypedKey]) -> bool {
|
||||
for typed_key in typed_keys {
|
||||
if self.items.contains(typed_key) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
impl core::ops::Deref for TypedKeySet {
|
||||
type Target = [TypedKey];
|
||||
|
||||
#[inline]
|
||||
fn deref(&self) -> &[TypedKey] {
|
||||
&self.items
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for TypedKeySet {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
|
||||
write!(f, "[")?;
|
||||
let mut first = true;
|
||||
for x in &self.items {
|
||||
if !first {
|
||||
write!(f, ",")?;
|
||||
first = false;
|
||||
}
|
||||
write!(f, "{}", x)?;
|
||||
}
|
||||
write!(f, "]")
|
||||
}
|
||||
}
|
||||
impl FromStr for TypedKeySet {
|
||||
type Err = VeilidAPIError;
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
let mut items = Vec::new();
|
||||
if s.len() < 2 {
|
||||
apibail_parse_error!("invalid length", s);
|
||||
}
|
||||
if &s[0..1] != "[" || &s[(s.len() - 1)..] != "]" {
|
||||
apibail_parse_error!("invalid format", s);
|
||||
}
|
||||
for x in s[1..s.len() - 1].split(",") {
|
||||
let tk = TypedKey::from_str(x.trim())?;
|
||||
items.push(tk);
|
||||
}
|
||||
|
||||
Ok(Self { items })
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(
|
||||
Clone,
|
||||
Copy,
|
||||
Debug,
|
||||
PartialEq,
|
||||
Eq,
|
||||
Hash,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
RkyvArchive,
|
||||
@ -110,6 +248,26 @@ impl TypedKeyPair {
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd for TypedKeyPair {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
}
|
||||
|
||||
impl Ord for TypedKeyPair {
|
||||
fn cmp(&self, other: &Self) -> cmp::Ordering {
|
||||
let x = compare_crypto_kind(self.kind, other.kind);
|
||||
if x != cmp::Ordering::Equal {
|
||||
return x;
|
||||
}
|
||||
let x = self.key.cmp(&other.key);
|
||||
if x != cmp::Ordering::Equal {
|
||||
return x;
|
||||
}
|
||||
self.secret.cmp(&other.secret)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for TypedKeyPair {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
|
||||
write!(
|
||||
@ -142,8 +300,6 @@ impl FromStr for TypedKeyPair {
|
||||
Clone,
|
||||
Copy,
|
||||
Debug,
|
||||
PartialOrd,
|
||||
Ord,
|
||||
PartialEq,
|
||||
Eq,
|
||||
Hash,
|
||||
@ -176,6 +332,22 @@ impl TypedSignature {
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd for TypedSignature {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
}
|
||||
|
||||
impl Ord for TypedSignature {
|
||||
fn cmp(&self, other: &Self) -> cmp::Ordering {
|
||||
let x = compare_crypto_kind(self.kind, other.kind);
|
||||
if x != cmp::Ordering::Equal {
|
||||
return x;
|
||||
}
|
||||
self.signature.cmp(&other.signature)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for TypedSignature {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
|
||||
write!(f, "{}:{}", self.kind, self.signature.encode())
|
||||
@ -198,8 +370,6 @@ impl FromStr for TypedSignature {
|
||||
Clone,
|
||||
Copy,
|
||||
Debug,
|
||||
PartialOrd,
|
||||
Ord,
|
||||
PartialEq,
|
||||
Eq,
|
||||
Hash,
|
||||
@ -232,6 +402,26 @@ impl TypedKeySignature {
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd for TypedKeySignature {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
}
|
||||
|
||||
impl Ord for TypedKeySignature {
|
||||
fn cmp(&self, other: &Self) -> cmp::Ordering {
|
||||
let x = compare_crypto_kind(self.kind, other.kind);
|
||||
if x != cmp::Ordering::Equal {
|
||||
return x;
|
||||
}
|
||||
let x = self.key.cmp(&other.key);
|
||||
if x != cmp::Ordering::Equal {
|
||||
return x;
|
||||
}
|
||||
self.signature.cmp(&other.signature)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for TypedKeySignature {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
|
||||
write!(
|
||||
|
@ -134,7 +134,7 @@ struct PublicAddressCheckCacheKey(ProtocolType, AddressType);
|
||||
// The mutable state of the network manager
|
||||
struct NetworkManagerInner {
|
||||
stats: NetworkManagerStats,
|
||||
client_whitelist: LruCache<PublicKey, ClientWhitelistEntry>,
|
||||
client_whitelist: LruCache<TypedKey, ClientWhitelistEntry>,
|
||||
public_address_check_cache:
|
||||
BTreeMap<PublicAddressCheckCacheKey, LruCache<IpAddr, SocketAddress>>,
|
||||
public_address_inconsistencies_table:
|
||||
@ -396,7 +396,7 @@ impl NetworkManager {
|
||||
debug!("finished network manager shutdown");
|
||||
}
|
||||
|
||||
pub fn update_client_whitelist(&self, client: PublicKey) {
|
||||
pub fn update_client_whitelist(&self, client: TypedKey) {
|
||||
let mut inner = self.inner.lock();
|
||||
match inner.client_whitelist.entry(client) {
|
||||
hashlink::lru_cache::Entry::Occupied(mut entry) => {
|
||||
@ -411,7 +411,7 @@ impl NetworkManager {
|
||||
}
|
||||
|
||||
#[instrument(level = "trace", skip(self), ret)]
|
||||
pub fn check_client_whitelist(&self, client: PublicKey) -> bool {
|
||||
pub fn check_client_whitelist(&self, client: TypedKey) -> bool {
|
||||
let mut inner = self.inner.lock();
|
||||
|
||||
match inner.client_whitelist.entry(client) {
|
||||
@ -519,12 +519,15 @@ impl NetworkManager {
|
||||
let routing_table = self.routing_table();
|
||||
|
||||
// Generate receipt and serialized form to return
|
||||
xxx add 'preferred_kind' and propagate envelope changes so we can make recent_peers work with cryptokind
|
||||
let vcrypto = self.crypto().best();
|
||||
|
||||
let nonce = Crypto::get_random_nonce();
|
||||
let receipt = Receipt::try_new(0, nonce, routing_table.node_id(), extra_data)?;
|
||||
let nonce = vcrypto.random_nonce();
|
||||
let node_id = routing_table.node_id(vcrypto.kind());
|
||||
let node_id_secret = routing_table.node_id_secret(vcrypto.kind());
|
||||
|
||||
let receipt = Receipt::try_new(MAX_ENVELOPE_VERSION, node_id.kind, nonce, node_id.key, extra_data)?;
|
||||
let out = receipt
|
||||
.to_signed_data(&routing_table.node_id_secret())
|
||||
.to_signed_data(self.crypto(), &node_id_secret)
|
||||
.wrap_err("failed to generate signed receipt")?;
|
||||
|
||||
// Record the receipt for later
|
||||
@ -545,10 +548,15 @@ xxx add 'preferred_kind' and propagate envelope changes so we can make recent_pe
|
||||
let routing_table = self.routing_table();
|
||||
|
||||
// Generate receipt and serialized form to return
|
||||
let nonce = Crypto::get_random_nonce();
|
||||
let receipt = Receipt::try_new(0, nonce, routing_table.node_id(), extra_data)?;
|
||||
let vcrypto = self.crypto().best();
|
||||
|
||||
let nonce = vcrypto.random_nonce();
|
||||
let node_id = routing_table.node_id(vcrypto.kind());
|
||||
let node_id_secret = routing_table.node_id_secret(vcrypto.kind());
|
||||
|
||||
let receipt = Receipt::try_new(MAX_ENVELOPE_VERSION, node_id.kind, nonce, node_id.key, extra_data)?;
|
||||
let out = receipt
|
||||
.to_signed_data(&routing_table.node_id_secret())
|
||||
.to_signed_data(self.crypto(), &node_id_secret)
|
||||
.wrap_err("failed to generate signed receipt")?;
|
||||
|
||||
// Record the receipt for later
|
||||
@ -568,7 +576,7 @@ xxx add 'preferred_kind' and propagate envelope changes so we can make recent_pe
|
||||
) -> NetworkResult<()> {
|
||||
let receipt_manager = self.receipt_manager();
|
||||
|
||||
let receipt = match Receipt::from_signed_data(receipt_data.as_ref()) {
|
||||
let receipt = match Receipt::from_signed_data(self.crypto(), receipt_data.as_ref()) {
|
||||
Err(e) => {
|
||||
return NetworkResult::invalid_message(e.to_string());
|
||||
}
|
||||
@ -589,7 +597,7 @@ xxx add 'preferred_kind' and propagate envelope changes so we can make recent_pe
|
||||
) -> NetworkResult<()> {
|
||||
let receipt_manager = self.receipt_manager();
|
||||
|
||||
let receipt = match Receipt::from_signed_data(receipt_data.as_ref()) {
|
||||
let receipt = match Receipt::from_signed_data(self.crypto(), receipt_data.as_ref()) {
|
||||
Err(e) => {
|
||||
return NetworkResult::invalid_message(e.to_string());
|
||||
}
|
||||
@ -609,7 +617,7 @@ xxx add 'preferred_kind' and propagate envelope changes so we can make recent_pe
|
||||
) -> NetworkResult<()> {
|
||||
let receipt_manager = self.receipt_manager();
|
||||
|
||||
let receipt = match Receipt::from_signed_data(receipt_data.as_ref()) {
|
||||
let receipt = match Receipt::from_signed_data(self.crypto(), receipt_data.as_ref()) {
|
||||
Err(e) => {
|
||||
return NetworkResult::invalid_message(e.to_string());
|
||||
}
|
||||
@ -626,11 +634,11 @@ xxx add 'preferred_kind' and propagate envelope changes so we can make recent_pe
|
||||
pub async fn handle_private_receipt<R: AsRef<[u8]>>(
|
||||
&self,
|
||||
receipt_data: R,
|
||||
private_route: PublicKey,
|
||||
private_route: TypedKey,
|
||||
) -> NetworkResult<()> {
|
||||
let receipt_manager = self.receipt_manager();
|
||||
|
||||
let receipt = match Receipt::from_signed_data(receipt_data.as_ref()) {
|
||||
let receipt = match Receipt::from_signed_data(self.crypto(), receipt_data.as_ref()) {
|
||||
Err(e) => {
|
||||
return NetworkResult::invalid_message(e.to_string());
|
||||
}
|
||||
@ -653,8 +661,7 @@ xxx add 'preferred_kind' and propagate envelope changes so we can make recent_pe
|
||||
// Add the peer info to our routing table
|
||||
let peer_nr = match routing_table.register_node_with_peer_info(
|
||||
RoutingDomain::PublicInternet,
|
||||
peer_info.node_id.key,
|
||||
peer_info.signed_node_info,
|
||||
peer_info,
|
||||
false,
|
||||
) {
|
||||
None => {
|
||||
@ -677,8 +684,7 @@ xxx add 'preferred_kind' and propagate envelope changes so we can make recent_pe
|
||||
// Add the peer info to our routing table
|
||||
let mut peer_nr = match routing_table.register_node_with_peer_info(
|
||||
RoutingDomain::PublicInternet,
|
||||
peer_info.node_id.key,
|
||||
peer_info.signed_node_info,
|
||||
peer_info,
|
||||
false,
|
||||
) {
|
||||
None => {
|
||||
@ -733,21 +739,25 @@ xxx add 'preferred_kind' and propagate envelope changes so we can make recent_pe
|
||||
#[instrument(level = "trace", skip(self, body), err)]
|
||||
fn build_envelope<B: AsRef<[u8]>>(
|
||||
&self,
|
||||
dest_node_id: PublicKey,
|
||||
dest_node_id: TypedKey,
|
||||
version: u8,
|
||||
body: B,
|
||||
) -> EyreResult<Vec<u8>> {
|
||||
// DH to get encryption key
|
||||
let routing_table = self.routing_table();
|
||||
let node_id = routing_table.node_id();
|
||||
let node_id_secret = routing_table.node_id_secret();
|
||||
let Some(vcrypto) = self.crypto().get(dest_node_id.kind) else {
|
||||
bail!("should not have a destination with incompatible crypto here");
|
||||
};
|
||||
|
||||
let node_id = routing_table.node_id(vcrypto.kind());
|
||||
let node_id_secret = routing_table.node_id_secret(vcrypto.kind());
|
||||
|
||||
// Get timestamp, nonce
|
||||
let ts = get_aligned_timestamp();
|
||||
let nonce = Crypto::get_random_nonce();
|
||||
let nonce = vcrypto.random_nonce();
|
||||
|
||||
// Encode envelope
|
||||
let envelope = Envelope::new(version, ts, nonce, node_id, dest_node_id);
|
||||
let envelope = Envelope::new(version, node_id.kind, ts, nonce, node_id.key, dest_node_id.key);
|
||||
envelope
|
||||
.to_encrypted_data(self.crypto(), body.as_ref(), &node_id_secret)
|
||||
.wrap_err("envelope failed to encode")
|
||||
@ -755,19 +765,22 @@ xxx add 'preferred_kind' and propagate envelope changes so we can make recent_pe
|
||||
|
||||
/// Called by the RPC handler when we want to issue an RPC request or response
|
||||
/// node_ref is the direct destination to which the envelope will be sent
|
||||
/// If 'node_id' is specified, it can be different than node_ref.node_id()
|
||||
/// If 'envelope_node_id' is specified, it can be different than the node_ref being sent to
|
||||
/// which will cause the envelope to be relayed
|
||||
#[instrument(level = "trace", skip(self, body), ret, err)]
|
||||
pub async fn send_envelope<B: AsRef<[u8]>>(
|
||||
&self,
|
||||
node_ref: NodeRef,
|
||||
envelope_node_id: Option<PublicKey>,
|
||||
envelope_node_id: Option<TypedKey>,
|
||||
body: B,
|
||||
) -> EyreResult<NetworkResult<SendDataKind>> {
|
||||
let via_node_id = node_ref.node_id();
|
||||
let envelope_node_id = envelope_node_id.unwrap_or(via_node_id);
|
||||
let via_node_ids = node_ref.node_ids();
|
||||
let Some(best_via_node_id) = via_node_ids.best() else {
|
||||
bail!("should have a best node id");
|
||||
};
|
||||
let envelope_node_id = envelope_node_id.unwrap_or(best_via_node_id);
|
||||
|
||||
if envelope_node_id != via_node_id {
|
||||
if !via_node_ids.contains(&envelope_node_id) {
|
||||
log_net!(
|
||||
"sending envelope to {:?} via {:?}",
|
||||
envelope_node_id,
|
||||
@ -776,11 +789,13 @@ xxx add 'preferred_kind' and propagate envelope changes so we can make recent_pe
|
||||
} else {
|
||||
log_net!("sending envelope to {:?}", node_ref);
|
||||
}
|
||||
// Get node's min/max version and see if we can send to it
|
||||
|
||||
// Get node's min/max envelope version and see if we can send to it
|
||||
// and if so, get the max version we can use
|
||||
let version = if let Some(min_max_version) = node_ref.min_max_version() {
|
||||
node_ref.envelope_support()
|
||||
let envelope_version = if let Some(min_max_version) = {
|
||||
#[allow(clippy::absurd_extreme_comparisons)]
|
||||
if min_max_version.min > MAX_CRYPTO_VERSION || min_max_version.max < MIN_CRYPTO_VERSION
|
||||
if min_max_version.min > MAX_ENVELOPE_VERSION || min_max_version.max < MIN_ENVELOPE_VERSION
|
||||
{
|
||||
bail!(
|
||||
"can't talk to this node {} because version is unsupported: ({},{})",
|
||||
@ -1374,7 +1389,7 @@ xxx add 'preferred_kind' and propagate envelope changes so we can make recent_pe
|
||||
// If the recipient id is not our node id, then it needs relaying
|
||||
let sender_id = TypedKey::new(envelope.get_crypto_kind(), envelope.get_sender_id());
|
||||
let recipient_id = TypedKey::new(envelope.get_crypto_kind(), envelope.get_recipient_id());
|
||||
if recipient_id != routing_table.node_id() {
|
||||
if !routing_table.matches_own_node_id(&[recipient_id]) {
|
||||
// See if the source node is allowed to resolve nodes
|
||||
// This is a costly operation, so only outbound-relay permitted
|
||||
// nodes are allowed to do this, for example PWA users
|
||||
@ -1419,7 +1434,7 @@ xxx add 'preferred_kind' and propagate envelope changes so we can make recent_pe
|
||||
}
|
||||
|
||||
// DH to get decryption key (cached)
|
||||
let node_id_secret = routing_table.node_id_secret();
|
||||
let node_id_secret = routing_table.node_id_secret(envelope.get_crypto_kind());
|
||||
|
||||
// Decrypt the envelope body
|
||||
let body = match envelope
|
||||
@ -1445,7 +1460,7 @@ xxx add 'preferred_kind' and propagate envelope changes so we can make recent_pe
|
||||
}
|
||||
Some(v) => v,
|
||||
};
|
||||
source_noderef.set_min_max_version(envelope.get_min_max_version());
|
||||
source_noderef.add_envelope_version(envelope.get_version());
|
||||
|
||||
// xxx: deal with spoofing and flooding here?
|
||||
|
||||
@ -1539,7 +1554,7 @@ xxx add 'preferred_kind' and propagate envelope changes so we can make recent_pe
|
||||
if let Some(nr) = routing_table.lookup_node_ref(k) {
|
||||
let peer_stats = nr.peer_stats();
|
||||
let peer = PeerTableData {
|
||||
node_ids: k,
|
||||
node_ids: nr.node_ids(),
|
||||
peer_address: v.last_connection.remote(),
|
||||
peer_stats,
|
||||
};
|
||||
|
@ -112,7 +112,7 @@ impl DiscoveryContext {
|
||||
&self,
|
||||
protocol_type: ProtocolType,
|
||||
address_type: AddressType,
|
||||
ignore_node: Option<PublicKey>,
|
||||
ignore_node_ids: Option<TypedKeySet>,
|
||||
) -> Option<(SocketAddress, NodeRef)> {
|
||||
let node_count = {
|
||||
let config = self.routing_table.network_manager().config();
|
||||
@ -121,7 +121,7 @@ impl DiscoveryContext {
|
||||
};
|
||||
|
||||
// Build an filter that matches our protocol and address type
|
||||
// and excludes relays so we can get an accurate external address
|
||||
// and excludes relayed nodes so we can get an accurate external address
|
||||
let dial_info_filter = DialInfoFilter::all()
|
||||
.with_protocol_type(protocol_type)
|
||||
.with_address_type(address_type);
|
||||
@ -130,11 +130,11 @@ impl DiscoveryContext {
|
||||
dial_info_filter.clone(),
|
||||
);
|
||||
let disallow_relays_filter = Box::new(
|
||||
move |rti: &RoutingTableInner, _k: PublicKey, v: Option<Arc<BucketEntry>>| {
|
||||
move |rti: &RoutingTableInner, v: Option<Arc<BucketEntry>>| {
|
||||
let v = v.unwrap();
|
||||
v.with(rti, |_rti, e| {
|
||||
if let Some(n) = e.signed_node_info(RoutingDomain::PublicInternet) {
|
||||
n.relay_id().is_none()
|
||||
n.relay_ids().is_empty()
|
||||
} else {
|
||||
false
|
||||
}
|
||||
@ -158,8 +158,8 @@ impl DiscoveryContext {
|
||||
|
||||
// For each peer, if it's not our ignore-node, ask them for our public address, filtering on desired dial info
|
||||
for mut peer in peers {
|
||||
if let Some(ignore_node) = ignore_node {
|
||||
if peer.node_id() == ignore_node {
|
||||
if let Some(ignore_node_ids) = &ignore_node_ids {
|
||||
if peer.node_ids().contains_any(ignore_node_ids) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@ -478,12 +478,12 @@ impl DiscoveryContext {
|
||||
|
||||
// Get our external address from some fast node, that is not node 1, call it node 2
|
||||
let (external_2_address, node_2) = match self
|
||||
.discover_external_address(protocol_type, address_type, Some(node_1.node_id()))
|
||||
.discover_external_address(protocol_type, address_type, Some(node_1.node_ids()))
|
||||
.await
|
||||
{
|
||||
None => {
|
||||
// If we can't get an external address, allow retry
|
||||
log_net!(debug "failed to discover external address 2 for {:?}:{:?}, skipping node {:?}", protocol_type, address_type, node_1.node_id());
|
||||
log_net!(debug "failed to discover external address 2 for {:?}:{:?}, skipping node {:?}", protocol_type, address_type, node_1);
|
||||
return Ok(false);
|
||||
}
|
||||
Some(v) => v,
|
||||
|
@ -11,7 +11,7 @@ pub enum ReceiptEvent {
|
||||
ReturnedOutOfBand,
|
||||
ReturnedInBand { inbound_noderef: NodeRef },
|
||||
ReturnedSafety,
|
||||
ReturnedPrivate { private_route: PublicKey },
|
||||
ReturnedPrivate { private_route: TypedKey },
|
||||
Expired,
|
||||
Cancelled,
|
||||
}
|
||||
@ -21,7 +21,7 @@ pub enum ReceiptReturned {
|
||||
OutOfBand,
|
||||
InBand { inbound_noderef: NodeRef },
|
||||
Safety,
|
||||
Private { private_route: PublicKey },
|
||||
Private { private_route: TypedKey },
|
||||
}
|
||||
|
||||
pub trait ReceiptCallback: Send + 'static {
|
||||
|
@ -2,18 +2,28 @@ use super::*;
|
||||
use core::sync::atomic::Ordering;
|
||||
use rkyv::{Archive as RkyvArchive, Deserialize as RkyvDeserialize, Serialize as RkyvSerialize};
|
||||
|
||||
/// Routing Table Bucket
|
||||
/// Stores map of public keys to entries, which may be in multiple routing tables per crypto kind
|
||||
/// Keeps entries at a particular 'dht distance' from this cryptokind's node id
|
||||
/// Helps to keep managed lists at particular distances so we can evict nodes by priority
|
||||
/// where the priority comes from liveness and age of the entry (older is better)
|
||||
pub struct Bucket {
|
||||
/// handle to the routing table
|
||||
routing_table: RoutingTable,
|
||||
entries: BTreeMap<PublicKey, Arc<BucketEntry>>,
|
||||
newest_entry: Option<PublicKey>,
|
||||
/// Map of keys to entries for this bucket
|
||||
entries: BTreeMap<TypedKey, Arc<BucketEntry>>,
|
||||
/// The most recent entry in this bucket
|
||||
newest_entry: Option<TypedKey>,
|
||||
/// The crypto kind in use for the public keys in this bucket
|
||||
kind: CryptoKind,
|
||||
}
|
||||
pub(super) type EntriesIter<'a> =
|
||||
alloc::collections::btree_map::Iter<'a, PublicKey, Arc<BucketEntry>>;
|
||||
alloc::collections::btree_map::Iter<'a, TypedKey, Arc<BucketEntry>>;
|
||||
|
||||
#[derive(Debug, RkyvArchive, RkyvSerialize, RkyvDeserialize)]
|
||||
#[archive_attr(repr(C), derive(CheckBytes))]
|
||||
struct SerializedBucketEntryData {
|
||||
key: PublicKey,
|
||||
key: TypedKey,
|
||||
value: u32, // index into serialized entries list
|
||||
}
|
||||
|
||||
@ -21,7 +31,7 @@ struct SerializedBucketEntryData {
|
||||
#[archive_attr(repr(C), derive(CheckBytes))]
|
||||
struct SerializedBucketData {
|
||||
entries: Vec<SerializedBucketEntryData>,
|
||||
newest_entry: Option<PublicKey>,
|
||||
newest_entry: Option<TypedKey>,
|
||||
}
|
||||
|
||||
fn state_ordering(state: BucketEntryState) -> usize {
|
||||
@ -33,11 +43,12 @@ fn state_ordering(state: BucketEntryState) -> usize {
|
||||
}
|
||||
|
||||
impl Bucket {
|
||||
pub fn new(routing_table: RoutingTable) -> Self {
|
||||
pub fn new(routing_table: RoutingTable, kind: CryptoKind) -> Self {
|
||||
Self {
|
||||
routing_table,
|
||||
entries: BTreeMap::new(),
|
||||
newest_entry: None,
|
||||
kind,
|
||||
}
|
||||
}
|
||||
|
||||
@ -83,22 +94,43 @@ impl Bucket {
|
||||
Ok(out)
|
||||
}
|
||||
|
||||
pub(super) fn add_entry(&mut self, node_id: PublicKey) -> NodeRef {
|
||||
log_rtab!("Node added: {}", node_id.encode());
|
||||
/// Create a new entry with a node_id of this crypto kind and return it
|
||||
pub(super) fn add_entry(&mut self, node_id: TypedKey) -> NodeRef {
|
||||
assert_eq!(node_id.kind, self.kind);
|
||||
|
||||
log_rtab!("Node added: {}", node_id);
|
||||
|
||||
// Add new entry
|
||||
self.entries.insert(node_id, Arc::new(BucketEntry::new()));
|
||||
let entry = Arc::new(BucketEntry::new());
|
||||
entry.with_mut_inner(|e| e.add_node_id(node_id));
|
||||
self.entries.insert(node_id.key, entry.clone());
|
||||
|
||||
// This is now the newest bucket entry
|
||||
self.newest_entry = Some(node_id);
|
||||
self.newest_entry = Some(node_id.key);
|
||||
|
||||
// Get a node ref to return
|
||||
let entry = self.entries.get(&node_id).unwrap().clone();
|
||||
NodeRef::new(self.routing_table.clone(), node_id, entry, None)
|
||||
// Get a node ref to return since this is new
|
||||
NodeRef::new(self.routing_table.clone(), entry, None)
|
||||
}
|
||||
|
||||
pub(super) fn remove_entry(&mut self, node_id: &PublicKey) {
|
||||
log_rtab!("Node removed: {}", node_id);
|
||||
/// Add an existing entry with a new node_id for this crypto kind
|
||||
pub(super) fn add_existing_entry(&mut self, node_id: TypedKey, entry: Arc<BucketEntry>) {
|
||||
assert_eq!(node_id.kind, self.kind);
|
||||
|
||||
log_rtab!("Existing node added: {}", node_id);
|
||||
|
||||
// Add existing entry
|
||||
entry.with_mut_inner(|e| e.add_node_id(node_id));
|
||||
self.entries.insert(node_id.key, entry);
|
||||
|
||||
// This is now the newest bucket entry
|
||||
self.newest_entry = Some(node_id.key);
|
||||
|
||||
// No need to return a noderef here because the noderef will already exist in the caller
|
||||
}
|
||||
|
||||
/// Remove an entry with a node_id for this crypto kind from the bucket
|
||||
fn remove_entry(&mut self, node_id: &TypedKey) {
|
||||
log_rtab!("Node removed: {}:{}", self.kind, node_id);
|
||||
|
||||
// Remove the entry
|
||||
self.entries.remove(node_id);
|
||||
@ -106,7 +138,7 @@ impl Bucket {
|
||||
// newest_entry is updated by kick_bucket()
|
||||
}
|
||||
|
||||
pub(super) fn entry(&self, key: &PublicKey) -> Option<Arc<BucketEntry>> {
|
||||
pub(super) fn entry(&self, key: &TypedKey) -> Option<Arc<BucketEntry>> {
|
||||
self.entries.get(key).cloned()
|
||||
}
|
||||
|
||||
@ -114,7 +146,7 @@ impl Bucket {
|
||||
self.entries.iter()
|
||||
}
|
||||
|
||||
pub(super) fn kick(&mut self, bucket_depth: usize) -> Option<BTreeSet<PublicKey>> {
|
||||
pub(super) fn kick(&mut self, bucket_depth: usize) -> Option<BTreeSet<TypedKey>> {
|
||||
// Get number of entries to attempt to purge from bucket
|
||||
let bucket_len = self.entries.len();
|
||||
|
||||
@ -124,11 +156,11 @@ impl Bucket {
|
||||
}
|
||||
|
||||
// Try to purge the newest entries that overflow the bucket
|
||||
let mut dead_node_ids: BTreeSet<PublicKey> = BTreeSet::new();
|
||||
let mut dead_node_ids: BTreeSet<TypedKey> = BTreeSet::new();
|
||||
let mut extra_entries = bucket_len - bucket_depth;
|
||||
|
||||
// Get the sorted list of entries by their kick order
|
||||
let mut sorted_entries: Vec<(PublicKey, Arc<BucketEntry>)> = self
|
||||
let mut sorted_entries: Vec<(TypedKey, Arc<BucketEntry>)> = self
|
||||
.entries
|
||||
.iter()
|
||||
.map(|(k, v)| (k.clone(), v.clone()))
|
||||
|
@ -68,22 +68,12 @@ pub struct BucketEntryLocalNetwork {
|
||||
node_status: Option<LocalNetworkNodeStatus>,
|
||||
}
|
||||
|
||||
/// A range of cryptography versions supported by this entry
|
||||
#[derive(Copy, Clone, Debug, RkyvArchive, RkyvSerialize, RkyvDeserialize)]
|
||||
#[archive_attr(repr(C), derive(CheckBytes))]
|
||||
pub struct VersionRange {
|
||||
/// The minimum cryptography version supported by this entry
|
||||
pub min: u8,
|
||||
/// The maximum cryptography version supported by this entry
|
||||
pub max: u8,
|
||||
}
|
||||
|
||||
/// The data associated with each bucket entry
|
||||
#[derive(Debug, RkyvArchive, RkyvSerialize, RkyvDeserialize)]
|
||||
#[archive_attr(repr(C), derive(CheckBytes))]
|
||||
pub struct BucketEntryInner {
|
||||
/// The node ids matching this bucket entry, with the cryptography versions supported by this node as the 'kind' field
|
||||
node_ids: Vec<TypedKey>,
|
||||
node_ids: TypedKeySet,
|
||||
/// The set of envelope versions supported by the node inclusive of the requirements of any relay the node may be using
|
||||
envelope_support: Vec<u8>,
|
||||
/// If this node has updated it's SignedNodeInfo since our network
|
||||
@ -133,9 +123,12 @@ impl BucketEntryInner {
|
||||
}
|
||||
|
||||
// Node ids
|
||||
pub fn node_ids(&self) -> Vec<TypedKey> {
|
||||
pub fn node_ids(&self) -> TypedKeySet {
|
||||
self.node_ids.clone()
|
||||
}
|
||||
pub fn add_node_id(&mut self, node_id: TypedKey) {
|
||||
self.node_ids.add(node_id);
|
||||
}
|
||||
|
||||
// Less is faster
|
||||
pub fn cmp_fastest(e1: &Self, e2: &Self) -> std::cmp::Ordering {
|
||||
@ -453,12 +446,23 @@ impl BucketEntryInner {
|
||||
out
|
||||
}
|
||||
|
||||
pub fn set_min_max_version(&mut self, min_max_version: VersionRange) {
|
||||
self.min_max_version = Some(min_max_version);
|
||||
pub fn add_envelope_version(&mut self, envelope_version: u8) {
|
||||
if self.envelope_support.contains(&envelope_version) {
|
||||
return;
|
||||
}
|
||||
self.envelope_support.push(envelope_version);
|
||||
self.envelope_support.dedup();
|
||||
self.envelope_support.sort();
|
||||
}
|
||||
|
||||
pub fn min_max_version(&self) -> Option<VersionRange> {
|
||||
self.min_max_version
|
||||
pub fn set_envelope_support(&mut self, envelope_support: Vec<u8>) {
|
||||
envelope_support.dedup();
|
||||
envelope_support.sort();
|
||||
self.envelope_support = envelope_support;
|
||||
}
|
||||
|
||||
pub fn envelope_support(&self) -> Vec<u8> {
|
||||
self.envelope_support.clone()
|
||||
}
|
||||
|
||||
pub fn state(&self, cur_ts: Timestamp) -> BucketEntryState {
|
||||
@ -757,7 +761,8 @@ impl BucketEntry {
|
||||
Self {
|
||||
ref_count: AtomicU32::new(0),
|
||||
inner: RwLock::new(BucketEntryInner {
|
||||
min_max_version: None,
|
||||
node_ids: TypedKeySet::new(),
|
||||
envelope_support: Vec::new(),
|
||||
updated_since_last_network_change: false,
|
||||
last_connections: BTreeMap::new(),
|
||||
local_network: BucketEntryLocalNetwork {
|
||||
|
@ -113,7 +113,7 @@ impl RoutingTable {
|
||||
let mut cnt = 0;
|
||||
out += &format!("Entries: {}\n", inner.bucket_entry_count);
|
||||
while b < blen {
|
||||
let filtered_entries: Vec<(&PublicKey, &Arc<BucketEntry>)> = inner.buckets[b]
|
||||
let filtered_entries: Vec<(&TypedKey, &Arc<BucketEntry>)> = inner.buckets[b]
|
||||
.entries()
|
||||
.filter(|e| {
|
||||
let state = e.1.with(inner, |_rti, e| e.state(cur_ts));
|
||||
@ -149,7 +149,7 @@ impl RoutingTable {
|
||||
out
|
||||
}
|
||||
|
||||
pub(crate) fn debug_info_entry(&self, node_id: PublicKey) -> String {
|
||||
pub(crate) fn debug_info_entry(&self, node_id: TypedKey) -> String {
|
||||
let mut out = String::new();
|
||||
out += &format!("Entry {:?}:\n", node_id);
|
||||
if let Some(nr) = self.lookup_node_ref(node_id) {
|
||||
|
@ -49,7 +49,7 @@ pub struct LowLevelPortInfo {
|
||||
pub protocol_to_port: ProtocolToPortMapping,
|
||||
}
|
||||
pub type RoutingTableEntryFilter<'t> =
|
||||
Box<dyn FnMut(&RoutingTableInner, PublicKey, Option<Arc<BucketEntry>>) -> bool + Send + 't>;
|
||||
Box<dyn FnMut(&RoutingTableInner, Option<Arc<BucketEntry>>) -> bool + Send + 't>;
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq)]
|
||||
pub struct RoutingTableHealth {
|
||||
@ -110,7 +110,7 @@ impl RoutingTableUnlockedInner {
|
||||
f(&*self.config.get())
|
||||
}
|
||||
|
||||
pub fn node_id(&self, kind: CryptoKind) -> PublicKey {
|
||||
pub fn node_id(&self, kind: CryptoKind) -> TypedKey {
|
||||
self.node_id_keypairs.get(&kind).unwrap().key
|
||||
}
|
||||
|
||||
@ -192,6 +192,27 @@ impl RoutingTable {
|
||||
this
|
||||
}
|
||||
|
||||
/////////////////////////////////////
|
||||
/// Unlocked passthrough
|
||||
pub fn network_manager(&self) -> NetworkManager {
|
||||
self.unlocked_inner.network_manager()
|
||||
}
|
||||
pub fn crypto(&self) -> Crypto {
|
||||
self.unlocked_inner.crypto()
|
||||
}
|
||||
pub fn rpc_processor(&self) -> RPCProcessor {
|
||||
self.unlocked_inner.rpc_processor()
|
||||
}
|
||||
pub fn node_id(&self, kind: CryptoKind) -> TypedKey {
|
||||
self.unlocked_inner.node_id(kind)
|
||||
}
|
||||
pub fn node_id_secret(&self, kind: CryptoKind) -> SecretKey {
|
||||
self.unlocked_inner.node_id_secret(kind)
|
||||
}
|
||||
pub fn matches_own_node_id(&self, node_ids: &[TypedKey]) -> bool {
|
||||
self.unlocked_inner.matches_own_node_id(node_ids)
|
||||
}
|
||||
|
||||
/////////////////////////////////////
|
||||
/// Initialization
|
||||
|
||||
@ -556,14 +577,14 @@ impl RoutingTable {
|
||||
}
|
||||
|
||||
/// Resolve an existing routing table entry and return a reference to it
|
||||
pub fn lookup_node_ref(&self, node_id: PublicKey) -> Option<NodeRef> {
|
||||
pub fn lookup_node_ref(&self, node_id: TypedKey) -> Option<NodeRef> {
|
||||
self.inner.read().lookup_node_ref(self.clone(), node_id)
|
||||
}
|
||||
|
||||
/// Resolve an existing routing table entry and return a filtered reference to it
|
||||
pub fn lookup_and_filter_noderef(
|
||||
&self,
|
||||
node_id: PublicKey,
|
||||
node_id: TypedKey,
|
||||
routing_domain_set: RoutingDomainSet,
|
||||
dial_info_filter: DialInfoFilter,
|
||||
) -> Option<NodeRef> {
|
||||
@ -596,7 +617,7 @@ impl RoutingTable {
|
||||
/// and add the last peer address we have for it, since that's pretty common
|
||||
pub fn register_node_with_existing_connection(
|
||||
&self,
|
||||
node_id: PublicKey,
|
||||
node_id: TypedKey,
|
||||
descriptor: ConnectionDescriptor,
|
||||
timestamp: Timestamp,
|
||||
) -> Option<NodeRef> {
|
||||
@ -615,7 +636,7 @@ impl RoutingTable {
|
||||
self.inner.read().get_routing_table_health()
|
||||
}
|
||||
|
||||
pub fn get_recent_peers(&self) -> Vec<(PublicKey, RecentPeersEntry)> {
|
||||
pub fn get_recent_peers(&self) -> Vec<(TypedKey, RecentPeersEntry)> {
|
||||
let mut recent_peers = Vec::new();
|
||||
let mut dead_peers = Vec::new();
|
||||
let mut out = Vec::new();
|
||||
@ -654,7 +675,7 @@ impl RoutingTable {
|
||||
out
|
||||
}
|
||||
|
||||
pub fn touch_recent_peer(&self, node_id: PublicKey, last_connection: ConnectionDescriptor) {
|
||||
pub fn touch_recent_peer(&self, node_id: TypedKey, last_connection: ConnectionDescriptor) {
|
||||
self.inner
|
||||
.write()
|
||||
.touch_recent_peer(node_id, last_connection)
|
||||
@ -703,7 +724,7 @@ impl RoutingTable {
|
||||
dial_info_filter: DialInfoFilter,
|
||||
) -> RoutingTableEntryFilter<'a> {
|
||||
// does it have matching public dial info?
|
||||
Box::new(move |rti, _k, e| {
|
||||
Box::new(move |rti, e| {
|
||||
if let Some(e) = e {
|
||||
e.with(rti, |_rti, e| {
|
||||
if let Some(ni) = e.node_info(routing_domain) {
|
||||
@ -731,7 +752,7 @@ impl RoutingTable {
|
||||
dial_info: DialInfo,
|
||||
) -> RoutingTableEntryFilter<'a> {
|
||||
// does the node's outbound capabilities match the dialinfo?
|
||||
Box::new(move |rti, _k, e| {
|
||||
Box::new(move |rti, e| {
|
||||
if let Some(e) = e {
|
||||
e.with(rti, |_rti, e| {
|
||||
if let Some(ni) = e.node_info(routing_domain) {
|
||||
@ -774,8 +795,8 @@ impl RoutingTable {
|
||||
let mut nodes_proto_v6 = vec![0usize, 0usize, 0usize, 0usize];
|
||||
|
||||
let filter = Box::new(
|
||||
move |rti: &RoutingTableInner, _k: PublicKey, v: Option<Arc<BucketEntry>>| {
|
||||
let entry = v.unwrap();
|
||||
move |rti: &RoutingTableInner, entry: Option<Arc<BucketEntry>>| {
|
||||
let entry = entry.unwrap();
|
||||
entry.with(rti, |_rti, e| {
|
||||
// skip nodes on our local network here
|
||||
if e.has_node_info(RoutingDomain::LocalNetwork.into()) {
|
||||
@ -821,8 +842,8 @@ impl RoutingTable {
|
||||
self.find_fastest_nodes(
|
||||
protocol_types_len * 2 * max_per_type,
|
||||
filters,
|
||||
|_rti, k: PublicKey, v: Option<Arc<BucketEntry>>| {
|
||||
NodeRef::new(self.clone(), k, v.unwrap().clone(), None)
|
||||
|_rti, entry: Option<Arc<BucketEntry>>| {
|
||||
NodeRef::new(self.clone(), entry.unwrap().clone(), None)
|
||||
},
|
||||
)
|
||||
}
|
||||
@ -838,10 +859,10 @@ impl RoutingTable {
|
||||
where
|
||||
C: for<'a, 'b> FnMut(
|
||||
&'a RoutingTableInner,
|
||||
&'b (PublicKey, Option<Arc<BucketEntry>>),
|
||||
&'b (PublicKey, Option<Arc<BucketEntry>>),
|
||||
&'b Option<Arc<BucketEntry>>,
|
||||
&'b Option<Arc<BucketEntry>>,
|
||||
) -> core::cmp::Ordering,
|
||||
T: for<'r> FnMut(&'r RoutingTableInner, PublicKey, Option<Arc<BucketEntry>>) -> O + Send,
|
||||
T: for<'r> FnMut(&'r RoutingTableInner, Option<Arc<BucketEntry>>) -> O + Send,
|
||||
{
|
||||
self.inner
|
||||
.read()
|
||||
@ -855,7 +876,7 @@ impl RoutingTable {
|
||||
transform: T,
|
||||
) -> Vec<O>
|
||||
where
|
||||
T: for<'r> FnMut(&'r RoutingTableInner, PublicKey, Option<Arc<BucketEntry>>) -> O + Send,
|
||||
T: for<'r> FnMut(&'r RoutingTableInner, Option<Arc<BucketEntry>>) -> O + Send,
|
||||
{
|
||||
self.inner
|
||||
.read()
|
||||
@ -864,12 +885,12 @@ impl RoutingTable {
|
||||
|
||||
pub fn find_closest_nodes<'a, T, O>(
|
||||
&self,
|
||||
node_id: PublicKey,
|
||||
node_id: TypedKey,
|
||||
filters: VecDeque<RoutingTableEntryFilter>,
|
||||
transform: T,
|
||||
) -> Vec<O>
|
||||
where
|
||||
T: for<'r> FnMut(&'r RoutingTableInner, PublicKey, Option<Arc<BucketEntry>>) -> O + Send,
|
||||
T: for<'r> FnMut(&'r RoutingTableInner, Option<Arc<BucketEntry>>) -> O + Send,
|
||||
{
|
||||
self.inner
|
||||
.read()
|
||||
@ -895,7 +916,7 @@ impl RoutingTable {
|
||||
pub async fn find_node(
|
||||
&self,
|
||||
node_ref: NodeRef,
|
||||
node_id: PublicKey,
|
||||
node_id: TypedKey,
|
||||
) -> EyreResult<NetworkResult<Vec<NodeRef>>> {
|
||||
let rpc_processor = self.rpc_processor();
|
||||
|
||||
@ -1021,7 +1042,7 @@ impl RoutingTable {
|
||||
// Go through all entries and find fastest entry that matches filter function
|
||||
let inner = self.inner.read();
|
||||
let inner = &*inner;
|
||||
let mut best_inbound_relay: Option<(PublicKey, Arc<BucketEntry>)> = None;
|
||||
let mut best_inbound_relay: Option<(TypedKey, Arc<BucketEntry>)> = None;
|
||||
|
||||
// Iterate all known nodes for candidates
|
||||
inner.with_entries(cur_ts, BucketEntryState::Unreliable, |rti, k, v| {
|
||||
@ -1054,6 +1075,6 @@ impl RoutingTable {
|
||||
Option::<()>::None
|
||||
});
|
||||
// Return the best inbound relay noderef
|
||||
best_inbound_relay.map(|(k, e)| NodeRef::new(self.clone(), k, e, None))
|
||||
best_inbound_relay.map(|(k, e)| NodeRef::new(self.clone(), e, None))
|
||||
}
|
||||
}
|
||||
|
@ -98,7 +98,7 @@ pub trait NodeRefBase: Sized {
|
||||
fn routing_table(&self) -> RoutingTable {
|
||||
self.common().routing_table.clone()
|
||||
}
|
||||
fn node_ids(&self) -> Vec<TypedKey> {
|
||||
fn node_ids(&self) -> TypedKeySet {
|
||||
self.operate(|_rti, e| e.node_ids())
|
||||
}
|
||||
fn has_updated_since_last_network_change(&self) -> bool {
|
||||
@ -112,11 +112,14 @@ pub trait NodeRefBase: Sized {
|
||||
e.update_node_status(node_status);
|
||||
});
|
||||
}
|
||||
fn min_max_version(&self) -> Option<VersionRange> {
|
||||
self.operate(|_rti, e| e.min_max_version())
|
||||
fn envelope_support(&self) -> Vec<u8> {
|
||||
self.operate(|_rti, e| e.envelope_support())
|
||||
}
|
||||
fn set_min_max_version(&self, min_max_version: VersionRange) {
|
||||
self.operate_mut(|_rti, e| e.set_min_max_version(min_max_version))
|
||||
fn add_envelope_version(&self, envelope_version: u8) {
|
||||
self.operate_mut(|_rti, e| e.add_envelope_version(envelope_version))
|
||||
}
|
||||
fn set_envelope_support(&self, envelope_support: Vec<u8>) {
|
||||
self.operate_mut(|_rti, e| e.set_envelope_support(envelope_support))
|
||||
}
|
||||
fn state(&self, cur_ts: Timestamp) -> BucketEntryState {
|
||||
self.operate(|_rti, e| e.state(cur_ts))
|
||||
|
@ -117,14 +117,14 @@ impl PrivateRoute {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn first_hop_node_id(&self) -> Option<PublicKey> {
|
||||
pub fn first_hop_node_id(&self) -> Option<TypedKey> {
|
||||
let PrivateRouteHops::FirstHop(pr_first_hop) = &self.hops else {
|
||||
return None;
|
||||
};
|
||||
|
||||
// Get the safety route to use from the spec
|
||||
Some(match &pr_first_hop.node {
|
||||
RouteNode::NodeId(n) => n.key,
|
||||
RouteNode::NodeId(n) => n,
|
||||
RouteNode::PeerInfo(p) => p.node_id.key,
|
||||
})
|
||||
}
|
||||
@ -162,13 +162,13 @@ pub enum SafetyRouteHops {
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct SafetyRoute {
|
||||
pub public_key: PublicKey,
|
||||
pub public_key: TypedKey,
|
||||
pub hop_count: u8,
|
||||
pub hops: SafetyRouteHops,
|
||||
}
|
||||
|
||||
impl SafetyRoute {
|
||||
pub fn new_stub(public_key: PublicKey, private_route: PrivateRoute) -> Self {
|
||||
pub fn new_stub(public_key: TypedKey, private_route: PrivateRoute) -> Self {
|
||||
// First hop should have already been popped off for stubbed safety routes since
|
||||
// we are sending directly to the first hop
|
||||
assert!(matches!(private_route.hops, PrivateRouteHops::Data(_)));
|
||||
|
@ -10,13 +10,13 @@ pub enum ContactMethod {
|
||||
/// Contact the node directly
|
||||
Direct(DialInfo),
|
||||
/// Request via signal the node connect back directly (relay, target)
|
||||
SignalReverse(PublicKey, PublicKey),
|
||||
SignalReverse(TypedKey, TypedKey),
|
||||
/// Request via signal the node negotiate a hole punch (relay, target_node)
|
||||
SignalHolePunch(PublicKey, PublicKey),
|
||||
SignalHolePunch(TypedKey, TypedKey),
|
||||
/// Must use an inbound relay to reach the node
|
||||
InboundRelay(PublicKey),
|
||||
InboundRelay(TypedKey),
|
||||
/// Must use outbound relay to reach the node
|
||||
OutboundRelay(PublicKey),
|
||||
OutboundRelay(TypedKey),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
@ -28,7 +28,7 @@ pub struct RoutingTableInner {
|
||||
/// Statistics about the total bandwidth to/from this node
|
||||
pub(super) self_transfer_stats: TransferStatsDownUp,
|
||||
/// Peers we have recently communicated with
|
||||
pub(super) recent_peers: LruCache<PublicKey, RecentPeersEntry>,
|
||||
pub(super) recent_peers: LruCache<TypedKey, RecentPeersEntry>,
|
||||
/// Storage for private/safety RouteSpecs
|
||||
pub(super) route_spec_store: Option<RouteSpecStore>,
|
||||
}
|
||||
@ -416,7 +416,7 @@ impl RoutingTableInner {
|
||||
|
||||
pub fn with_entries<
|
||||
T,
|
||||
F: FnMut(&RoutingTableInner, PublicKey, Arc<BucketEntry>) -> Option<T>,
|
||||
F: FnMut(&RoutingTableInner, TypedKey, Arc<BucketEntry>) -> Option<T>,
|
||||
>(
|
||||
&self,
|
||||
cur_ts: Timestamp,
|
||||
@ -442,7 +442,7 @@ impl RoutingTableInner {
|
||||
|
||||
pub fn with_entries_mut<
|
||||
T,
|
||||
F: FnMut(&mut RoutingTableInner, PublicKey, Arc<BucketEntry>) -> Option<T>,
|
||||
F: FnMut(&mut RoutingTableInner, TypedKey, Arc<BucketEntry>) -> Option<T>,
|
||||
>(
|
||||
&mut self,
|
||||
cur_ts: Timestamp,
|
||||
@ -537,66 +537,87 @@ impl RoutingTableInner {
|
||||
return None;
|
||||
}
|
||||
|
||||
// Look up all bucket entries and make sure we only have zero or one
|
||||
// If we have more than one, pick the one with the best cryptokind to add node ids to
|
||||
let mut best_entry: Option<Arc<BucketEntry>> = None;
|
||||
for node_id in node_ids {
|
||||
if let Some((kind, idx)) = self.unlocked_inner.find_bucket_index(*node_id) {
|
||||
let bucket = &self.buckets[&kind][idx];
|
||||
if let Some(entry) = bucket.entry(&node_id.key) {
|
||||
// Best entry is the first one in sorted order that exists from the node id list
|
||||
// Everything else that matches will be overwritten in the bucket and the
|
||||
// existing noderefs will eventually unref and drop the old unindexed bucketentry
|
||||
// We do this instead of merging for now. We could 'kill' entries and have node_refs
|
||||
// rewrite themselves to point to the merged entry upon dereference. The use case for this
|
||||
// may not be worth the effort.
|
||||
best_entry = Some(entry);
|
||||
break;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// If the entry does exist already, update it
|
||||
if let Some(best_entry) = best_entry {
|
||||
let nr = best_entry.map(|e| NodeRef::new(outer_self.clone(), best_entry, None));
|
||||
|
||||
// Update the entry with all of the node ids
|
||||
nr.update_node_ids(node_ids);
|
||||
|
||||
// Update the entry with the update func
|
||||
nr.operate_mut(|rti, e| update_func(rti, e));
|
||||
|
||||
return Some(nr);
|
||||
}
|
||||
|
||||
// Find a bucket for the first node id crypto kind we can handle
|
||||
let (node_id, kind, idx) = node_ids.iter().find_map(|x| {
|
||||
self.unlocked_inner
|
||||
.find_bucket_index(*x)
|
||||
.map(|v| (*x, v.0, v.1))
|
||||
})?;
|
||||
|
||||
// Look up existing entry
|
||||
let idx = node_ids
|
||||
.iter()
|
||||
.find_map(|x| self.unlocked_inner.find_bucket_index(x));
|
||||
let noderef = {
|
||||
let bucket = &self.buckets[idx];
|
||||
let entry = bucket.entry(&node_id);
|
||||
entry.map(|e| NodeRef::new(outer_self.clone(), node_id, e, None))
|
||||
let bucket = &self.buckets[&kind][idx];
|
||||
let entry = bucket.entry(&node_id.key);
|
||||
entry.map(|e| NodeRef::new(outer_self.clone(), e, None))
|
||||
};
|
||||
|
||||
// If one doesn't exist, insert into bucket, possibly evicting a bucket member
|
||||
let noderef = match noderef {
|
||||
None => {
|
||||
// Make new entry
|
||||
self.bucket_entry_count += 1;
|
||||
let cnt = self.bucket_entry_count;
|
||||
let bucket = &mut self.buckets[idx];
|
||||
let nr = bucket.add_entry(node_id);
|
||||
self.bucket_entry_count += 1;
|
||||
let cnt = self.bucket_entry_count;
|
||||
let bucket = &mut self.buckets[idx];
|
||||
let nr = bucket.add_entry(node_id);
|
||||
|
||||
// Update the entry
|
||||
let entry = bucket.entry(&node_id).unwrap();
|
||||
entry.with_mut(self, update_func);
|
||||
// Update the entry
|
||||
let entry = bucket.entry(&node_id).unwrap();
|
||||
entry.with_mut(self, update_func);
|
||||
|
||||
// Kick the bucket
|
||||
self.unlocked_inner.kick_queue.lock().insert(idx);
|
||||
log_rtab!(debug "Routing table now has {} nodes, {} live", cnt, self.get_entry_count(RoutingDomainSet::all(), BucketEntryState::Unreliable));
|
||||
// Kick the bucket
|
||||
self.unlocked_inner.kick_queue.lock().insert(idx);
|
||||
log_rtab!(debug "Routing table now has {} nodes, {} live", cnt, self.get_entry_count(RoutingDomainSet::all(), BucketEntryState::Unreliable));
|
||||
|
||||
nr
|
||||
}
|
||||
Some(nr) => {
|
||||
// Update the entry
|
||||
let bucket = &mut self.buckets[idx];
|
||||
let entry = bucket.entry(&node_id).unwrap();
|
||||
entry.with_mut(self, update_func);
|
||||
|
||||
nr
|
||||
}
|
||||
};
|
||||
|
||||
Some(noderef)
|
||||
Some(NodeRef::new(outer_self.clone(), e, None))
|
||||
}
|
||||
|
||||
/// Resolve an existing routing table entry and return a reference to it
|
||||
pub fn lookup_node_ref(&self, outer_self: RoutingTable, node_id: PublicKey) -> Option<NodeRef> {
|
||||
if node_id == self.unlocked_inner.node_id {
|
||||
pub fn lookup_node_ref(&self, outer_self: RoutingTable, node_id: TypedKey) -> Option<NodeRef> {
|
||||
if self.unlocked_inner.matches_own_node_id(&[node_id]) {
|
||||
log_rtab!(error "can't look up own node id in routing table");
|
||||
return None;
|
||||
}
|
||||
let idx = self.unlocked_inner.find_bucket_index(node_id);
|
||||
let bucket = &self.buckets[idx];
|
||||
let (kind, idx) = self.unlocked_inner.find_bucket_index(node_id)?;
|
||||
let bucket = &self.buckets[&kind][idx];
|
||||
bucket
|
||||
.entry(&node_id)
|
||||
.map(|e| NodeRef::new(outer_self, node_id, e, None))
|
||||
.entry(&node_id.key)
|
||||
.map(|e| NodeRef::new(outer_self, e, None))
|
||||
}
|
||||
|
||||
/// Resolve an existing routing table entry and return a filtered reference to it
|
||||
pub fn lookup_and_filter_noderef(
|
||||
&self,
|
||||
outer_self: RoutingTable,
|
||||
node_id: PublicKey,
|
||||
node_id: TypedKey,
|
||||
routing_domain_set: RoutingDomainSet,
|
||||
dial_info_filter: DialInfoFilter,
|
||||
) -> Option<NodeRef> {
|
||||
@ -611,7 +632,7 @@ impl RoutingTableInner {
|
||||
}
|
||||
|
||||
/// Resolve an existing routing table entry and call a function on its entry without using a noderef
|
||||
pub fn with_node_entry<F, R>(&self, node_id: PublicKey, f: F) -> Option<R>
|
||||
pub fn with_node_entry<F, R>(&self, node_id: TypedKey, f: F) -> Option<R>
|
||||
where
|
||||
F: FnOnce(Arc<BucketEntry>) -> R,
|
||||
{
|
||||
@ -682,11 +703,11 @@ impl RoutingTableInner {
|
||||
pub fn register_node_with_existing_connection(
|
||||
&mut self,
|
||||
outer_self: RoutingTable,
|
||||
node_id: PublicKey,
|
||||
node_id: TypedKey,
|
||||
descriptor: ConnectionDescriptor,
|
||||
timestamp: Timestamp,
|
||||
) -> Option<NodeRef> {
|
||||
let out = self.create_node_ref(outer_self, node_id, |_rti, e| {
|
||||
let out = self.create_node_ref(outer_self, &[node_id], |_rti, e| {
|
||||
// this node is live because it literally just connected to us
|
||||
e.touch_last_seen(timestamp);
|
||||
});
|
||||
@ -743,7 +764,7 @@ impl RoutingTableInner {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn touch_recent_peer(&mut self, node_id: PublicKey, last_connection: ConnectionDescriptor) {
|
||||
pub fn touch_recent_peer(&mut self, node_id: TypedKey, last_connection: ConnectionDescriptor) {
|
||||
self.recent_peers
|
||||
.insert(node_id, RecentPeersEntry { last_connection });
|
||||
}
|
||||
@ -758,29 +779,27 @@ impl RoutingTableInner {
|
||||
node_count: usize,
|
||||
mut filters: VecDeque<RoutingTableEntryFilter>,
|
||||
) -> Vec<NodeRef> {
|
||||
let public_node_filter = Box::new(
|
||||
|rti: &RoutingTableInner, _k: PublicKey, v: Option<Arc<BucketEntry>>| {
|
||||
let entry = v.unwrap();
|
||||
entry.with(rti, |_rti, e| {
|
||||
// skip nodes on local network
|
||||
if e.node_info(RoutingDomain::LocalNetwork).is_some() {
|
||||
return false;
|
||||
}
|
||||
// skip nodes not on public internet
|
||||
if e.node_info(RoutingDomain::PublicInternet).is_none() {
|
||||
return false;
|
||||
}
|
||||
true
|
||||
})
|
||||
},
|
||||
) as RoutingTableEntryFilter;
|
||||
let public_node_filter = Box::new(|rti: &RoutingTableInner, v: Option<Arc<BucketEntry>>| {
|
||||
let entry = v.unwrap();
|
||||
entry.with(rti, |_rti, e| {
|
||||
// skip nodes on local network
|
||||
if e.node_info(RoutingDomain::LocalNetwork).is_some() {
|
||||
return false;
|
||||
}
|
||||
// skip nodes not on public internet
|
||||
if e.node_info(RoutingDomain::PublicInternet).is_none() {
|
||||
return false;
|
||||
}
|
||||
true
|
||||
})
|
||||
}) as RoutingTableEntryFilter;
|
||||
filters.push_front(public_node_filter);
|
||||
|
||||
self.find_fastest_nodes(
|
||||
node_count,
|
||||
filters,
|
||||
|_rti: &RoutingTableInner, k: PublicKey, v: Option<Arc<BucketEntry>>| {
|
||||
NodeRef::new(outer_self.clone(), k, v.unwrap().clone(), None)
|
||||
|_rti: &RoutingTableInner, k: TypedKey, v: Option<Arc<BucketEntry>>| {
|
||||
NodeRef::new(outer_self.clone(), v.unwrap().clone(), None)
|
||||
},
|
||||
)
|
||||
}
|
||||
@ -789,9 +808,9 @@ impl RoutingTableInner {
|
||||
&self,
|
||||
routing_domain: RoutingDomain,
|
||||
has_valid_own_node_info: bool,
|
||||
v: Option<Arc<BucketEntry>>,
|
||||
entry: Option<Arc<BucketEntry>>,
|
||||
) -> bool {
|
||||
match v {
|
||||
match entry {
|
||||
None => has_valid_own_node_info,
|
||||
Some(entry) => entry.with(self, |_rti, e| {
|
||||
e.signed_node_info(routing_domain.into())
|
||||
@ -805,12 +824,11 @@ impl RoutingTableInner {
|
||||
&self,
|
||||
routing_domain: RoutingDomain,
|
||||
own_peer_info: &PeerInfo,
|
||||
k: PublicKey,
|
||||
v: Option<Arc<BucketEntry>>,
|
||||
entry: Option<Arc<BucketEntry>>,
|
||||
) -> PeerInfo {
|
||||
match v {
|
||||
match entry {
|
||||
None => own_peer_info.clone(),
|
||||
Some(entry) => entry.with(self, |_rti, e| e.make_peer_info(k, routing_domain).unwrap()),
|
||||
Some(entry) => entry.with(self, |_rti, e| e.make_peer_info(routing_domain).unwrap()),
|
||||
}
|
||||
}
|
||||
|
||||
@ -825,15 +843,14 @@ impl RoutingTableInner {
|
||||
where
|
||||
C: for<'a, 'b> FnMut(
|
||||
&'a RoutingTableInner,
|
||||
&'b (PublicKey, Option<Arc<BucketEntry>>),
|
||||
&'b (PublicKey, Option<Arc<BucketEntry>>),
|
||||
&'b Option<Arc<BucketEntry>>,
|
||||
&'b Option<Arc<BucketEntry>>,
|
||||
) -> core::cmp::Ordering,
|
||||
T: for<'r> FnMut(&'r RoutingTableInner, PublicKey, Option<Arc<BucketEntry>>) -> O,
|
||||
T: for<'r> FnMut(&'r RoutingTableInner, TypedKey, Option<Arc<BucketEntry>>) -> O,
|
||||
{
|
||||
// collect all the nodes for sorting
|
||||
let mut nodes = Vec::<(PublicKey, Option<Arc<BucketEntry>>)>::with_capacity(
|
||||
self.bucket_entry_count + 1,
|
||||
);
|
||||
let mut nodes =
|
||||
Vec::<(TypedKey, Option<Arc<BucketEntry>>)>::with_capacity(self.bucket_entry_count + 1);
|
||||
|
||||
// add our own node (only one of there with the None entry)
|
||||
let mut filtered = false;
|
||||
@ -880,13 +897,13 @@ impl RoutingTableInner {
|
||||
transform: T,
|
||||
) -> Vec<O>
|
||||
where
|
||||
T: for<'r> FnMut(&'r RoutingTableInner, PublicKey, Option<Arc<BucketEntry>>) -> O,
|
||||
T: for<'r> FnMut(&'r RoutingTableInner, Option<Arc<BucketEntry>>) -> O,
|
||||
{
|
||||
let cur_ts = get_aligned_timestamp();
|
||||
|
||||
// Add filter to remove dead nodes always
|
||||
let filter_dead = Box::new(
|
||||
move |rti: &RoutingTableInner, _k: PublicKey, v: Option<Arc<BucketEntry>>| {
|
||||
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) {
|
||||
@ -904,8 +921,8 @@ impl RoutingTableInner {
|
||||
|
||||
// Fastest sort
|
||||
let sort = |rti: &RoutingTableInner,
|
||||
(a_key, a_entry): &(PublicKey, Option<Arc<BucketEntry>>),
|
||||
(b_key, b_entry): &(PublicKey, Option<Arc<BucketEntry>>)| {
|
||||
(a_key, a_entry): &(TypedKey, Option<Arc<BucketEntry>>),
|
||||
(b_key, b_entry): &(TypedKey, Option<Arc<BucketEntry>>)| {
|
||||
// same nodes are always the same
|
||||
if a_key == b_key {
|
||||
return core::cmp::Ordering::Equal;
|
||||
@ -960,12 +977,12 @@ impl RoutingTableInner {
|
||||
|
||||
pub fn find_closest_nodes<T, O>(
|
||||
&self,
|
||||
node_id: PublicKey,
|
||||
node_id: TypedKey,
|
||||
filters: VecDeque<RoutingTableEntryFilter>,
|
||||
transform: T,
|
||||
) -> Vec<O>
|
||||
where
|
||||
T: for<'r> FnMut(&'r RoutingTableInner, PublicKey, Option<Arc<BucketEntry>>) -> O,
|
||||
T: for<'r> FnMut(&'r RoutingTableInner, TypedKey, Option<Arc<BucketEntry>>) -> O,
|
||||
{
|
||||
let cur_ts = get_aligned_timestamp();
|
||||
let node_count = {
|
||||
@ -976,8 +993,8 @@ impl RoutingTableInner {
|
||||
|
||||
// closest sort
|
||||
let sort = |rti: &RoutingTableInner,
|
||||
(a_key, a_entry): &(PublicKey, Option<Arc<BucketEntry>>),
|
||||
(b_key, b_entry): &(PublicKey, Option<Arc<BucketEntry>>)| {
|
||||
(a_key, a_entry): &(TypedKey, Option<Arc<BucketEntry>>),
|
||||
(b_key, b_entry): &(TypedKey, Option<Arc<BucketEntry>>)| {
|
||||
// same nodes are always the same
|
||||
if a_key == b_key {
|
||||
return core::cmp::Ordering::Equal;
|
||||
|
@ -205,7 +205,7 @@ impl RoutingTable {
|
||||
for pi in peer_info {
|
||||
let k = pi.node_id.key;
|
||||
// Register the node
|
||||
if let Some(nr) = self.register_node_with_peer_info(
|
||||
if let Some(nr) = self.register_node_with_signed_node_info(
|
||||
RoutingDomain::PublicInternet,
|
||||
k,
|
||||
pi.signed_node_info,
|
||||
@ -301,7 +301,7 @@ impl RoutingTable {
|
||||
log_rtab!("--- bootstrapping {} with {:?}", k.encode(), &v);
|
||||
|
||||
// Make invalid signed node info (no signature)
|
||||
if let Some(nr) = self.register_node_with_peer_info(
|
||||
if let Some(nr) = self.register_node_with_signed_node_info(
|
||||
RoutingDomain::PublicInternet,
|
||||
k,
|
||||
SignedNodeInfo::Direct(SignedDirectNodeInfo::with_no_signature(NodeInfo {
|
||||
|
@ -24,7 +24,7 @@ impl RoutingTable {
|
||||
let noderefs = routing_table.find_fastest_nodes(
|
||||
min_peer_count,
|
||||
VecDeque::new(),
|
||||
|_rti, k: PublicKey, v: Option<Arc<BucketEntry>>| {
|
||||
|_rti, k: TypedKey, v: Option<Arc<BucketEntry>>| {
|
||||
NodeRef::new(routing_table.clone(), k, v.unwrap().clone(), None)
|
||||
},
|
||||
);
|
||||
|
@ -8,7 +8,7 @@ const BACKGROUND_SAFETY_ROUTE_COUNT: usize = 2;
|
||||
|
||||
impl RoutingTable {
|
||||
/// Fastest routes sort
|
||||
fn route_sort_latency_fn(a: &(PublicKey, u64), b: &(PublicKey, u64)) -> cmp::Ordering {
|
||||
fn route_sort_latency_fn(a: &(TypedKey, u64), b: &(TypedKey, u64)) -> cmp::Ordering {
|
||||
let mut al = a.1;
|
||||
let mut bl = b.1;
|
||||
// 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
|
||||
#[instrument(level = "trace", skip(self))]
|
||||
fn get_allocated_routes_to_test(&self, cur_ts: Timestamp) -> Vec<PublicKey> {
|
||||
fn get_allocated_routes_to_test(&self, cur_ts: Timestamp) -> Vec<TypedKey> {
|
||||
let default_route_hop_count =
|
||||
self.with_config(|c| c.network.rpc.default_route_hop_count as usize);
|
||||
|
||||
let rss = self.route_spec_store();
|
||||
let mut must_test_routes = Vec::<PublicKey>::new();
|
||||
let mut unpublished_routes = Vec::<(PublicKey, u64)>::new();
|
||||
let mut expired_routes = Vec::<PublicKey>::new();
|
||||
let mut must_test_routes = Vec::<TypedKey>::new();
|
||||
let mut unpublished_routes = Vec::<(TypedKey, u64)>::new();
|
||||
let mut expired_routes = Vec::<TypedKey>::new();
|
||||
rss.list_allocated_routes(|k, v| {
|
||||
let stats = v.get_stats();
|
||||
// Ignore nodes that don't need testing
|
||||
@ -95,7 +95,7 @@ impl RoutingTable {
|
||||
async fn test_route_set(
|
||||
&self,
|
||||
stop_token: StopToken,
|
||||
routes_needing_testing: Vec<PublicKey>,
|
||||
routes_needing_testing: Vec<TypedKey>,
|
||||
) -> EyreResult<()> {
|
||||
if routes_needing_testing.is_empty() {
|
||||
return Ok(());
|
||||
@ -107,7 +107,7 @@ impl RoutingTable {
|
||||
#[derive(Default, Debug)]
|
||||
struct TestRouteContext {
|
||||
failed: bool,
|
||||
dead_routes: Vec<PublicKey>,
|
||||
dead_routes: Vec<TypedKey>,
|
||||
}
|
||||
|
||||
let mut unord = FuturesUnordered::new();
|
||||
|
@ -117,7 +117,7 @@ impl RPCOperation {
|
||||
|
||||
pub fn decode(
|
||||
operation_reader: &veilid_capnp::operation::Reader,
|
||||
opt_sender_node_id: Option<&PublicKey>,
|
||||
opt_sender_node_id: Option<&TypedKey>,
|
||||
) -> Result<Self, RPCError> {
|
||||
let op_id = OperationId::new(operation_reader.get_op_id());
|
||||
|
||||
|
@ -2,7 +2,7 @@ use super::*;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct RPCOperationFindBlockQ {
|
||||
pub block_id: PublicKey,
|
||||
pub block_id: TypedKey,
|
||||
}
|
||||
|
||||
impl RPCOperationFindBlockQ {
|
||||
|
@ -2,7 +2,7 @@ use super::*;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct RPCOperationFindNodeQ {
|
||||
pub node_id: PublicKey,
|
||||
pub node_id: TypedKey,
|
||||
}
|
||||
|
||||
impl RPCOperationFindNodeQ {
|
||||
|
@ -39,9 +39,9 @@ pub fn decode_peer_info(
|
||||
.reborrow()
|
||||
.get_signed_node_info()
|
||||
.map_err(RPCError::protocol)?;
|
||||
let node_ids = Vec::with_capacity(nids_reader.len() as usize);
|
||||
let node_ids = TypedKeySet::with_capacity(nids_reader.len() as usize);
|
||||
for nid_reader in nids_reader.iter() {
|
||||
node_ids.push(decode_typed_key(&nid_reader)?);
|
||||
node_ids.add(decode_typed_key(&nid_reader)?);
|
||||
}
|
||||
let signed_node_info = decode_signed_node_info(&sni_reader, crypto, &node_ids)?;
|
||||
|
||||
|
@ -67,10 +67,10 @@ pub fn decode_signed_relayed_node_info(
|
||||
.reborrow()
|
||||
.get_relay_ids()
|
||||
.map_err(RPCError::protocol)?;
|
||||
let mut relay_ids = Vec::with_capacity(rids_reader.len() as usize);
|
||||
let mut relay_ids = TypedKeySet::with_capacity(rids_reader.len() as usize);
|
||||
for rid_reader in rids_reader {
|
||||
let relay_id = decode_typed_key(&rid_reader)?;
|
||||
relay_ids.push(relay_id);
|
||||
relay_ids.add(relay_id);
|
||||
}
|
||||
|
||||
let ri_reader = reader
|
||||
|
@ -15,7 +15,7 @@ pub enum Destination {
|
||||
/// The relay to send to
|
||||
relay: NodeRef,
|
||||
/// The final destination the relay should send to
|
||||
target: PublicKey,
|
||||
target: TypedKey,
|
||||
/// Require safety route or not
|
||||
safety_selection: SafetySelection,
|
||||
},
|
||||
@ -36,7 +36,7 @@ impl Destination {
|
||||
safety_selection: SafetySelection::Unsafe(sequencing),
|
||||
}
|
||||
}
|
||||
pub fn relay(relay: NodeRef, target: PublicKey) -> Self {
|
||||
pub fn relay(relay: NodeRef, target: TypedKey) -> Self {
|
||||
let sequencing = relay.sequencing();
|
||||
Self::Relay {
|
||||
relay,
|
||||
|
@ -520,12 +520,8 @@ impl RPCProcessor {
|
||||
|
||||
// Make the routed operation
|
||||
// xxx: replace MAX_CRYPTO_VERSION with the version from the factory
|
||||
let operation = RoutedOperation::new(
|
||||
MAX_CRYPTO_VERSION,
|
||||
safety_selection.get_sequencing(),
|
||||
nonce,
|
||||
enc_msg_data,
|
||||
);
|
||||
let operation =
|
||||
RoutedOperation::new(safety_selection.get_sequencing(), nonce, enc_msg_data);
|
||||
|
||||
// Prepare route operation
|
||||
let sr_hop_count = compiled_route.safety_route.hop_count;
|
||||
@ -1218,7 +1214,7 @@ impl RPCProcessor {
|
||||
"sender signednodeinfo has invalid peer scope",
|
||||
));
|
||||
}
|
||||
opt_sender_nr = self.routing_table().register_node_with_peer_info(
|
||||
opt_sender_nr = self.routing_table().register_node_with_signed_node_info(
|
||||
routing_domain,
|
||||
sender_node_id,
|
||||
sender_node_info.clone(),
|
||||
|
@ -100,8 +100,8 @@ impl RPCProcessor {
|
||||
// find N nodes closest to the target node in our routing table
|
||||
|
||||
let filter = Box::new(
|
||||
move |rti: &RoutingTableInner, _k: PublicKey, v: Option<Arc<BucketEntry>>| {
|
||||
rti.filter_has_valid_signed_node_info(RoutingDomain::PublicInternet, true, v)
|
||||
move |rti: &RoutingTableInner, entry: Option<Arc<BucketEntry>>| {
|
||||
rti.filter_has_valid_signed_node_info(RoutingDomain::PublicInternet, true, entry)
|
||||
},
|
||||
) as RoutingTableEntryFilter;
|
||||
let filters = VecDeque::from([filter]);
|
||||
@ -110,8 +110,8 @@ impl RPCProcessor {
|
||||
find_node_q.node_id,
|
||||
filters,
|
||||
// transform
|
||||
|rti, k, v| {
|
||||
rti.transform_to_peer_info(RoutingDomain::PublicInternet, &own_peer_info, k, v)
|
||||
|rti, entry| {
|
||||
rti.transform_to_peer_info(RoutingDomain::PublicInternet, &own_peer_info, entry)
|
||||
},
|
||||
);
|
||||
|
||||
|
@ -77,7 +77,7 @@ impl RPCProcessor {
|
||||
&self,
|
||||
routed_operation: RoutedOperation,
|
||||
next_route_node: RouteNode,
|
||||
safety_route_public_key: PublicKey,
|
||||
safety_route_public_key: TypedKey,
|
||||
next_private_route: PrivateRoute,
|
||||
) -> Result<NetworkResult<()>, RPCError> {
|
||||
// Make sure hop count makes sense
|
||||
@ -142,7 +142,7 @@ impl RPCProcessor {
|
||||
&self,
|
||||
_detail: RPCMessageHeaderDetailDirect,
|
||||
routed_operation: RoutedOperation,
|
||||
remote_sr_pubkey: PublicKey,
|
||||
remote_sr_pubkey: TypedKey,
|
||||
) -> Result<NetworkResult<()>, RPCError> {
|
||||
|
||||
// Now that things are valid, decrypt the routed operation with DEC(nonce, DH(the SR's public key, the PR's (or node's) secret)
|
||||
@ -177,8 +177,8 @@ impl RPCProcessor {
|
||||
&self,
|
||||
detail: RPCMessageHeaderDetailDirect,
|
||||
routed_operation: RoutedOperation,
|
||||
remote_sr_pubkey: PublicKey,
|
||||
pr_pubkey: PublicKey,
|
||||
remote_sr_pubkey: TypedKey,
|
||||
pr_pubkey: TypedKey,
|
||||
) -> Result<NetworkResult<()>, RPCError> {
|
||||
// Get sender id
|
||||
let sender_id = detail.envelope.get_sender_id();
|
||||
@ -237,8 +237,8 @@ impl RPCProcessor {
|
||||
&self,
|
||||
detail: RPCMessageHeaderDetailDirect,
|
||||
routed_operation: RoutedOperation,
|
||||
remote_sr_pubkey: PublicKey,
|
||||
pr_pubkey: PublicKey,
|
||||
remote_sr_pubkey: TypedKey,
|
||||
pr_pubkey: TypedKey,
|
||||
) -> Result<NetworkResult<()>, RPCError> {
|
||||
|
||||
// If the private route public key is our node id, then this was sent via safety route to our node directly
|
||||
@ -260,7 +260,7 @@ impl RPCProcessor {
|
||||
pub(crate) async fn process_private_route_first_hop(
|
||||
&self,
|
||||
mut routed_operation: RoutedOperation,
|
||||
sr_pubkey: PublicKey,
|
||||
sr_pubkey: TypedKey,
|
||||
mut private_route: PrivateRoute,
|
||||
) -> Result<NetworkResult<()>, RPCError> {
|
||||
let Some(pr_first_hop) = private_route.pop_first_hop() else {
|
||||
@ -312,7 +312,7 @@ impl RPCProcessor {
|
||||
}
|
||||
|
||||
/// Decrypt route hop data and sign routed operation
|
||||
pub(crate) fn decrypt_private_route_hop_data(&self, route_hop_data: &RouteHopData, pr_pubkey: &PublicKey, route_operation: &mut RoutedOperation) -> Result<NetworkResult<RouteHop>, RPCError>
|
||||
pub(crate) fn decrypt_private_route_hop_data(&self, route_hop_data: &RouteHopData, pr_pubkey: &TypedKey, route_operation: &mut RoutedOperation) -> Result<NetworkResult<RouteHop>, RPCError>
|
||||
{
|
||||
// Decrypt the blob with DEC(nonce, DH(the PR's public key, this hop's secret)
|
||||
let node_id_secret = self.routing_table.node_id_secret();
|
||||
|
@ -102,7 +102,7 @@ impl RPCProcessor {
|
||||
dial_info.clone(),
|
||||
);
|
||||
let will_validate_dial_info_filter = Box::new(
|
||||
move |rti: &RoutingTableInner, _k: PublicKey, v: Option<Arc<BucketEntry>>| {
|
||||
move |rti: &RoutingTableInner, _k: TypedKey, v: Option<Arc<BucketEntry>>| {
|
||||
let entry = v.unwrap();
|
||||
entry.with(rti, move |_rti, e| {
|
||||
if let Some(status) = &e.node_status(routing_domain) {
|
||||
|
@ -132,9 +132,9 @@ pub async fn test_frozen(ts: TableStore) {
|
||||
|
||||
assert!(db.store_rkyv(0, b"asdf", &dht_key).await.is_ok());
|
||||
|
||||
assert_eq!(db.load_rkyv::<PublicKey>(0, b"qwer").unwrap(), None);
|
||||
assert_eq!(db.load_rkyv::<TypedKey>(0, b"qwer").unwrap(), None);
|
||||
|
||||
let d = match db.load_rkyv::<PublicKey>(0, b"asdf") {
|
||||
let d = match db.load_rkyv::<TypedKey>(0, b"asdf") {
|
||||
Ok(x) => x,
|
||||
Err(e) => {
|
||||
panic!("couldn't decode: {}", e);
|
||||
@ -148,7 +148,7 @@ pub async fn test_frozen(ts: TableStore) {
|
||||
);
|
||||
|
||||
assert!(
|
||||
db.load_rkyv::<PublicKey>(1, b"foo").is_err(),
|
||||
db.load_rkyv::<TypedKey>(1, b"foo").is_err(),
|
||||
"should fail to unfreeze"
|
||||
);
|
||||
}
|
||||
|
@ -192,7 +192,7 @@ fn config_callback(key: String) -> ConfigCallbackReturn {
|
||||
"network.client_whitelist_timeout_ms" => Ok(Box::new(300_000u32)),
|
||||
"network.reverse_connection_receipt_time_ms" => Ok(Box::new(5_000u32)),
|
||||
"network.hole_punch_receipt_time_ms" => Ok(Box::new(5_000u32)),
|
||||
"network.node_id" => Ok(Box::new(Option::<PublicKey>::None)),
|
||||
"network.node_id" => Ok(Box::new(Option::<TypedKey>::None)),
|
||||
"network.node_id_secret" => Ok(Box::new(Option::<SecretKey>::None)),
|
||||
"network.bootstrap" => Ok(Box::new(Vec::<String>::new())),
|
||||
"network.bootstrap_nodes" => Ok(Box::new(Vec::<String>::new())),
|
||||
|
@ -167,7 +167,7 @@ impl VeilidAPI {
|
||||
// Private route allocation
|
||||
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
pub async fn new_private_route(&self) -> Result<(PublicKey, Vec<u8>), VeilidAPIError> {
|
||||
pub async fn new_private_route(&self) -> Result<(TypedKey, Vec<u8>), VeilidAPIError> {
|
||||
self.new_custom_private_route(Stability::default(), Sequencing::default())
|
||||
.await
|
||||
}
|
||||
@ -177,7 +177,7 @@ impl VeilidAPI {
|
||||
&self,
|
||||
stability: Stability,
|
||||
sequencing: Sequencing,
|
||||
) -> Result<(PublicKey, Vec<u8>), VeilidAPIError> {
|
||||
) -> Result<(TypedKey, Vec<u8>), VeilidAPIError> {
|
||||
let default_route_hop_count: usize = {
|
||||
let config = self.config()?;
|
||||
let c = config.get();
|
||||
@ -223,14 +223,14 @@ impl VeilidAPI {
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
pub fn import_remote_private_route(&self, blob: Vec<u8>) -> Result<PublicKey, VeilidAPIError> {
|
||||
pub fn import_remote_private_route(&self, blob: Vec<u8>) -> Result<TypedKey, VeilidAPIError> {
|
||||
let rss = self.routing_table()?.route_spec_store();
|
||||
rss.import_remote_private_route(blob)
|
||||
.map_err(|e| VeilidAPIError::invalid_argument(e, "blob", "private route blob"))
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
pub fn release_private_route(&self, key: &PublicKey) -> Result<(), VeilidAPIError> {
|
||||
pub fn release_private_route(&self, key: &TypedKey) -> Result<(), VeilidAPIError> {
|
||||
let rss = self.routing_table()?.route_spec_store();
|
||||
if rss.release_route(key) {
|
||||
Ok(())
|
||||
|
@ -7,7 +7,7 @@ use routing_table::*;
|
||||
|
||||
#[derive(Default, Debug)]
|
||||
struct DebugCache {
|
||||
imported_routes: Vec<PublicKey>,
|
||||
imported_routes: Vec<TypedKey>,
|
||||
}
|
||||
|
||||
static DEBUG_CACHE: Mutex<DebugCache> = Mutex::new(DebugCache {
|
||||
@ -30,12 +30,12 @@ fn get_string(text: &str) -> Option<String> {
|
||||
Some(text.to_owned())
|
||||
}
|
||||
|
||||
fn get_route_id(rss: RouteSpecStore) -> impl Fn(&str) -> Option<PublicKey> {
|
||||
fn get_route_id(rss: RouteSpecStore) -> impl Fn(&str) -> Option<TypedKey> {
|
||||
return move |text: &str| {
|
||||
if text.is_empty() {
|
||||
return None;
|
||||
}
|
||||
match PublicKey::try_decode(text).ok() {
|
||||
match TypedKey::try_decode(text).ok() {
|
||||
Some(key) => {
|
||||
let routes = rss.list_allocated_routes(|k, _| Some(*k));
|
||||
if routes.contains(&key) {
|
||||
@ -187,8 +187,8 @@ fn get_destination(routing_table: RoutingTable) -> impl FnOnce(&str) -> Option<D
|
||||
fn get_number(text: &str) -> Option<usize> {
|
||||
usize::from_str(text).ok()
|
||||
}
|
||||
fn get_dht_key(text: &str) -> Option<PublicKey> {
|
||||
PublicKey::try_decode(text).ok()
|
||||
fn get_dht_key(text: &str) -> Option<TypedKey> {
|
||||
TypedKey::try_decode(text).ok()
|
||||
}
|
||||
|
||||
fn get_node_ref(routing_table: RoutingTable) -> impl FnOnce(&str) -> Option<NodeRef> {
|
||||
|
@ -108,11 +108,11 @@ pub enum VeilidAPIError {
|
||||
#[error("Shutdown")]
|
||||
Shutdown,
|
||||
#[error("Key not found: {key}")]
|
||||
KeyNotFound { key: PublicKey },
|
||||
KeyNotFound { key: TypedKey },
|
||||
#[error("No connection: {message}")]
|
||||
NoConnection { message: String },
|
||||
#[error("No peer info: {node_id}")]
|
||||
NoPeerInfo { node_id: PublicKey },
|
||||
NoPeerInfo { node_id: TypedKey },
|
||||
#[error("Internal: {message}")]
|
||||
Internal { message: String },
|
||||
#[error("Unimplemented: {message}")]
|
||||
@ -147,7 +147,7 @@ impl VeilidAPIError {
|
||||
pub fn shutdown() -> Self {
|
||||
Self::Shutdown
|
||||
}
|
||||
pub fn key_not_found(key: PublicKey) -> Self {
|
||||
pub fn key_not_found(key: TypedKey) -> Self {
|
||||
Self::KeyNotFound { key }
|
||||
}
|
||||
pub fn no_connection<T: ToString>(msg: T) -> Self {
|
||||
@ -155,7 +155,7 @@ impl VeilidAPIError {
|
||||
message: msg.to_string(),
|
||||
}
|
||||
}
|
||||
pub fn no_peer_info(node_id: PublicKey) -> Self {
|
||||
pub fn no_peer_info(node_id: TypedKey) -> Self {
|
||||
Self::NoPeerInfo { node_id }
|
||||
}
|
||||
pub fn internal<T: ToString>(msg: T) -> Self {
|
||||
|
@ -4,8 +4,8 @@ use super::*;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum Target {
|
||||
NodeId(PublicKey),
|
||||
PrivateRoute(PublicKey),
|
||||
NodeId(TypedKey),
|
||||
PrivateRoute(TypedKey),
|
||||
}
|
||||
|
||||
pub struct RoutingContextInner {}
|
||||
|
@ -256,7 +256,7 @@ pub struct VeilidStateAttachment {
|
||||
)]
|
||||
#[archive_attr(repr(C), derive(CheckBytes))]
|
||||
pub struct PeerTableData {
|
||||
pub node_ids: Vec<TypedKey>,
|
||||
pub node_ids: TypedKeySet,
|
||||
pub peer_address: PeerAddress,
|
||||
pub peer_stats: PeerStats,
|
||||
}
|
||||
@ -279,8 +279,8 @@ pub struct VeilidStateNetwork {
|
||||
)]
|
||||
#[archive_attr(repr(C), derive(CheckBytes))]
|
||||
pub struct VeilidStateRoute {
|
||||
pub dead_routes: Vec<PublicKey>,
|
||||
pub dead_remote_routes: Vec<PublicKey>,
|
||||
pub dead_routes: Vec<TypedKey>,
|
||||
pub dead_remote_routes: Vec<TypedKey>,
|
||||
}
|
||||
|
||||
#[derive(
|
||||
@ -513,7 +513,7 @@ impl SafetySelection {
|
||||
#[archive_attr(repr(C), derive(CheckBytes))]
|
||||
pub struct SafetySpec {
|
||||
/// preferred safety route if it still exists
|
||||
pub preferred_route: Option<PublicKey>,
|
||||
pub preferred_route: Option<TypedKey>,
|
||||
/// must be greater than 0
|
||||
pub hop_count: usize,
|
||||
/// prefer reliability over speed
|
||||
@ -1924,7 +1924,7 @@ impl SignedDirectNodeInfo {
|
||||
#[archive_attr(repr(C), derive(CheckBytes))]
|
||||
pub struct SignedRelayedNodeInfo {
|
||||
pub node_info: NodeInfo,
|
||||
pub relay_ids: Vec<TypedKey>,
|
||||
pub relay_ids: TypedKeySet,
|
||||
pub relay_info: SignedDirectNodeInfo,
|
||||
pub timestamp: Timestamp,
|
||||
pub signatures: Vec<TypedSignature>,
|
||||
@ -1935,7 +1935,7 @@ impl SignedRelayedNodeInfo {
|
||||
crypto: Crypto,
|
||||
node_ids: &[TypedKey],
|
||||
node_info: NodeInfo,
|
||||
relay_ids: Vec<TypedKey>,
|
||||
relay_ids: TypedKeySet,
|
||||
relay_info: SignedDirectNodeInfo,
|
||||
timestamp: Timestamp,
|
||||
typed_signatures: Vec<TypedSignature>,
|
||||
@ -1955,7 +1955,7 @@ impl SignedRelayedNodeInfo {
|
||||
pub fn make_signatures(
|
||||
crypto: Crypto,
|
||||
node_info: NodeInfo,
|
||||
relay_ids: Vec<TypedKey>,
|
||||
relay_ids: TypedKeySet,
|
||||
relay_info: SignedDirectNodeInfo,
|
||||
typed_key_pairs: Vec<TypedKeyPair>,
|
||||
) -> Result<Self, VeilidAPIError> {
|
||||
@ -2043,9 +2043,9 @@ impl SignedNodeInfo {
|
||||
SignedNodeInfo::Relayed(r) => &r.node_info,
|
||||
}
|
||||
}
|
||||
pub fn relay_ids(&self) -> Vec<TypedKey> {
|
||||
pub fn relay_ids(&self) -> TypedKeySet {
|
||||
match self {
|
||||
SignedNodeInfo::Direct(_) => Vec::new(),
|
||||
SignedNodeInfo::Direct(_) => TypedKeySet::new(),
|
||||
SignedNodeInfo::Relayed(r) => r.relay_ids.clone(),
|
||||
}
|
||||
}
|
||||
@ -2107,12 +2107,12 @@ impl SignedNodeInfo {
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, RkyvArchive, RkyvSerialize, RkyvDeserialize)]
|
||||
#[archive_attr(repr(C), derive(CheckBytes))]
|
||||
pub struct PeerInfo {
|
||||
pub node_ids: Vec<TypedKey>,
|
||||
pub node_ids: TypedKeySet,
|
||||
pub signed_node_info: SignedNodeInfo,
|
||||
}
|
||||
|
||||
impl PeerInfo {
|
||||
pub fn new(node_ids: Vec<TypedKey>, signed_node_info: SignedNodeInfo) -> Self {
|
||||
pub fn new(node_ids: TypedKeySet, signed_node_info: SignedNodeInfo) -> Self {
|
||||
Self {
|
||||
node_ids,
|
||||
signed_node_info,
|
||||
|
@ -93,7 +93,7 @@ pub struct VeilidFFIConfig {
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize)]
|
||||
pub struct VeilidFFIKeyBlob {
|
||||
pub key: veilid_core::PublicKey,
|
||||
pub key: veilid_core::TypedKey,
|
||||
#[serde(with = "veilid_core::json_as_base64")]
|
||||
pub blob: Vec<u8>,
|
||||
}
|
||||
@ -417,7 +417,7 @@ pub extern "C" fn routing_context_with_sequencing(id: u32, sequencing: FfiStr) -
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn routing_context_app_call(port: i64, id: u32, target: FfiStr, request: FfiStr) {
|
||||
let target: veilid_core::PublicKey =
|
||||
let target: veilid_core::TypedKey =
|
||||
veilid_core::deserialize_opt_json(target.into_opt_string()).unwrap();
|
||||
let request: Vec<u8> = data_encoding::BASE64URL_NOPAD
|
||||
.decode(
|
||||
@ -453,7 +453,7 @@ pub extern "C" fn routing_context_app_call(port: i64, id: u32, target: FfiStr, r
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn routing_context_app_message(port: i64, id: u32, target: FfiStr, message: FfiStr) {
|
||||
let target: veilid_core::PublicKey =
|
||||
let target: veilid_core::TypedKey =
|
||||
veilid_core::deserialize_opt_json(target.into_opt_string()).unwrap();
|
||||
let message: Vec<u8> = data_encoding::BASE64URL_NOPAD
|
||||
.decode(
|
||||
@ -539,7 +539,7 @@ pub extern "C" fn import_remote_private_route(port: i64, blob: FfiStr) {
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn release_private_route(port: i64, key: FfiStr) {
|
||||
let key: veilid_core::PublicKey =
|
||||
let key: veilid_core::TypedKey =
|
||||
veilid_core::deserialize_opt_json(key.into_opt_string()).unwrap();
|
||||
DartIsolateWrapper::new(port).spawn_result(async move {
|
||||
let veilid_api = get_veilid_api().await?;
|
||||
|
@ -4,7 +4,7 @@ use clap::{Arg, ArgMatches, Command};
|
||||
use std::ffi::OsStr;
|
||||
use std::path::Path;
|
||||
use std::str::FromStr;
|
||||
use veilid_core::{PublicKey, SecretKey};
|
||||
use veilid_core::{SecretKey, TypedKey};
|
||||
|
||||
fn do_clap_matches(default_config_path: &OsStr) -> Result<clap::ArgMatches, clap::Error> {
|
||||
let matches = Command::new("veilid-server")
|
||||
@ -246,11 +246,11 @@ pub fn process_command_line() -> EyreResult<(Settings, ArgMatches)> {
|
||||
// Split or get secret
|
||||
let (k, s) = if let Some((k, s)) = v.split_once(':') {
|
||||
let k =
|
||||
PublicKey::try_decode(k).wrap_err("failed to decode node id from command line")?;
|
||||
TypedKey::try_decode(k).wrap_err("failed to decode node id from command line")?;
|
||||
let s = SecretKey::try_decode(s)?;
|
||||
(k, s)
|
||||
} else {
|
||||
let k = PublicKey::try_decode(v)?;
|
||||
let k = TypedKey::try_decode(v)?;
|
||||
let buffer = rpassword::prompt_password("Enter secret key (will not echo): ")
|
||||
.wrap_err("invalid secret key")?;
|
||||
let buffer = buffer.trim().to_string();
|
||||
|
@ -595,7 +595,7 @@ pub struct Network {
|
||||
pub client_whitelist_timeout_ms: u32,
|
||||
pub reverse_connection_receipt_time_ms: u32,
|
||||
pub hole_punch_receipt_time_ms: u32,
|
||||
pub node_id: Option<veilid_core::PublicKey>,
|
||||
pub node_id: Option<veilid_core::TypedKey>,
|
||||
pub node_id_secret: Option<veilid_core::SecretKey>,
|
||||
pub bootstrap: Vec<String>,
|
||||
pub bootstrap_nodes: Vec<ParsedNodeDialInfo>,
|
||||
|
@ -137,7 +137,7 @@ pub struct VeilidWASMConfig {
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize)]
|
||||
pub struct VeilidKeyBlob {
|
||||
pub key: veilid_core::PublicKey,
|
||||
pub key: veilid_core::TypedKey,
|
||||
#[serde(with = "veilid_core::json_as_base64")]
|
||||
pub blob: Vec<u8>,
|
||||
}
|
||||
@ -459,7 +459,7 @@ pub fn import_remote_private_route(blob: String) -> Promise {
|
||||
|
||||
#[wasm_bindgen()]
|
||||
pub fn release_private_route(key: String) -> Promise {
|
||||
let key: veilid_core::PublicKey = veilid_core::deserialize_json(&key).unwrap();
|
||||
let key: veilid_core::TypedKey = veilid_core::deserialize_json(&key).unwrap();
|
||||
wrap_api_future_void(async move {
|
||||
let veilid_api = get_veilid_api()?;
|
||||
veilid_api.release_private_route(&key)?;
|
||||
|
Loading…
Reference in New Issue
Block a user