Feature/coconut feature (#805)

* 'Coconut' feature in gateway

* Enabled coconut feature in gateway-requests

* Native client coconut feature

* Ibid for socks5 client

* Ibid for wasm client

* Coconut feature flag for validator-api

* Added coconut feature flag to our CI

* build.yml typo

* Continue on windows errors

* Missing quote

* Another typo in build.yml

* Reclaiming disk space when building for windows on CI
This commit is contained in:
Jędrzej Stuczyński
2021-10-11 09:17:58 +01:00
committed by GitHub
parent 51dc8c81ed
commit 4e0e081b3e
27 changed files with 397 additions and 205 deletions
+14 -7
View File
@@ -2,7 +2,6 @@
// SPDX-License-Identifier: Apache-2.0
use crate::config::template::config_template;
use coconut_interface::{Base58, KeyPair};
use config::defaults::{
default_api_endpoints, DEFAULT_EPOCH_LENGTH, DEFAULT_FIRST_EPOCH_START,
DEFAULT_MIXNET_CONTRACT_ADDRESS,
@@ -14,6 +13,9 @@ use std::time::Duration;
use time::OffsetDateTime;
use url::Url;
#[cfg(feature = "coconut")]
use coconut_interface::{Base58, KeyPair};
mod template;
const DEFAULT_LOCAL_VALIDATOR: &str = "http://localhost:26657";
@@ -30,7 +32,6 @@ const DEFAULT_CACHE_INTERVAL: Duration = Duration::from_secs(60);
const DEFAULT_MONITOR_THRESHOLD: u8 = 60;
#[derive(Debug, Default, Deserialize, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct Config {
#[serde(default)]
base: Base,
@@ -74,7 +75,7 @@ impl NymConfig for Config {
}
#[derive(Debug, Deserialize, PartialEq, Serialize)]
#[serde(deny_unknown_fields, default)]
#[serde(default)]
pub struct Base {
local_validator: Url,
@@ -82,6 +83,7 @@ pub struct Base {
mixnet_contract_address: String,
// Avoid breaking derives for now
#[cfg(feature = "coconut")]
keypair_bs58: String,
}
@@ -92,13 +94,14 @@ impl Default for Base {
.parse()
.expect("default local validator is malformed!"),
mixnet_contract_address: DEFAULT_MIXNET_CONTRACT_ADDRESS.to_string(),
#[cfg(feature = "coconut")]
keypair_bs58: String::default(),
}
}
}
#[derive(Debug, Deserialize, PartialEq, Serialize)]
#[serde(deny_unknown_fields, default)]
#[serde(default)]
pub struct NetworkMonitor {
/// Specifies whether network monitoring service is enabled in this process.
enabled: bool,
@@ -179,7 +182,7 @@ impl Default for NetworkMonitor {
}
#[derive(Debug, Deserialize, PartialEq, Serialize)]
#[serde(deny_unknown_fields, default)]
#[serde(default)]
pub struct NodeStatusAPI {
/// Path to the database file containing uptime statuses for all mixnodes and gateways.
database_path: PathBuf,
@@ -200,7 +203,7 @@ impl Default for NodeStatusAPI {
}
#[derive(Debug, Deserialize, PartialEq, Serialize)]
#[serde(deny_unknown_fields, default)]
#[serde(default)]
pub struct TopologyCacher {
#[serde(with = "humantime_serde")]
caching_interval: Duration,
@@ -215,7 +218,7 @@ impl Default for TopologyCacher {
}
#[derive(Debug, Deserialize, PartialEq, Serialize)]
#[serde(deny_unknown_fields, default)]
#[serde(default)]
pub struct Rewarding {
/// Specifies whether rewarding service is enabled in this process.
enabled: bool,
@@ -254,6 +257,7 @@ impl Config {
Config::default()
}
#[cfg(feature = "coconut")]
pub fn keypair(&self) -> KeyPair {
KeyPair::try_from_bs58(self.base.keypair_bs58.clone()).unwrap()
}
@@ -298,6 +302,7 @@ impl Config {
self
}
#[cfg(feature = "coconut")]
pub fn with_keypair<S: Into<String>>(mut self, keypair_bs58: S) -> Self {
self.base.keypair_bs58 = keypair_bs58.into();
self
@@ -391,6 +396,8 @@ impl Config {
self.node_status_api.database_path.clone()
}
// fix dead code warnings as this method is only ever used with coconut feature
#[cfg(feature = "coconut")]
pub fn get_all_validator_api_endpoints(&self) -> Vec<Url> {
self.network_monitor.all_validator_apis.clone()
}
+30 -18
View File
@@ -16,7 +16,6 @@ use ::config::NymConfig;
use anyhow::Result;
use cache::ValidatorCache;
use clap::{App, Arg, ArgMatches};
use coconut::InternalSignRequest;
use log::{info, warn};
use rocket::fairing::AdHoc;
use rocket::http::Method;
@@ -31,8 +30,10 @@ use tokio::sync::Notify;
use url::Url;
use validator_client::nymd::SigningNymdClient;
#[cfg(feature = "coconut")]
use coconut::InternalSignRequest;
pub(crate) mod cache;
mod coconut;
pub(crate) mod config;
mod network_monitor;
mod node_status_api;
@@ -40,17 +41,22 @@ pub(crate) mod nymd_client;
mod rewarding;
pub(crate) mod storage;
#[cfg(feature = "coconut")]
mod coconut;
const MONITORING_ENABLED: &str = "enable-monitor";
const REWARDING_ENABLED: &str = "enable-rewarding";
const V4_TOPOLOGY_ARG: &str = "v4-topology-filepath";
const V6_TOPOLOGY_ARG: &str = "v6-topology-filepath";
const API_VALIDATORS_ARG: &str = "api-validators";
const DETAILED_REPORT_ARG: &str = "detailed-report";
const MIXNET_CONTRACT_ARG: &str = "mixnet-contract";
const MNEMONIC_ARG: &str = "mnemonic";
const WRITE_CONFIG_ARG: &str = "save-config";
const KEYPAIR_ARG: &str = "keypair";
const NYMD_VALIDATOR_ARG: &str = "nymd-validator";
const API_VALIDATORS_ARG: &str = "api-validators";
#[cfg(feature = "coconut")]
const KEYPAIR_ARG: &str = "keypair";
const EPOCH_LENGTH_ARG: &str = "epoch-length";
const FIRST_REWARDING_EPOCH_ARG: &str = "first-epoch";
@@ -70,7 +76,7 @@ fn parse_validators(raw: &str) -> Vec<Url> {
}
fn parse_args<'a>() -> ArgMatches<'a> {
App::new("Nym Validator API")
let base_app = App::new("Nym Validator API")
.author("Nymtech")
.arg(
Arg::with_name(MONITORING_ENABLED)
@@ -104,12 +110,6 @@ fn parse_args<'a>() -> ArgMatches<'a> {
.long(NYMD_VALIDATOR_ARG)
.takes_value(true)
)
.arg(
Arg::with_name(API_VALIDATORS_ARG)
.help("specifies list of all validators on the network issuing coconut credentials. Ensure they are properly ordered")
.long(API_VALIDATORS_ARG)
.takes_value(true)
)
.arg(Arg::with_name(MIXNET_CONTRACT_ARG)
.long(MIXNET_CONTRACT_ARG)
.help("Address of the validator contract managing the network")
@@ -134,10 +134,10 @@ fn parse_args<'a>() -> ArgMatches<'a> {
.short("w")
)
.arg(
Arg::with_name(KEYPAIR_ARG)
.help("Path to the secret key file")
Arg::with_name(API_VALIDATORS_ARG)
.help("specifies list of all validators on the network issuing coconut credentials. Ensure they are properly ordered")
.long(API_VALIDATORS_ARG)
.takes_value(true)
.long(KEYPAIR_ARG)
)
.arg(
Arg::with_name(FIRST_REWARDING_EPOCH_ARG)
@@ -159,9 +159,17 @@ fn parse_args<'a>() -> ArgMatches<'a> {
.takes_value(true)
.long(REWARDING_MONITOR_THRESHOLD_ARG)
.requires(REWARDING_ENABLED)
)
);
.get_matches()
#[cfg(feature = "coconut")]
let base_app = base_app.arg(
Arg::with_name(KEYPAIR_ARG)
.help("Path to the secret key file")
.takes_value(true)
.long(KEYPAIR_ARG),
);
base_app.get_matches()
}
async fn wait_for_interrupt() {
@@ -264,6 +272,8 @@ fn override_config(mut config: Config, matches: &ArgMatches) -> Config {
if matches.is_present(DETAILED_REPORT_ARG) {
config = config.with_detailed_network_monitor_report(true)
}
#[cfg(feature = "coconut")]
if let Some(keypair_path) = matches.value_of(KEYPAIR_ARG) {
let keypair_bs58 = std::fs::read_to_string(keypair_path)
.unwrap()
@@ -377,8 +387,10 @@ async fn setup_rocket(config: &Config, liftoff_notify: Arc<Notify>) -> Result<Ro
let rocket = rocket::build()
.attach(setup_cors()?)
.attach(setup_liftoff_notify(liftoff_notify))
.attach(ValidatorCache::stage())
.attach(InternalSignRequest::stage(config.keypair()));
.attach(ValidatorCache::stage());
#[cfg(feature = "coconut")]
let rocket = rocket.attach(InternalSignRequest::stage(config.keypair()));
// see if we should start up network monitor and if so, attach the node status api
if config.get_network_monitor_enabled() {
+12 -6
View File
@@ -15,9 +15,6 @@ use crate::network_monitor::monitor::summary_producer::SummaryProducer;
use crate::network_monitor::monitor::Monitor;
use crate::network_monitor::tested_network::TestedNetwork;
use crate::storage::NodeStatusStorage;
use coconut_interface::Credential;
use credentials::bandwidth::prepare_for_spending;
use credentials::obtain_aggregate_verification_key;
use crypto::asymmetric::{encryption, identity};
use futures::channel::mpsc;
use log::info;
@@ -25,6 +22,11 @@ use nymsphinx::addressing::clients::Recipient;
use std::sync::Arc;
use topology::NymTopology;
#[cfg(feature = "coconut")]
use coconut_interface::Credential;
#[cfg(feature = "coconut")]
use credentials::{bandwidth::prepare_for_spending, obtain_aggregate_verification_key};
pub(crate) mod chunker;
pub(crate) mod gateways_reader;
pub(crate) mod monitor;
@@ -90,6 +92,7 @@ impl<'a> NetworkMonitorBuilder<'a> {
*encryption_keypair.public_key(),
);
#[cfg(feature = "coconut")]
let bandwidth_credential =
TEMPORARY_obtain_bandwidth_credential(self.config, identity_keypair.public_key()).await;
@@ -97,8 +100,9 @@ impl<'a> NetworkMonitorBuilder<'a> {
self.config,
gateway_status_update_sender,
Arc::clone(&identity_keypair),
bandwidth_credential,
self.config.get_gateway_sending_rate(),
#[cfg(feature = "coconut")]
bandwidth_credential,
);
let received_processor = new_received_processor(
@@ -163,6 +167,7 @@ fn new_packet_preparer(
// SECURITY:
// this implies we are re-using the same credential for all gateways all the time (which unfortunately is true!)
#[cfg(feature = "coconut")]
#[allow(non_snake_case)]
async fn TEMPORARY_obtain_bandwidth_credential(
config: &Config,
@@ -192,17 +197,18 @@ fn new_packet_sender(
config: &Config,
gateways_status_updater: GatewayClientUpdateSender,
local_identity: Arc<identity::KeyPair>,
bandwidth_credential: Credential,
max_sending_rate: usize,
#[cfg(feature = "coconut")] bandwidth_credential: Credential,
) -> PacketSender {
PacketSender::new(
gateways_status_updater,
local_identity,
bandwidth_credential,
config.get_gateway_response_timeout(),
config.get_gateway_connection_timeout(),
config.get_max_concurrent_gateway_clients(),
max_sending_rate,
#[cfg(feature = "coconut")]
bandwidth_credential,
)
}
@@ -2,7 +2,6 @@
// SPDX-License-Identifier: Apache-2.0
use crate::network_monitor::monitor::receiver::{GatewayClientUpdate, GatewayClientUpdateSender};
use coconut_interface::Credential;
use crypto::asymmetric::identity::{self, PUBLIC_KEY_LENGTH};
use futures::channel::mpsc;
use futures::stream::{self, FuturesUnordered, StreamExt};
@@ -22,6 +21,9 @@ use std::task::Poll;
use std::time::Duration;
use tokio::time::Instant;
#[cfg(feature = "coconut")]
use coconut_interface::Credential;
const TIME_CHUNK_SIZE: Duration = Duration::from_millis(50);
pub(crate) struct GatewayPackets {
@@ -71,7 +73,8 @@ struct FreshGatewayClientData {
// SECURITY:
// since currently we have no double spending protection, just to get things running
// we're re-using the same credential for all gateways all the time. THIS IS VERY BAD!!
bandwidth_credential: Credential,
#[cfg(feature = "coconut")]
coconut_bandwidth_credential: Credential,
}
pub(crate) struct PacketSender {
@@ -93,11 +96,11 @@ impl PacketSender {
pub(crate) fn new(
gateways_status_updater: GatewayClientUpdateSender,
local_identity: Arc<identity::KeyPair>,
bandwidth_credential: Credential,
gateway_response_timeout: Duration,
gateway_connection_timeout: Duration,
max_concurrent_clients: usize,
max_sending_rate: usize,
#[cfg(feature = "coconut")] coconut_bandwidth_credential: Credential,
) -> Self {
PacketSender {
active_gateway_clients: HashMap::new(),
@@ -105,7 +108,8 @@ impl PacketSender {
gateways_status_updater,
local_identity,
gateway_response_timeout,
bandwidth_credential,
#[cfg(feature = "coconut")]
coconut_bandwidth_credential,
}),
gateway_connection_timeout,
max_concurrent_clients,
@@ -137,7 +141,6 @@ impl PacketSender {
message_sender,
ack_sender,
fresh_gateway_client_data.gateway_response_timeout,
fresh_gateway_client_data.bandwidth_credential.clone(),
),
(message_receiver, ack_receiver),
)
@@ -230,7 +233,14 @@ impl PacketSender {
// (an actual bug we experienced)
match tokio::time::timeout(
gateway_connection_timeout,
new_client.authenticate_and_start(),
new_client.authenticate_and_start(
#[cfg(feature = "coconut")]
Some(
fresh_gateway_client_data
.coconut_bandwidth_credential
.clone(),
),
),
)
.await
{