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
+96 -8
View File
@@ -5,7 +5,7 @@ on: [push, pull_request]
jobs:
build:
runs-on: ${{ matrix.os }}
continue-on-error: ${{ matrix.rust == 'nightly' || matrix.rust == 'beta' }}
continue-on-error: ${{ matrix.rust == 'nightly' || matrix.rust == 'beta' || matrix.os == 'windows-latest' }}
strategy:
matrix:
rust: [stable, beta, nightly]
@@ -16,33 +16,121 @@ jobs:
run: sudo apt-get update && sudo apt-get install libwebkit2gtk-4.0-dev build-essential curl wget libssl-dev libgtk-3-dev squashfs-tools
if: matrix.os == 'ubuntu-latest'
- uses: actions/checkout@v2
- name: Check out repository code
uses: actions/checkout@v2
- uses: actions-rs/toolchain@v1
- name: Install rust toolchain
uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: ${{ matrix.rust }}
override: true
components: rustfmt, clippy
- uses: actions-rs/cargo@v1
- name: Build all binaries
uses: actions-rs/cargo@v1
with:
command: build
args: --all
- uses: actions-rs/cargo@v1
- name: Run all tests
uses: actions-rs/cargo@v1
with:
command: test
args: --all
- uses: actions-rs/cargo@v1
- name: Check formatting
uses: actions-rs/cargo@v1
with:
command: fmt
args: --all -- --check
- uses: actions-rs/cargo@v1
- name: Run clippy
uses: actions-rs/cargo@v1
if: ${{ matrix.rust != 'nightly' }}
with:
command: clippy
args: -- -D warnings
# COCONUT stuff
- name: Reclaim some disk space (because Windows is being annoying)
uses: actions-rs/cargo@v1
if: ${{ matrix.os == 'windows-latest' }}
with:
command: clean
# BUILD
- name: Build gateway with coconut feature
uses: actions-rs/cargo@v1
with:
command: build
args: --bin nym-gateway --features=coconut
- name: Build native client with coconut feature
uses: actions-rs/cargo@v1
with:
command: build
args: --bin nym-client --features=coconut
- name: Build socks5 client with coconut feature
uses: actions-rs/cargo@v1
with:
command: build
args: --bin nym-socks5-client --features=coconut
- name: Build validator-api with coconut feature
uses: actions-rs/cargo@v1
with:
command: build
args: --bin nym-validator-api --features=coconut
# TEST
- name: Test gateway with coconut feature
uses: actions-rs/cargo@v1
with:
command: test
args: --bin nym-gateway --features=coconut
- name: Test native client with coconut feature
uses: actions-rs/cargo@v1
with:
command: test
args: --bin nym-client --features=coconut
- name: Test socks5 client with coconut feature
uses: actions-rs/cargo@v1
with:
command: test
args: --bin nym-socks5-client --features=coconut
- name: Test validator-api with coconut feature
uses: actions-rs/cargo@v1
with:
command: test
args: --bin nym-validator-api --features=coconut
# CLIPPY
- name: Run clippy on gateway with coconut feature
uses: actions-rs/cargo@v1
with:
command: clippy
args: --bin nym-gateway --features=coconut -- -D warnings
- name: Run clippy on native client with coconut feature
uses: actions-rs/cargo@v1
with:
command: clippy
args: --bin nym-client --features=coconut -- -D warnings
- name: Run clippy on socks5 client with coconut feature
uses: actions-rs/cargo@v1
with:
command: clippy
args: --bin nym-socks5-client --features=coconut -- -D warnings
- name: Run clippy on validator-api with coconut feature
uses: actions-rs/cargo@v1
with:
command: clippy
args: --bin nym-validator-api --features=coconut -- -D warnings
+5
View File
@@ -21,6 +21,11 @@ jobs:
command: build
args: --manifest-path clients/webassembly/Cargo.toml --target wasm32-unknown-unknown
- uses: actions-rs/cargo@v1
with:
command: build
args: --manifest-path clients/webassembly/Cargo.toml --target wasm32-unknown-unknown --features=coconut
# for some reason this does not seem to work correctly, leave it for later, building is good enough for now
# - uses: actions-rs/cargo@v1
# with:
+5 -2
View File
@@ -31,8 +31,8 @@ tokio-tungstenite = "0.14" # websocket
## internal
client-core = { path = "../client-core" }
coconut-interface = { path = "../../common/coconut-interface" }
credentials = { path = "../../common/credentials" }
coconut-interface = { path = "../../common/coconut-interface", optional = true }
credentials = { path = "../../common/credentials", optional = true }
config = { path = "../../common/config" }
crypto = { path = "../../common/crypto" }
gateway-client = { path = "../../common/client-libs/gateway-client" }
@@ -44,5 +44,8 @@ websocket-requests = { path = "websocket-requests" }
validator-client = { path = "../../common/client-libs/validator-client" }
version-checker = { path = "../../common/version-checker" }
[features]
coconut = ["coconut-interface", "credentials", "gateway-requests/coconut", "gateway-client/coconut"]
[dev-dependencies]
serde_json = "1.0" # for the "textsend" example
+13 -7
View File
@@ -22,9 +22,6 @@ use client_core::client::topology_control::{
TopologyAccessor, TopologyRefresher, TopologyRefresherConfig,
};
use client_core::config::persistence::key_pathfinder::ClientKeyPathfinder;
use coconut_interface::Credential;
use credentials::bandwidth::prepare_for_spending;
use credentials::obtain_aggregate_verification_key;
use crypto::asymmetric::identity;
use futures::channel::mpsc;
use gateway_client::{
@@ -38,6 +35,11 @@ use nymsphinx::anonymous_replies::ReplySurb;
use nymsphinx::receiver::ReconstructedMessage;
use tokio::runtime::Runtime;
#[cfg(feature = "coconut")]
use coconut_interface::Credential;
#[cfg(feature = "coconut")]
use credentials::{bandwidth::prepare_for_spending, obtain_aggregate_verification_key};
pub(crate) mod config;
pub struct NymClient {
@@ -166,7 +168,8 @@ impl NymClient {
.start(self.runtime.handle())
}
async fn prepare_credential(&self) -> Credential {
#[cfg(feature = "coconut")]
async fn prepare_coconut_credential(&self) -> Credential {
let verification_key = obtain_aggregate_verification_key(
&self.config.get_base().get_validator_api_endpoints(),
)
@@ -208,7 +211,8 @@ impl NymClient {
.expect("provided gateway id is invalid!");
self.runtime.block_on(async {
let coconut_credential = self.prepare_credential().await;
#[cfg(feature = "coconut")]
let coconut_credential = self.prepare_coconut_credential().await;
let mut gateway_client = GatewayClient::new(
gateway_address,
@@ -218,11 +222,13 @@ impl NymClient {
mixnet_message_sender,
ack_sender,
self.config.get_base().get_gateway_response_timeout(),
coconut_credential,
);
gateway_client
.authenticate_and_start()
.authenticate_and_start(
#[cfg(feature = "coconut")]
Some(coconut_credential),
)
.await
.expect("could not authenticate and start up the gateway connection");
+2 -29
View File
@@ -6,10 +6,7 @@ use crate::commands::override_config;
use clap::{App, Arg, ArgMatches};
use client_core::client::key_manager::KeyManager;
use client_core::config::persistence::key_pathfinder::ClientKeyPathfinder;
use coconut_interface::Credential;
use config::NymConfig;
use credentials::bandwidth::prepare_for_spending;
use credentials::obtain_aggregate_verification_key;
use crypto::asymmetric::{encryption, identity};
use gateway_client::GatewayClient;
use gateway_requests::registration::handshake::SharedKeys;
@@ -60,34 +57,15 @@ pub fn command_args<'a, 'b>() -> clap::App<'a, 'b> {
)
}
// this behaviour should definitely be changed, we shouldn't
// need to get bandwidth credential for registration
async fn prepare_temporary_credential(validators: &[Url], raw_identity: &[u8]) -> Credential {
let verification_key = obtain_aggregate_verification_key(validators)
.await
.expect("could not obtain aggregate verification key of validators");
let bandwidth_credential = credentials::bandwidth::obtain_signature(raw_identity, validators)
.await
.expect("could not obtain bandwidth credential");
prepare_for_spending(raw_identity, &bandwidth_credential, &verification_key)
.expect("could not prepare out bandwidth credential for spending")
}
async fn register_with_gateway(
gateway: &gateway::Node,
our_identity: Arc<identity::KeyPair>,
validator_urls: Vec<Url>,
) -> Arc<SharedKeys> {
let timeout = Duration::from_millis(1500);
let coconut_credential =
prepare_temporary_credential(&validator_urls, &our_identity.public_key().to_bytes()).await;
let mut gateway_client = GatewayClient::new_init(
gateway.clients_address(),
gateway.identity_key,
our_identity.clone(),
coconut_credential,
timeout,
);
gateway_client
@@ -210,13 +188,8 @@ pub fn execute(matches: &ArgMatches) {
config
.get_base_mut()
.with_gateway_id(gate_details.identity_key.to_base58_string());
let validator_urls = config.get_base().get_validator_api_endpoints();
let shared_keys = register_with_gateway(
&gate_details,
key_manager.identity_keypair(),
validator_urls,
)
.await;
let shared_keys =
register_with_gateway(&gate_details, key_manager.identity_keypair()).await;
(shared_keys, gate_details.clients_address())
};
+5 -2
View File
@@ -24,8 +24,8 @@ url = "2.2"
# internal
client-core = { path = "../client-core" }
coconut-interface = { path = "../../common/coconut-interface" }
credentials = { path = "../../common/credentials" }
coconut-interface = { path = "../../common/coconut-interface", optional = true }
credentials = { path = "../../common/credentials", optional = true }
config = { path = "../../common/config" }
crypto = { path = "../../common/crypto" }
gateway-client = { path = "../../common/client-libs/gateway-client" }
@@ -38,3 +38,6 @@ pemstore = { path = "../../common/pemstore" }
proxy-helpers = { path = "../../common/socks5/proxy-helpers" }
validator-client = { path = "../../common/client-libs/validator-client" }
version-checker = { path = "../../common/version-checker" }
[features]
coconut = ["coconut-interface", "credentials", "gateway-requests/coconut", "gateway-client/coconut"]
+13 -7
View File
@@ -23,9 +23,6 @@ use client_core::client::topology_control::{
TopologyAccessor, TopologyRefresher, TopologyRefresherConfig,
};
use client_core::config::persistence::key_pathfinder::ClientKeyPathfinder;
use coconut_interface::Credential;
use credentials::bandwidth::prepare_for_spending;
use credentials::obtain_aggregate_verification_key;
use crypto::asymmetric::identity;
use futures::channel::mpsc;
use gateway_client::{
@@ -37,6 +34,11 @@ use nymsphinx::addressing::clients::Recipient;
use nymsphinx::addressing::nodes::NodeIdentity;
use tokio::runtime::Runtime;
#[cfg(feature = "coconut")]
use coconut_interface::Credential;
#[cfg(feature = "coconut")]
use credentials::{bandwidth::prepare_for_spending, obtain_aggregate_verification_key};
pub(crate) mod config;
pub struct NymClient {
@@ -154,7 +156,8 @@ impl NymClient {
.start(self.runtime.handle())
}
async fn prepare_credential(&self) -> Credential {
#[cfg(feature = "coconut")]
async fn prepare_coconut_credential(&self) -> Credential {
let verification_key = obtain_aggregate_verification_key(
&self.config.get_base().get_validator_api_endpoints(),
)
@@ -196,7 +199,8 @@ impl NymClient {
.expect("provided gateway id is invalid!");
self.runtime.block_on(async {
let coconut_credential = self.prepare_credential().await;
#[cfg(feature = "coconut")]
let coconut_credential = self.prepare_coconut_credential().await;
let mut gateway_client = GatewayClient::new(
gateway_address,
@@ -206,11 +210,13 @@ impl NymClient {
mixnet_message_sender,
ack_sender,
self.config.get_base().get_gateway_response_timeout(),
coconut_credential,
);
gateway_client
.authenticate_and_start()
.authenticate_and_start(
#[cfg(feature = "coconut")]
Some(coconut_credential),
)
.await
.expect("could not authenticate and start up the gateway connection");
+2 -29
View File
@@ -6,10 +6,7 @@ use crate::commands::override_config;
use clap::{App, Arg, ArgMatches};
use client_core::client::key_manager::KeyManager;
use client_core::config::persistence::key_pathfinder::ClientKeyPathfinder;
use coconut_interface::Credential;
use config::NymConfig;
use credentials::bandwidth::prepare_for_spending;
use credentials::obtain_aggregate_verification_key;
use crypto::asymmetric::{encryption, identity};
use gateway_client::GatewayClient;
use gateway_requests::registration::handshake::SharedKeys;
@@ -60,34 +57,15 @@ pub fn command_args<'a, 'b>() -> clap::App<'a, 'b> {
)
}
// this behaviour should definitely be changed, we shouldn't
// need to get bandwidth credential for registration
async fn prepare_temporary_credential(validators: &[Url], raw_identity: &[u8]) -> Credential {
let verification_key = obtain_aggregate_verification_key(validators)
.await
.expect("could not obtain aggregate verification key of validators");
let bandwidth_credential = credentials::bandwidth::obtain_signature(raw_identity, validators)
.await
.expect("could not obtain bandwidth credential");
prepare_for_spending(raw_identity, &bandwidth_credential, &verification_key)
.expect("could not prepare out bandwidth credential for spending")
}
async fn register_with_gateway(
gateway: &gateway::Node,
our_identity: Arc<identity::KeyPair>,
validator_urls: Vec<Url>,
) -> Arc<SharedKeys> {
let timeout = Duration::from_millis(1500);
let coconut_credential =
prepare_temporary_credential(&validator_urls, &our_identity.public_key().to_bytes()).await;
let mut gateway_client = GatewayClient::new_init(
gateway.clients_address(),
gateway.identity_key,
our_identity.clone(),
coconut_credential,
timeout,
);
gateway_client
@@ -211,13 +189,8 @@ pub fn execute(matches: &ArgMatches) {
config
.get_base_mut()
.with_gateway_id(gate_details.identity_key.to_base58_string());
let validator_urls = config.get_base().get_validator_api_endpoints();
let shared_keys = register_with_gateway(
&gate_details,
key_manager.identity_keypair(),
validator_urls,
)
.await;
let shared_keys =
register_with_gateway(&gate_details, key_manager.identity_keypair()).await;
(shared_keys, gate_details.clients_address())
};
+3 -2
View File
@@ -14,6 +14,7 @@ crate-type = ["cdylib", "rlib"]
[features]
default = ["console_error_panic_hook"]
offline-test = []
coconut = ["coconut-interface", "credentials", "gateway-client/coconut"]
[dependencies]
futures = "0.3"
@@ -25,8 +26,8 @@ rand = { version = "0.7.3", features = ["wasm-bindgen"] }
url = "2.2"
# internal
coconut-interface = { path = "../../common/coconut-interface" }
credentials = { path = "../../common/credentials" }
coconut-interface = { path = "../../common/coconut-interface", optional = true }
credentials = { path = "../../common/credentials", optional = true }
crypto = { path = "../../common/crypto" }
nymsphinx = { path = "../../common/nymsphinx" }
topology = { path = "../../common/topology" }
+22 -11
View File
@@ -1,9 +1,6 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
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 gateway_client::GatewayClient;
@@ -20,6 +17,11 @@ use wasm_bindgen::prelude::*;
use wasm_bindgen_futures::spawn_local;
use wasm_utils::{console_log, console_warn};
#[cfg(feature = "coconut")]
use coconut_interface::Credential;
#[cfg(feature = "coconut")]
use credentials::{bandwidth::prepare_for_spending, obtain_aggregate_verification_key};
pub(crate) mod received_processor;
const DEFAULT_AVERAGE_PACKET_DELAY: Duration = Duration::from_millis(200);
@@ -101,7 +103,8 @@ impl NymClient {
self.self_recipient().to_string()
}
async fn prepare_credential(validators: &[Url], identity_bytes: &[u8]) -> Credential {
#[cfg(feature = "coconut")]
async fn prepare_coconut_credential(validators: &[Url], identity_bytes: &[u8]) -> Credential {
let verification_key = obtain_aggregate_verification_key(validators)
.await
.expect("could not obtain aggregate verification key of validators");
@@ -119,17 +122,23 @@ impl NymClient {
// Right now it's impossible to have async exported functions to take `&self` rather than self
pub async fn initial_setup(self) -> Self {
let validator_server = self.validator_server.clone();
let identity_public_key = self.identity.public_key().clone();
#[cfg(feature = "coconut")]
let coconut_credential = {
let validator_server = self.validator_server.clone();
let identity_public_key = self.identity.public_key().clone();
Self::prepare_coconut_credential(
&vec![validator_server],
&identity_public_key.to_bytes(),
)
.await
};
let mut client = self.get_and_update_topology().await;
let gateway = client.choose_gateway();
let (mixnet_messages_sender, mixnet_messages_receiver) = mpsc::unbounded();
let (ack_sender, ack_receiver) = mpsc::unbounded();
let coconut_credential =
Self::prepare_credential(&vec![validator_server], &identity_public_key.to_bytes())
.await;
let mut gateway_client = GatewayClient::new(
gateway.clients_address(),
Arc::clone(&client.identity),
@@ -138,11 +147,13 @@ impl NymClient {
mixnet_messages_sender,
ack_sender,
DEFAULT_GATEWAY_RESPONSE_TIMEOUT,
coconut_credential,
);
gateway_client
.authenticate_and_start()
.authenticate_and_start(
#[cfg(feature = "coconut")]
Some(coconut_credential),
)
.await
.expect("could not authenticate and start up the gateway connection");
+4 -1
View File
@@ -17,7 +17,7 @@ rand = { version = "0.7.3", features = ["wasm-bindgen"] }
crypto = { path = "../../crypto" }
gateway-requests = { path = "../../../gateway/gateway-requests" }
nymsphinx = { path = "../../nymsphinx" }
coconut-interface = { path = "../../coconut-interface" }
coconut-interface = { path = "../../coconut-interface", optional = true }
[dependencies.tungstenite]
version = "0.13"
@@ -57,3 +57,6 @@ features = ["js"]
[dev-dependencies]
# for tests
#url = "2.1"
[features]
coconut = ["gateway-requests/coconut", "coconut-interface"]
+52 -33
View File
@@ -8,7 +8,6 @@ pub use crate::packet_router::{
AcknowledgementReceiver, AcknowledgementSender, MixnetMessageReceiver, MixnetMessageSender,
};
use crate::socket_state::{PartiallyDelegated, SocketState};
use coconut_interface::Credential;
use crypto::asymmetric::identity;
use futures::{FutureExt, SinkExt, StreamExt};
use gateway_requests::authentication::encrypted_address::EncryptedAddressBytes;
@@ -31,6 +30,9 @@ use fluvio_wasm_timer as wasm_timer;
#[cfg(target_arch = "wasm32")]
use wasm_utils::websocket::JSWebsocket;
#[cfg(feature = "coconut")]
use coconut_interface::Credential;
const DEFAULT_RECONNECTION_ATTEMPTS: usize = 10;
const DEFAULT_RECONNECTION_BACKOFF: Duration = Duration::from_secs(5);
@@ -53,7 +55,6 @@ pub struct GatewayClient {
reconnection_attempts: usize,
/// Delay between each subsequent reconnection attempt.
reconnection_backoff: Duration,
coconut_credential: Credential,
}
impl GatewayClient {
@@ -67,7 +68,6 @@ impl GatewayClient {
mixnet_message_sender: MixnetMessageSender,
ack_sender: AcknowledgementSender,
response_timeout_duration: Duration,
coconut_credential: Credential,
) -> Self {
GatewayClient {
authenticated: false,
@@ -82,7 +82,6 @@ impl GatewayClient {
should_reconnect_on_failure: true,
reconnection_attempts: DEFAULT_RECONNECTION_ATTEMPTS,
reconnection_backoff: DEFAULT_RECONNECTION_BACKOFF,
coconut_credential,
}
}
@@ -103,7 +102,6 @@ impl GatewayClient {
gateway_address: String,
gateway_identity: identity::PublicKey,
local_identity: Arc<identity::KeyPair>,
coconut_credential: Credential,
response_timeout_duration: Duration,
) -> Self {
use futures::channel::mpsc;
@@ -127,7 +125,6 @@ impl GatewayClient {
should_reconnect_on_failure: false,
reconnection_attempts: DEFAULT_RECONNECTION_ATTEMPTS,
reconnection_backoff: DEFAULT_RECONNECTION_BACKOFF,
coconut_credential,
}
}
@@ -199,7 +196,14 @@ impl GatewayClient {
for i in 1..self.reconnection_attempts {
info!("attempt {}...", i);
if self.authenticate_and_start().await.is_ok() {
if self
.authenticate_and_start(
#[cfg(feature = "coconut")]
None,
)
.await
.is_ok()
{
info!("managed to reconnect!");
return Ok(());
}
@@ -218,7 +222,13 @@ impl GatewayClient {
// final attempt (done separately to be able to return a proper error)
info!("attempt {}", self.reconnection_attempts);
match self.authenticate_and_start().await {
match self
.authenticate_and_start(
#[cfg(feature = "coconut")]
None,
)
.await
{
Ok(_) => {
info!("managed to reconnect!");
Ok(())
@@ -455,7 +465,11 @@ impl GatewayClient {
}
}
pub async fn claim_bandwidth(&mut self) -> Result<(), GatewayClientError> {
#[cfg(feature = "coconut")]
pub async fn claim_coconut_bandwidth(
&mut self,
coconut_credential: Credential,
) -> Result<(), GatewayClientError> {
if !self.authenticated {
return Err(GatewayClientError::NotAuthenticated);
}
@@ -466,8 +480,8 @@ impl GatewayClient {
let mut rng = OsRng;
let iv = IV::new_random(&mut rng);
let msg = ClientControlRequest::new_enc_bandwidth_credential(
&self.coconut_credential,
let msg = ClientControlRequest::new_enc_coconut_bandwidth_credential(
&coconut_credential,
self.shared_key.as_ref().unwrap(),
iv,
)
@@ -527,15 +541,10 @@ impl GatewayClient {
}
}
pub async fn send_ping_message(&mut self) -> Result<(), GatewayClientError> {
if !self.connection.is_established() {
return Err(GatewayClientError::ConnectionNotEstablished);
}
// as per RFC6455 section 5.5.2, `Ping frame MAY include "Application data".`
// so we don't need to include any here.
let msg = Message::Ping(Vec::new());
async fn send_with_reconnection_on_failure(
&mut self,
msg: Message,
) -> Result<(), GatewayClientError> {
if let Err(err) = self.send_websocket_message_without_response(msg).await {
if err.is_closed_connection() && self.should_reconnect_on_failure {
info!("Going to attempt a reconnection");
@@ -548,6 +557,17 @@ impl GatewayClient {
}
}
pub async fn send_ping_message(&mut self) -> Result<(), GatewayClientError> {
if !self.connection.is_established() {
return Err(GatewayClientError::ConnectionNotEstablished);
}
// as per RFC6455 section 5.5.2, `Ping frame MAY include "Application data".`
// so we don't need to include any here.
let msg = Message::Ping(Vec::new());
self.send_with_reconnection_on_failure(msg).await
}
// TODO: possibly make responses optional
pub async fn send_mix_packet(
&mut self,
@@ -569,17 +589,7 @@ impl GatewayClient {
.as_ref()
.expect("no shared key present even though we're authenticated!"),
);
if let Err(err) = self.send_websocket_message_without_response(msg).await {
if err.is_closed_connection() && self.should_reconnect_on_failure {
info!("Going to attempt a reconnection");
self.attempt_reconnection().await
} else {
Err(err)
}
} else {
Ok(())
}
self.send_with_reconnection_on_failure(msg).await
}
async fn recover_socket_connection(&mut self) -> Result<(), GatewayClientError> {
@@ -634,12 +644,21 @@ impl GatewayClient {
Ok(())
}
pub async fn authenticate_and_start(&mut self) -> Result<Arc<SharedKeys>, GatewayClientError> {
pub async fn authenticate_and_start(
&mut self,
#[cfg(feature = "coconut")] coconut_credential: Option<Credential>,
) -> Result<Arc<SharedKeys>, GatewayClientError> {
if !self.connection.is_established() {
self.establish_connection().await?;
}
let shared_key = self.perform_initial_authentication().await?;
self.claim_bandwidth().await?;
#[cfg(feature = "coconut")]
{
if let Some(coconut_credential) = coconut_credential {
self.claim_coconut_bandwidth(coconut_credential).await?;
}
}
// this call is NON-blocking
self.start_listening_for_mixnet_messages()?;
+5 -2
View File
@@ -29,8 +29,8 @@ url = { version = "2.2", features = [ "serde" ] }
sqlx = { version = "0.5", features = ["runtime-tokio-rustls", "sqlite", "macros", "migrate"] }
# internal
coconut-interface = { path = "../common/coconut-interface" }
credentials = { path = "../common/credentials" }
coconut-interface = { path = "../common/coconut-interface" , optional = true}
credentials = { path = "../common/credentials" , optional = true}
config = { path = "../common/config" }
crypto = { path = "../common/crypto" }
gateway-requests = { path = "gateway-requests" }
@@ -41,6 +41,9 @@ pemstore = { path = "../common/pemstore" }
validator-client = { path = "../common/client-libs/validator-client" }
version-checker = { path = "../common/version-checker" }
[features]
coconut = ["coconut-interface", "credentials", "gateway-requests/coconut"]
[build-dependencies]
tokio = { version = "1.4", features = ["rt-multi-thread", "macros"] }
sqlx = { version = "0.5", features = ["runtime-tokio-rustls", "sqlite", "macros", "migrate"] }
+5 -2
View File
@@ -23,8 +23,11 @@ bincode = "1.3"
crypto = { path = "../../common/crypto" }
pemstore = { path = "../../common/pemstore" }
coconut-interface = { path = "../../common/coconut-interface" }
credentials = { path = "../../common/credentials"}
coconut-interface = { path = "../../common/coconut-interface", optional = true }
credentials = { path = "../../common/credentials", optional = true }
[features]
coconut = ["coconut-interface", "credentials"]
[dependencies.tungstenite]
version = "0.13.0"
+10 -5
View File
@@ -5,7 +5,6 @@ use crate::authentication::encrypted_address::EncryptedAddressBytes;
use crate::iv::IV;
use crate::registration::handshake::SharedKeys;
use crate::GatewayMacSize;
use coconut_interface::Credential;
use crypto::generic_array::typenum::Unsigned;
use crypto::hmac::recompute_keyed_hmac_and_verify_tag;
use crypto::symmetric::stream_cipher;
@@ -21,6 +20,9 @@ use std::{
};
use tungstenite::protocol::Message;
#[cfg(feature = "coconut")]
use coconut_interface::Credential;
#[derive(Serialize, Deserialize, Debug)]
#[serde(tag = "type", rename_all = "camelCase")]
pub enum RegistrationHandshake {
@@ -115,7 +117,8 @@ pub enum ClientControlRequest {
},
#[serde(alias = "handshakePayload")]
RegisterHandshakeInitRequest { data: Vec<u8> },
BandwidthCredential {
#[cfg(feature = "coconut")]
CoconutBandwidthCredential {
enc_credential: Vec<u8>,
iv: Vec<u8>,
},
@@ -134,7 +137,8 @@ impl ClientControlRequest {
}
}
pub fn new_enc_bandwidth_credential(
#[cfg(feature = "coconut")]
pub fn new_enc_coconut_bandwidth_credential(
credential: &Credential,
shared_key: &SharedKeys,
iv: IV,
@@ -144,7 +148,7 @@ impl ClientControlRequest {
let enc_credential =
shared_key.encrypt_and_tag(&serialized_credential, Some(iv.inner()));
Some(ClientControlRequest::BandwidthCredential {
Some(ClientControlRequest::CoconutBandwidthCredential {
enc_credential,
iv: iv.to_bytes(),
})
@@ -153,7 +157,8 @@ impl ClientControlRequest {
}
}
pub fn try_from_enc_bandwidth_credential(
#[cfg(feature = "coconut")]
pub fn try_from_enc_coconut_bandwidth_credential(
enc_credential: Vec<u8>,
shared_key: &SharedKeys,
iv: IV,
+3 -1
View File
@@ -2,5 +2,7 @@
// SPDX-License-Identifier: Apache-2.0
pub(crate) mod active_clients;
mod bandwidth;
pub(crate) mod websocket;
#[cfg(feature = "coconut")]
mod bandwidth;
@@ -1,12 +1,11 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::node::client_handling::bandwidth::Bandwidth;
use crate::node::client_handling::websocket::connection_handler::{ClientDetails, FreshHandler};
use crate::node::client_handling::websocket::message_receiver::MixMessageReceiver;
use crate::node::storage::error::StorageError;
use futures::StreamExt;
use gateway_requests::iv::{IVConversionError, IV};
use gateway_requests::iv::IVConversionError;
use gateway_requests::types::{BinaryRequest, ServerResponse};
use gateway_requests::{ClientControlRequest, GatewayRequestsError};
use log::*;
@@ -18,6 +17,11 @@ use thiserror::Error;
use tokio::io::{AsyncRead, AsyncWrite};
use tokio_tungstenite::tungstenite::protocol::Message;
#[cfg(feature = "coconut")]
use crate::node::client_handling::bandwidth::Bandwidth;
#[cfg(feature = "coconut")]
use gateway_requests::iv::IV;
#[derive(Debug, Error)]
enum RequestHandlingError {
#[error("Internal gateway storage error")]
@@ -32,17 +36,20 @@ enum RequestHandlingError {
#[error("Provided binary request was malformed - {0}")]
InvalidTextRequest(<ClientControlRequest as TryFrom<String>>::Error),
#[error("Provided bandwidth credential did not verify correctly")]
InvalidBandwidthCredential,
#[error("Provided bandwidth credential did not have expected structure - {0}")]
BandwidthCredentialError(#[from] credentials::error::Error),
#[error("The received request is not valid in the current context")]
IllegalRequest,
#[cfg(feature = "coconut")]
#[error("Provided bandwidth credential asks for more bandwidth than it is supported to add at once (credential value: {0}, supported: {}). Try to split it before attempting again", i64::MAX)]
UnsupportedBandwidthValue(u64),
#[error("The received request is not valid in the current context")]
IllegalRequest,
#[cfg(feature = "coconut")]
#[error("Provided bandwidth credential did not verify correctly")]
InvalidCoconutBandwidthCredential,
#[cfg(feature = "coconut")]
#[error("Provided coconut bandwidth credential did not have expected structure - {0}")]
CoconutBandwidthCredentialError(#[from] credentials::error::Error),
}
impl RequestHandlingError {
@@ -110,6 +117,10 @@ where
Ok(bandwidth)
}
// note: this is not technically a "coconut" thing, but currently we have no non-coconut
// bandwidth handling and hence clippy complains about dead and unreachable code
// so whenever we introduce another form of bandwidth claim, this feature flag should get removed
#[cfg(feature = "coconut")]
/// Increases the amount of available bandwidth of the connected client by the specified value.
///
/// # Arguments
@@ -148,6 +159,7 @@ where
}
}
#[cfg(feature = "coconut")]
/// Tries to handle the received bandwidth request by checking correctness of the received data
/// and if successful, increases client's bandwidth by an appropriate amount.
///
@@ -155,20 +167,20 @@ where
///
/// * `enc_credential`: raw encrypted bandwidth credential to verify.
/// * `iv`: fresh iv used for the credential.
async fn handle_bandwidth(
async fn handle_coconut_bandwidth(
&mut self,
enc_credential: Vec<u8>,
iv: Vec<u8>,
) -> Result<ServerResponse, RequestHandlingError> {
let iv = IV::try_from_bytes(&iv)?;
let credential = ClientControlRequest::try_from_enc_bandwidth_credential(
let credential = ClientControlRequest::try_from_enc_coconut_bandwidth_credential(
enc_credential,
&self.client.shared_keys,
iv,
)?;
if !credential.verify(&self.inner.aggregated_verification_key) {
return Err(RequestHandlingError::InvalidBandwidthCredential);
return Err(RequestHandlingError::InvalidCoconutBandwidthCredential);
}
let bandwidth = Bandwidth::try_from(credential)?;
@@ -202,10 +214,17 @@ where
&self,
mix_packet: MixPacket,
) -> Result<ServerResponse, RequestHandlingError> {
// currently we have no way for increasing bandwidth hence we shouldn't be performing
// any meaningful metering. Once we have another way of claiming bandwidth, this
// feature lock should go away
#[cfg(feature = "coconut")]
// for now let's just use actual size of the sphinx packet. there's a tiny bit of overhead
// we're not including (but it's literally like 2 bytes) when the packet is framed
let consumed_bandwidth = mix_packet.sphinx_packet().len() as i64;
#[cfg(not(feature = "coconut"))]
let consumed_bandwidth = 0;
let available_bandwidth = self.get_available_bandwidth().await?;
if available_bandwidth < consumed_bandwidth {
@@ -254,8 +273,9 @@ where
match ClientControlRequest::try_from(raw_request) {
Err(e) => RequestHandlingError::InvalidTextRequest(e).into_error_message(),
Ok(request) => match request {
ClientControlRequest::BandwidthCredential { enc_credential, iv } => {
match self.handle_bandwidth(enc_credential, iv).await {
#[cfg(feature = "coconut")]
ClientControlRequest::CoconutBandwidthCredential { enc_credential, iv } => {
match self.handle_coconut_bandwidth(enc_credential, iv).await {
Ok(response) => response.into(),
Err(err) => err.into_error_message(),
}
@@ -7,7 +7,6 @@ use crate::node::client_handling::websocket::connection_handler::{
};
use crate::node::storage::error::StorageError;
use crate::node::storage::PersistentStorage;
use coconut_interface::VerificationKey;
use crypto::asymmetric::identity;
use futures::{channel::mpsc, SinkExt, StreamExt};
use gateway_requests::authentication::encrypted_address::{
@@ -28,6 +27,9 @@ use thiserror::Error;
use tokio::io::{AsyncRead, AsyncWrite};
use tokio_tungstenite::tungstenite::{protocol::Message, Error as WsError};
#[cfg(feature = "coconut")]
use coconut_interface::VerificationKey;
#[derive(Debug, Error)]
enum InitialAuthenticationError {
#[error("Internal gateway storage error")]
@@ -67,10 +69,12 @@ pub(crate) struct FreshHandler<R, S> {
rng: R,
local_identity: Arc<identity::KeyPair>,
pub(crate) active_clients_store: ActiveClientsStore,
pub(crate) aggregated_verification_key: VerificationKey,
pub(crate) outbound_mix_sender: MixForwardingSender,
pub(crate) socket_connection: SocketStream<S>,
pub(crate) storage: PersistentStorage,
#[cfg(feature = "coconut")]
pub(crate) aggregated_verification_key: VerificationKey,
}
impl<R, S> FreshHandler<R, S>
@@ -84,9 +88,9 @@ where
conn: S,
outbound_mix_sender: MixForwardingSender,
local_identity: Arc<identity::KeyPair>,
aggregated_verification_key: VerificationKey,
storage: PersistentStorage,
active_clients_store: ActiveClientsStore,
#[cfg(feature = "coconut")] aggregated_verification_key: VerificationKey,
) -> Self {
FreshHandler {
rng,
@@ -94,8 +98,9 @@ where
outbound_mix_sender,
socket_connection: SocketStream::RawTcp(conn),
local_identity,
aggregated_verification_key,
storage,
#[cfg(feature = "coconut")]
aggregated_verification_key,
}
}
@@ -492,6 +497,11 @@ where
ClientControlRequest::RegisterHandshakeInitRequest { data } => {
self.handle_register(data).await
}
// note: this is not technically a "coconut" thing, but currently we have no non-coconut
// bandwidth handling and hence clippy complains about dead and unreachable code
// so whenever we introduce another form of bandwidth claim, this feature flag should get removed
#[cfg(feature = "coconut")]
// won't accept anything else (like bandwidth) without prior authentication
_ => Err(InitialAuthenticationError::InvalidRequest),
}
@@ -4,7 +4,6 @@
use crate::node::client_handling::active_clients::ActiveClientsStore;
use crate::node::client_handling::websocket::connection_handler::FreshHandler;
use crate::node::storage::PersistentStorage;
use coconut_interface::VerificationKey;
use crypto::asymmetric::identity;
use log::*;
use mixnet_client::forwarder::MixForwardingSender;
@@ -14,9 +13,14 @@ use std::process;
use std::sync::Arc;
use tokio::task::JoinHandle;
#[cfg(feature = "coconut")]
use coconut_interface::VerificationKey;
pub(crate) struct Listener {
address: SocketAddr,
local_identity: Arc<identity::KeyPair>,
#[cfg(feature = "coconut")]
aggregated_verification_key: VerificationKey,
}
@@ -24,11 +28,12 @@ impl Listener {
pub(crate) fn new(
address: SocketAddr,
local_identity: Arc<identity::KeyPair>,
aggregated_verification_key: VerificationKey,
#[cfg(feature = "coconut")] aggregated_verification_key: VerificationKey,
) -> Self {
Listener {
address,
local_identity,
#[cfg(feature = "coconut")]
aggregated_verification_key,
}
}
@@ -61,9 +66,10 @@ impl Listener {
socket,
outbound_mix_sender.clone(),
Arc::clone(&self.local_identity),
self.aggregated_verification_key.clone(),
storage.clone(),
active_clients_store.clone(),
#[cfg(feature = "coconut")]
self.aggregated_verification_key.clone(),
);
tokio::spawn(async move { handle.start_handling().await });
}
+11 -4
View File
@@ -6,8 +6,6 @@ use crate::node::client_handling::active_clients::ActiveClientsStore;
use crate::node::client_handling::websocket;
use crate::node::mixnet_handling::receiver::connection_handler::ConnectionHandler;
use crate::node::storage::PersistentStorage;
use coconut_interface::VerificationKey;
use credentials::obtain_aggregate_verification_key;
use crypto::asymmetric::{encryption, identity};
use log::*;
use mixnet_client::forwarder::{MixForwardingSender, PacketForwarder};
@@ -17,6 +15,11 @@ use std::net::SocketAddr;
use std::process;
use std::sync::Arc;
#[cfg(feature = "coconut")]
use coconut_interface::VerificationKey;
#[cfg(feature = "coconut")]
use credentials::obtain_aggregate_verification_key;
pub(crate) mod client_handling;
pub(crate) mod mixnet_handling;
pub(crate) mod storage;
@@ -83,8 +86,8 @@ impl Gateway {
fn start_client_websocket_listener(
&self,
forwarding_channel: MixForwardingSender,
verification_key: VerificationKey,
active_clients_store: ActiveClientsStore,
#[cfg(feature = "coconut")] verification_key: VerificationKey,
) {
info!("Starting client [web]socket listener...");
@@ -96,6 +99,7 @@ impl Gateway {
websocket::Listener::new(
listening_address,
Arc::clone(&self.identity),
#[cfg(feature = "coconut")]
verification_key,
)
.start(
@@ -170,6 +174,7 @@ impl Gateway {
}
}
#[cfg(feature = "coconut")]
let validators_verification_key =
obtain_aggregate_verification_key(&self.config.get_validator_api_endpoints())
.await
@@ -182,10 +187,12 @@ impl Gateway {
mix_forwarding_channel.clone(),
active_clients_store.clone(),
);
self.start_client_websocket_listener(
mix_forwarding_channel,
validators_verification_key,
active_clients_store,
#[cfg(feature = "coconut")]
validators_verification_key,
);
info!("Finished nym gateway startup procedure - it should now be able to receive mix and client traffic!");
+4
View File
@@ -54,6 +54,10 @@ impl BandwidthManager {
.await
}
// note: this is not technically a "coconut" thing, but currently we have no non-coconut
// bandwidth handling and hence clippy complains about dead and unreachable code
// so whenever we introduce another form of bandwidth claim, this feature flag should get removed
#[cfg(feature = "coconut")]
/// Increases available bandwidth of the particular client by the specified amount.
///
/// # Arguments
+4
View File
@@ -211,6 +211,10 @@ impl PersistentStorage {
Ok(res)
}
// note: this is not technically a "coconut" thing, but currently we have no non-coconut
// bandwidth handling and hence clippy complains about dead and unreachable code
// so whenever we introduce another form of bandwidth claim, this feature flag should get removed
#[cfg(feature = "coconut")]
/// Increases available bandwidth of the particular client by the specified amount.
///
/// # Arguments
+4 -2
View File
@@ -48,9 +48,11 @@ nymsphinx = { path="../common/nymsphinx" }
topology = { path="../common/topology" }
validator-client = { path="../common/client-libs/validator-client", features = ["nymd-client"] }
version-checker = { path="../common/version-checker" }
coconut-interface = { path = "../common/coconut-interface" }
credentials = { path = "../common/credentials" }
coconut-interface = { path = "../common/coconut-interface", optional = true }
credentials = { path = "../common/credentials", optional = true }
[features]
coconut = ["coconut-interface", "credentials", "gateway-client/coconut"]
[build-dependencies]
tokio = { version = "1.4", features = ["rt-multi-thread", "macros"] }
+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
{