Files
nym/explorer-api/src/mix_nodes/mod.rs
T
Jędrzej Stuczyński a274edffba Feature/nymd client integration (#736)
* Calculating gas fees

* Ability to set custom fees

* Added extra test

* Removed commented code

* Moved all msg types to common contract crate

* Temporarily disabling get_tx method

* Finishing up nymd client API

* Comment fix

* Remaining fee values

* Some cleanup

* Removed needless borrow

* Fixed imports in contract tests

* Moved error types around

* New ValidatorClient

* Experiment with new type of defaults

* Removed dead module

* Dealt with unwrap

* Migrated mixnode to use new validator client

* Migrated gateway to use new validator client

* Mixnode and gateway adjustments

* More exported defaults

* Clients using new validator client

* Fixed mixnode upgrade

* Moved default values to a new crate

* Changed behaviour of validator client features

* Migrated basic functions of validator api

* Updated config + fixed startup

* Fixed wasm client build

* Integration with the explorer api

* Removed tokio dev dependency

* Needless borrow

* Fixex wasm client build

* Fixed tauri client build

* Needless borrows

* Fixed client upgrade print

* Removed redundant comments

* Made note on aggregated verification key into a doc comment

* Removed mixnet contract references from verloc

* Modified default validators structure

* Reformatted validator-api Cargo.toml file

* Removed commented code

* Made the doc comment example a no-run

* Fixed a upgrade print... again

* Adjusted the doc example

* Removed unused import
2021-08-18 14:41:00 +01:00

170 lines
5.2 KiB
Rust

mod utils;
use std::collections::HashMap;
use std::sync::Arc;
use std::time::{Duration, SystemTime};
use rocket::tokio::sync::RwLock;
use serde::{Deserialize, Serialize};
use crate::mix_nodes::utils::map_2_letter_to_3_letter_country_code;
use mixnet_contract::MixNodeBond;
use network_defaults::default_api_endpoints;
pub(crate) type LocationCache = HashMap<String, Location>;
#[derive(Debug, Deserialize)]
pub(crate) struct GeoLocation {
pub(crate) ip: String,
pub(crate) country_code: String,
pub(crate) country_name: String,
pub(crate) region_code: String,
pub(crate) region_name: String,
pub(crate) city: String,
pub(crate) zip_code: String,
pub(crate) time_zone: String,
pub(crate) latitude: f32,
pub(crate) longitude: f32,
pub(crate) metro_code: u32,
}
#[derive(Clone, Debug, JsonSchema, Serialize, Deserialize)]
pub(crate) struct Location {
pub(crate) two_letter_iso_country_code: String,
pub(crate) three_letter_iso_country_code: String,
pub(crate) country_name: String,
pub(crate) lat: f32,
pub(crate) lng: f32,
}
impl Location {
pub(crate) fn new(geo_location: GeoLocation) -> Self {
let three_letter_iso_country_code = map_2_letter_to_3_letter_country_code(&geo_location);
Location {
country_name: geo_location.country_name,
two_letter_iso_country_code: geo_location.country_code,
three_letter_iso_country_code,
lat: geo_location.latitude,
lng: geo_location.longitude,
}
}
}
#[derive(Clone, Debug)]
pub(crate) struct MixNodeBondWithLocation {
pub(crate) location: Option<Location>,
pub(crate) bond: MixNodeBond,
}
#[derive(Clone, Debug)]
pub(crate) struct MixNodesResult {
pub(crate) valid_until: SystemTime,
pub(crate) value: HashMap<String, MixNodeBondWithLocation>,
location_cache: LocationCache,
}
#[derive(Clone)]
pub(crate) struct ThreadsafeMixNodesResult {
inner: Arc<RwLock<MixNodesResult>>,
}
impl ThreadsafeMixNodesResult {
pub(crate) fn new() -> Self {
ThreadsafeMixNodesResult {
inner: Arc::new(RwLock::new(MixNodesResult {
value: HashMap::new(),
valid_until: SystemTime::now() - Duration::from_secs(60), // in the past
location_cache: LocationCache::new(),
})),
}
}
pub(crate) fn new_with_location_cache(location_cache: LocationCache) -> Self {
ThreadsafeMixNodesResult {
inner: Arc::new(RwLock::new(MixNodesResult {
value: HashMap::new(),
valid_until: SystemTime::now() - Duration::from_secs(60), // in the past
location_cache,
})),
}
}
pub(crate) async fn get_location_cache(&self) -> LocationCache {
self.inner.read().await.location_cache.clone()
}
pub(crate) async fn set_location(&self, identity_key: &str, location: Location) {
let mut guard = self.inner.write().await;
// cache the location for this mix node so that it can be used when the mix node list is refreshed
guard
.location_cache
.insert(identity_key.to_string(), location.clone());
// add the location to the mix node
guard
.value
.entry(identity_key.to_string())
.and_modify(|item| item.location = Some(location));
}
pub(crate) async fn get(&self) -> MixNodesResult {
// check ttl
let valid_until = self.inner.read().await.valid_until;
if valid_until < SystemTime::now() {
// force reload
self.refresh().await;
}
// return in-memory cache
self.inner.read().await.clone()
}
pub(crate) async fn refresh_and_get(&self) -> MixNodesResult {
self.refresh().await;
self.inner.read().await.clone()
}
async fn refresh(&self) {
// get mixnodes and cache the new value
let value = retrieve_mixnodes().await;
let location_cache = self.inner.read().await.location_cache.clone();
*self.inner.write().await = MixNodesResult {
value: value
.into_iter()
.map(|bond| {
let location = location_cache.get(&bond.mix_node.identity_key).cloned(); // add the location, if we've located this mix node before
(
bond.mix_node.identity_key.to_string(),
MixNodeBondWithLocation { location, bond },
)
})
.collect(),
valid_until: SystemTime::now() + Duration::from_secs(60 * 10), // valid for 10 minutes
location_cache,
};
}
}
pub(crate) async fn retrieve_mixnodes() -> Vec<MixNodeBond> {
let client = new_validator_client();
info!("About to retrieve mixnode bonds...");
let bonds: Vec<MixNodeBond> = match client.get_cached_mixnodes().await {
Ok(result) => result,
Err(e) => {
error!("Unable to retrieve mixnode bonds: {:?}", e);
vec![]
}
};
info!("Fetched {} mixnode bonds", bonds.len());
bonds
}
// TODO: inject constants
fn new_validator_client() -> validator_client::ApiClient {
validator_client::ApiClient::new(default_api_endpoints()[0].clone())
}