Further topology cleanup by defining NymTopology trait
This commit is contained in:
Generated
+1
-1
@@ -449,6 +449,7 @@ version = "0.1.0"
|
||||
dependencies = [
|
||||
"reqwest 0.9.24 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"topology 0.1.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2056,7 +2057,6 @@ dependencies = [
|
||||
"addressing 0.1.0",
|
||||
"base64 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"curve25519-dalek 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"directory_client 0.1.0",
|
||||
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
||||
@@ -8,4 +8,7 @@ edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
reqwest = "0.9.22"
|
||||
serde = { version = "1.0.104", features = ["derive"] }
|
||||
serde = { version = "1.0.104", features = ["derive"] }
|
||||
|
||||
## internal
|
||||
topology = {path = "../../common/topology"}
|
||||
@@ -1,11 +1,24 @@
|
||||
use crate::requests::presence_topology_get::PresenceTopologyGetRequester;
|
||||
use crate::{Client, Config, DirectoryClient};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use topology::NymTopology;
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CocoPresence {
|
||||
pub host: String,
|
||||
pub pub_key: String,
|
||||
pub last_seen: i64,
|
||||
pub last_seen: u64,
|
||||
}
|
||||
|
||||
impl Into<topology::CocoNode> for CocoPresence {
|
||||
fn into(self) -> topology::CocoNode {
|
||||
topology::CocoNode {
|
||||
host: self.host,
|
||||
pub_key: self.pub_key,
|
||||
last_seen: self.last_seen,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||
@@ -18,21 +31,54 @@ pub struct MixNodePresence {
|
||||
pub version: String,
|
||||
}
|
||||
|
||||
impl Into<topology::MixNode> for MixNodePresence {
|
||||
fn into(self) -> topology::MixNode {
|
||||
topology::MixNode {
|
||||
host: self.host,
|
||||
pub_key: self.pub_key,
|
||||
layer: self.layer,
|
||||
last_seen: self.last_seen,
|
||||
version: self.version,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct MixProviderPresence {
|
||||
pub host: String,
|
||||
pub pub_key: String,
|
||||
pub registered_clients: Vec<MixProviderClient>,
|
||||
pub last_seen: u64,
|
||||
pub version: String,
|
||||
}
|
||||
|
||||
impl Into<topology::MixProviderNode> for MixProviderPresence {
|
||||
fn into(self) -> topology::MixProviderNode {
|
||||
topology::MixProviderNode {
|
||||
host: self.host,
|
||||
pub_key: self.pub_key,
|
||||
registered_clients: self.registered_clients.into_iter().map(|c| c.into()).collect(),
|
||||
last_seen: self.last_seen,
|
||||
version: self.version,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct MixProviderClient {
|
||||
pub pub_key: String,
|
||||
}
|
||||
|
||||
impl Into<topology::MixProviderClient> for MixProviderClient {
|
||||
fn into(self) -> topology::MixProviderClient {
|
||||
topology::MixProviderClient {
|
||||
pub_key: self.pub_key,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Topology shows us the current state of the overall Nym network
|
||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
@@ -41,3 +87,31 @@ pub struct Topology {
|
||||
pub mix_nodes: Vec<MixNodePresence>,
|
||||
pub mix_provider_nodes: Vec<MixProviderPresence>,
|
||||
}
|
||||
|
||||
impl NymTopology for Topology {
|
||||
fn new(directory_server: String) -> Self {
|
||||
println!("Using directory server: {:?}", directory_server);
|
||||
let directory_config = Config {
|
||||
base_url: directory_server,
|
||||
};
|
||||
let directory = Client::new(directory_config);
|
||||
|
||||
let topology = directory
|
||||
.presence_topology
|
||||
.get()
|
||||
.expect("Failed to retrieve network topology.");
|
||||
topology
|
||||
}
|
||||
|
||||
fn get_mix_nodes(&self) -> Vec<topology::MixNode> {
|
||||
self.mix_nodes.iter().map(|x| x.clone().into()).collect()
|
||||
}
|
||||
|
||||
fn get_mix_provider_nodes(&self) -> Vec<topology::MixProviderNode> {
|
||||
self.mix_provider_nodes.iter().map(|x| x.clone().into()).collect()
|
||||
}
|
||||
|
||||
fn get_coco_nodes(&self) -> Vec<topology::CocoNode> {
|
||||
self.coco_nodes.iter().map(|x| x.clone().into()).collect()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ use std::net::SocketAddr;
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
use tokio::runtime::Runtime;
|
||||
use topology::get_topology;
|
||||
use topology::NymTopology;
|
||||
|
||||
const LOOP_COVER_AVERAGE_DELAY: f64 = 0.5;
|
||||
// seconds
|
||||
@@ -223,10 +223,10 @@ impl NymClient {
|
||||
println!("Starting nym client");
|
||||
let mut rt = Runtime::new()?;
|
||||
|
||||
let topology = get_topology(self.directory.clone());
|
||||
let topology = Topology::new(self.directory.clone());
|
||||
// this is temporary and assumes there exists only a single provider.
|
||||
let provider_address: SocketAddr = topology
|
||||
.mix_provider_nodes
|
||||
.get_mix_provider_nodes()
|
||||
.first()
|
||||
.unwrap()
|
||||
.host
|
||||
|
||||
@@ -5,6 +5,7 @@ use directory_client::presence::Topology;
|
||||
use sphinx::route::{Destination, DestinationAddressBytes, Node, SURBIdentifier};
|
||||
use sphinx::SphinxPacket;
|
||||
use std::net::SocketAddr;
|
||||
use topology::NymTopology;
|
||||
|
||||
pub const LOOP_COVER_MESSAGE_PAYLOAD: &[u8] = b"The cake is a lie!";
|
||||
|
||||
@@ -23,7 +24,7 @@ pub fn encapsulate_message(
|
||||
message: Vec<u8>,
|
||||
topology: &Topology,
|
||||
) -> (SocketAddr, SphinxPacket) {
|
||||
let mixes_route = topology::route_from(&topology);
|
||||
let mixes_route = topology.route_from();
|
||||
let first_provider = topology.mix_provider_nodes.first().unwrap();
|
||||
let decoded_key_bytes =
|
||||
base64::decode_config(&first_provider.pub_key, base64::URL_SAFE).unwrap();
|
||||
|
||||
@@ -15,7 +15,6 @@ serde = { version = "1.0.104", features = ["derive"] }
|
||||
|
||||
## internal
|
||||
addressing = {path = "../addressing"}
|
||||
directory_client = { path = "../../client/directory_client" }
|
||||
|
||||
## will be moved to proper dependencies once released
|
||||
sphinx = { path = "../../../sphinx" }
|
||||
+66
-47
@@ -1,56 +1,75 @@
|
||||
use addressing;
|
||||
use curve25519_dalek::montgomery::MontgomeryPoint;
|
||||
use directory_client::presence::{MixNodePresence, Topology};
|
||||
use directory_client::requests::presence_topology_get::PresenceTopologyGetRequester;
|
||||
use directory_client::DirectoryClient;
|
||||
use rand::seq::SliceRandom;
|
||||
use sphinx::route::Node as SphinxNode;
|
||||
use std::collections::HashMap;
|
||||
|
||||
pub fn get_topology(directory_server: String) -> Topology {
|
||||
println!("Using directory server: {:?}", directory_server);
|
||||
let directory_config = directory_client::Config {
|
||||
base_url: directory_server,
|
||||
};
|
||||
let directory = directory_client::Client::new(directory_config);
|
||||
|
||||
let topology = directory
|
||||
.presence_topology
|
||||
.get()
|
||||
.expect("Failed to retrieve network topology.");
|
||||
topology
|
||||
#[derive(Debug)]
|
||||
pub struct MixNode {
|
||||
pub host: String,
|
||||
pub pub_key: String,
|
||||
pub layer: u64,
|
||||
pub last_seen: u64,
|
||||
pub version: String,
|
||||
}
|
||||
|
||||
pub fn route_from(topology: &Topology) -> Vec<SphinxNode> {
|
||||
let mut layered_topology: HashMap<u64, Vec<MixNodePresence>> = HashMap::new();
|
||||
let mixes = topology.mix_nodes.iter();
|
||||
for mix in mixes {
|
||||
let layer_nodes = layered_topology.entry(mix.layer).or_insert(Vec::new());
|
||||
layer_nodes.push(mix.clone());
|
||||
}
|
||||
|
||||
let num_layers = layered_topology.len() as u64;
|
||||
let mut route = vec![];
|
||||
|
||||
for x in 1..=num_layers {
|
||||
let nodes = &layered_topology[&x];
|
||||
let the_node = nodes.choose(&mut rand::thread_rng()).unwrap();
|
||||
route.push(the_node);
|
||||
}
|
||||
|
||||
route
|
||||
.iter()
|
||||
.map(|mix| {
|
||||
let address_bytes =
|
||||
addressing::encoded_bytes_from_socket_address(mix.host.clone().parse().unwrap());
|
||||
let decoded_key_bytes = base64::decode_config(&mix.pub_key, base64::URL_SAFE).unwrap();
|
||||
let mut key_bytes = [0; 32];
|
||||
key_bytes.copy_from_slice(&decoded_key_bytes[..]);
|
||||
let key = MontgomeryPoint(key_bytes);
|
||||
SphinxNode {
|
||||
address: address_bytes,
|
||||
pub_key: key,
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
#[derive(Debug)]
|
||||
pub struct MixProviderClient {
|
||||
pub pub_key: String,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct MixProviderNode {
|
||||
pub host: String,
|
||||
pub pub_key: String,
|
||||
pub registered_clients: Vec<MixProviderClient>,
|
||||
pub last_seen: u64,
|
||||
pub version: String,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct CocoNode {
|
||||
pub host: String,
|
||||
pub pub_key: String,
|
||||
pub last_seen: u64,
|
||||
}
|
||||
|
||||
pub trait NymTopology {
|
||||
fn new(directory_server: String) -> Self;
|
||||
fn get_mix_nodes(&self) -> Vec<MixNode>;
|
||||
fn get_mix_provider_nodes(&self) -> Vec<MixProviderNode>;
|
||||
fn get_coco_nodes(&self) -> Vec<CocoNode>;
|
||||
fn route_from(&self) -> Vec<SphinxNode> {
|
||||
let mut layered_topology: HashMap<u64, Vec<MixNode>> = HashMap::new();
|
||||
for mix in self.get_mix_nodes() {
|
||||
let layer_nodes = layered_topology.entry(mix.layer).or_insert(Vec::new());
|
||||
layer_nodes.push(mix);
|
||||
}
|
||||
|
||||
// TODO: assertion that num_layers is a sane number
|
||||
let num_layers = layered_topology.len() as u64;
|
||||
|
||||
let route: Vec<_> = (1..=num_layers)
|
||||
.map(|layer| &layered_topology[&layer]) // for each layer
|
||||
.map(|nodes| nodes.choose(&mut rand::thread_rng()).unwrap()) // choose random node
|
||||
.collect();
|
||||
|
||||
route
|
||||
.iter()
|
||||
.map(|mix| {
|
||||
let address_bytes = addressing::encoded_bytes_from_socket_address(
|
||||
mix.host.clone().parse().unwrap(),
|
||||
);
|
||||
let decoded_key_bytes =
|
||||
base64::decode_config(&mix.pub_key, base64::URL_SAFE).unwrap();
|
||||
let mut key_bytes = [0; 32];
|
||||
key_bytes.copy_from_slice(&decoded_key_bytes[..]);
|
||||
let key = MontgomeryPoint(key_bytes);
|
||||
SphinxNode {
|
||||
address: address_bytes,
|
||||
pub_key: key,
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,6 +42,7 @@ impl Notifier {
|
||||
host: self.host.clone(),
|
||||
pub_key: self.pub_key.clone(),
|
||||
registered_clients: unlocked_ledger.current_clients(),
|
||||
last_seen: 0,
|
||||
version: env!("CARGO_PKG_VERSION").to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user