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
This commit is contained in:
Jędrzej Stuczyński
2021-08-18 14:41:00 +01:00
committed by GitHub
parent eec211e038
commit a274edffba
91 changed files with 2249 additions and 2784 deletions
@@ -1,7 +1,7 @@
use thiserror::Error;
#[derive(Error, Debug)]
pub enum ValidatorAPIClientError {
pub enum ValidatorAPIError {
#[error("There was an issue with the REST request - {source}")]
ReqwestClientError {
#[from]
@@ -1,77 +1,167 @@
pub mod error;
use crate::validator_api::error::ValidatorAPIClientError;
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::validator_api::error::ValidatorAPIError;
use coconut_interface::{BlindSignRequestBody, BlindedSignatureResponse, VerificationKeyResponse};
use mixnet_contract::{GatewayBond, MixNodeBond};
use serde::{Deserialize, Serialize};
use url::Url;
pub const VALIDATOR_API_PORT: u16 = 8080;
pub const VALIDATOR_API_CACHE_VERSION: &str = "/v1";
pub(crate) const VALIDATOR_API_MIXNODES: &str = "/mixnodes";
pub(crate) const VALIDATOR_API_GATEWAYS: &str = "/gateways";
pub const VALIDATOR_API_VERIFICATION_KEY: &str = "/verification_key";
pub const VALIDATOR_API_BLIND_SIGN: &str = "/blind_sign";
pub mod error;
pub(crate) mod routes;
type PathSegments<'a> = &'a [&'a str];
pub struct Client {
url: Url,
reqwest_client: reqwest::Client,
}
impl Default for Client {
fn default() -> Self {
Client::new()
}
}
impl Client {
pub fn new() -> Self {
pub fn new(url: Url) -> Self {
let reqwest_client = reqwest::Client::new();
Self { reqwest_client }
Self {
url,
reqwest_client,
}
}
pub async fn query_validator_api<T>(
&self,
query: String,
validator_url: &Url,
) -> Result<T, ValidatorAPIClientError>
pub fn change_url(&mut self, new_url: Url) {
self.url = new_url
}
async fn query_validator_api<T>(&self, path: PathSegments<'_>) -> Result<T, ValidatorAPIError>
where
for<'a> T: Deserialize<'a>,
{
let mut validator_api_url = validator_url.clone();
validator_api_url
.set_port(Some(VALIDATOR_API_PORT))
.unwrap();
let query_url = format!("{}{}", validator_api_url.as_str(), query);
Ok(self
.reqwest_client
.get(query_url)
.send()
.await?
.json()
.await?)
let url = create_api_url(&self.url, path);
Ok(self.reqwest_client.get(url).send().await?.json().await?)
}
pub async fn post_validator_api<D, S>(
async fn post_validator_api<B, T>(
&self,
query: String,
json_body: &S,
validator_url: &Url,
) -> Result<D, ValidatorAPIClientError>
path: PathSegments<'_>,
json_body: &B,
) -> Result<T, ValidatorAPIError>
where
for<'a> D: Deserialize<'a>,
S: Serialize,
B: Serialize + ?Sized,
for<'a> T: Deserialize<'a>,
{
let mut validator_api_url = validator_url.clone();
validator_api_url
.set_port(Some(VALIDATOR_API_PORT))
.unwrap();
let query_url = format!("{}{}", validator_api_url.as_str(), query);
let url = create_api_url(&self.url, path);
Ok(self
.reqwest_client
.post(query_url)
.get(url)
.json(json_body)
.send()
.await?
.json()
.await?)
}
pub async fn get_mixnodes(&self) -> Result<Vec<MixNodeBond>, ValidatorAPIError> {
self.query_validator_api(&[routes::API_VERSION, routes::MIXNODES])
.await
}
pub async fn get_gateways(&self) -> Result<Vec<GatewayBond>, ValidatorAPIError> {
self.query_validator_api(&[routes::API_VERSION, routes::GATEWAYS])
.await
}
pub async fn blind_sign(
&self,
request_body: &BlindSignRequestBody,
) -> Result<BlindedSignatureResponse, ValidatorAPIError> {
self.post_validator_api(
&[routes::API_VERSION, routes::COCONUT_BLIND_SIGN],
request_body,
)
.await
}
pub async fn get_coconut_verification_key(
&self,
) -> Result<VerificationKeyResponse, ValidatorAPIError> {
self.query_validator_api(&[routes::API_VERSION, routes::COCONUT_VERIFICATION_KEY])
.await
}
}
// utility function that should solve the double slash problem in validator API forever.
fn create_api_url(base: &Url, segments: PathSegments<'_>) -> Url {
let mut url = base.clone();
let mut path_segments = url
.path_segments_mut()
.expect("provided validator url does not have a base!");
for segment in segments {
let segment = segment.strip_prefix('/').unwrap_or(segment);
let segment = segment.strip_suffix('/').unwrap_or(segment);
path_segments.push(segment);
}
// I don't understand why compiler couldn't figure out that it's no longer used
// and can be dropped
drop(path_segments);
url
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn creating_api_path() {
let base_url: Url = "http://foomp.com".parse().unwrap();
// works with 1 segment
assert_eq!(
"http://foomp.com/foo",
create_api_url(&base_url, &["foo"]).as_str()
);
// works with 2 segments
assert_eq!(
"http://foomp.com/foo/bar",
create_api_url(&base_url, &["foo", "bar"]).as_str()
);
// works with leading slash
assert_eq!(
"http://foomp.com/foo",
create_api_url(&base_url, &["/foo"]).as_str()
);
assert_eq!(
"http://foomp.com/foo/bar",
create_api_url(&base_url, &["/foo", "bar"]).as_str()
);
assert_eq!(
"http://foomp.com/foo/bar",
create_api_url(&base_url, &["foo", "/bar"]).as_str()
);
// works with trailing slash
assert_eq!(
"http://foomp.com/foo",
create_api_url(&base_url, &["foo/"]).as_str()
);
assert_eq!(
"http://foomp.com/foo/bar",
create_api_url(&base_url, &["foo/", "bar"]).as_str()
);
assert_eq!(
"http://foomp.com/foo/bar",
create_api_url(&base_url, &["foo", "bar/"]).as_str()
);
// works with both leading and trailing slash
assert_eq!(
"http://foomp.com/foo",
create_api_url(&base_url, &["/foo/"]).as_str()
);
assert_eq!(
"http://foomp.com/foo/bar",
create_api_url(&base_url, &["/foo/", "/bar/"]).as_str()
);
}
}
@@ -0,0 +1,11 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use network_defaults::VALIDATOR_API_VERSION;
pub const API_VERSION: &str = VALIDATOR_API_VERSION;
pub const MIXNODES: &str = "mixnodes";
pub const GATEWAYS: &str = "gateways";
pub const COCONUT_BLIND_SIGN: &str = "blind_sign";
pub const COCONUT_VERIFICATION_KEY: &str = "verification_key";