[Product data] Data consumption with ecash ticket (#5120)

* add ticket report

* fix wasm client
This commit is contained in:
Simon Wicky
2024-11-14 15:38:44 +01:00
committed by GitHub
parent fa45b5e564
commit bea4eb5cb0
12 changed files with 110 additions and 8 deletions
Generated
+3
View File
@@ -4502,6 +4502,7 @@ dependencies = [
"nym-pemstore",
"nym-serde-helpers",
"nym-sphinx",
"nym-statistics-common",
"nym-task",
"nym-topology",
"nym-types",
@@ -5496,6 +5497,7 @@ dependencies = [
"nym-network-defaults",
"nym-pemstore",
"nym-sphinx",
"nym-statistics-common",
"nym-task",
"nym-validator-client",
"rand",
@@ -10946,6 +10948,7 @@ dependencies = [
"nym-gateway-client",
"nym-sphinx",
"nym-sphinx-acknowledgements",
"nym-statistics-common",
"nym-task",
"nym-topology",
"nym-validator-client",
@@ -358,6 +358,7 @@ where
bandwidth_controller: Option<BandwidthController<C, S::CredentialStore>>,
details_store: &S::GatewaysDetailsStore,
packet_router: PacketRouter,
stats_reporter: ClientStatsSender,
shutdown: TaskClient,
) -> Result<GatewayClient<C, S::CredentialStore>, ClientCoreError>
where
@@ -373,7 +374,12 @@ where
let mut gateway_client =
if let Some(existing_client) = initialisation_result.authenticated_ephemeral_client {
existing_client.upgrade(packet_router, bandwidth_controller, shutdown)
existing_client.upgrade(
packet_router,
bandwidth_controller,
stats_reporter,
shutdown,
)
} else {
let cfg = GatewayConfig::new(
details.gateway_id,
@@ -394,6 +400,7 @@ where
Some(details.shared_key),
packet_router,
bandwidth_controller,
stats_reporter,
shutdown,
)
};
@@ -446,6 +453,7 @@ where
Ok(gateway_client)
}
#[allow(clippy::too_many_arguments)]
async fn setup_gateway_transceiver(
custom_gateway_transceiver: Option<Box<dyn GatewayTransceiver + Send>>,
config: &Config,
@@ -453,6 +461,7 @@ where
bandwidth_controller: Option<BandwidthController<C, S::CredentialStore>>,
details_store: &S::GatewaysDetailsStore,
packet_router: PacketRouter,
stats_reporter: ClientStatsSender,
mut shutdown: TaskClient,
) -> Result<Box<dyn GatewayTransceiver + Send>, ClientCoreError>
where
@@ -483,6 +492,7 @@ where
bandwidth_controller,
details_store,
packet_router,
stats_reporter,
shutdown,
)
.await?;
@@ -766,6 +776,7 @@ where
bandwidth_controller,
&details_store,
gateway_packet_router,
stats_reporter.clone(),
shutdown.fork("gateway_transceiver"),
)
.await?;
@@ -29,6 +29,7 @@ nym-crypto = { path = "../../crypto" }
nym-gateway-requests = { path = "../../gateway-requests" }
nym-network-defaults = { path = "../../network-defaults" }
nym-sphinx = { path = "../../nymsphinx" }
nym-statistics-common = { path = "../../statistics" }
nym-pemstore = { path = "../../pemstore" }
nym-validator-client = { path = "../validator-client", default-features = false }
nym-task = { path = "../../task" }
@@ -25,6 +25,8 @@ use nym_gateway_requests::{
CREDENTIAL_UPDATE_V2_PROTOCOL_VERSION, CURRENT_PROTOCOL_VERSION,
};
use nym_sphinx::forwarding::packet::MixPacket;
use nym_statistics_common::clients::credential::CredentialStatsEvent;
use nym_statistics_common::clients::ClientStatsSender;
use nym_task::TaskClient;
use nym_validator_client::nyxd::contract_traits::DkgQueryClient;
use rand::rngs::OsRng;
@@ -94,6 +96,7 @@ pub struct GatewayClient<C, St = EphemeralCredentialStorage> {
connection: SocketState,
packet_router: PacketRouter,
bandwidth_controller: Option<BandwidthController<C, St>>,
stats_reporter: ClientStatsSender,
// currently unused (but populated)
negotiated_protocol: Option<u8>,
@@ -103,6 +106,7 @@ pub struct GatewayClient<C, St = EphemeralCredentialStorage> {
}
impl<C, St> GatewayClient<C, St> {
#[allow(clippy::too_many_arguments)]
pub fn new(
cfg: GatewayClientConfig,
gateway_config: GatewayConfig,
@@ -111,6 +115,7 @@ impl<C, St> GatewayClient<C, St> {
shared_key: Option<Arc<SharedGatewayKey>>,
packet_router: PacketRouter,
bandwidth_controller: Option<BandwidthController<C, St>>,
stats_reporter: ClientStatsSender,
task_client: TaskClient,
) -> Self {
GatewayClient {
@@ -124,6 +129,7 @@ impl<C, St> GatewayClient<C, St> {
connection: SocketState::NotConnected,
packet_router,
bandwidth_controller,
stats_reporter,
negotiated_protocol: None,
task_client,
}
@@ -714,6 +720,7 @@ impl<C, St> GatewayClient<C, St> {
{
// TODO: make it configurable
const TICKETS_TO_SPEND: u32 = 1;
const MIXNET_TICKET: TicketType = TicketType::V1MixnetEntry;
if !self.authenticated {
return Err(GatewayClientError::NotAuthenticated);
@@ -750,14 +757,23 @@ impl<C, St> GatewayClient<C, St> {
let prepared_credential = self
.unchecked_bandwidth_controller()
.prepare_ecash_ticket(
TicketType::V1MixnetEntry,
MIXNET_TICKET,
self.gateway_identity.to_bytes(),
TICKETS_TO_SPEND,
)
.await?;
match self.claim_ecash_bandwidth(prepared_credential.data).await {
Ok(_) => Ok(()),
Ok(_) => {
self.stats_reporter.report(
CredentialStatsEvent::TicketSpent {
typ: MIXNET_TICKET,
amount: TICKETS_TO_SPEND,
}
.into(),
);
Ok(())
}
Err(err) => {
error!("failed to claim ecash bandwidth with the gateway...: {err}");
if err.is_ticket_replay() {
@@ -1030,6 +1046,7 @@ impl GatewayClient<InitOnly, EphemeralCredentialStorage> {
connection: SocketState::NotConnected,
packet_router,
bandwidth_controller: None,
stats_reporter: ClientStatsSender::new(None),
negotiated_protocol: None,
task_client,
}
@@ -1039,6 +1056,7 @@ impl GatewayClient<InitOnly, EphemeralCredentialStorage> {
self,
packet_router: PacketRouter,
bandwidth_controller: Option<BandwidthController<C, St>>,
stats_reporter: ClientStatsSender,
task_client: TaskClient,
) -> GatewayClient<C, St> {
// invariants that can't be broken
@@ -1058,6 +1076,7 @@ impl GatewayClient<InitOnly, EphemeralCredentialStorage> {
connection: self.connection,
packet_router,
bandwidth_controller,
stats_reporter,
negotiated_protocol: self.negotiated_protocol,
task_client,
}
@@ -0,0 +1,52 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use super::ClientStatsEvents;
use nym_credentials_interface::TicketType;
use serde::{Deserialize, Serialize};
#[derive(Default, Debug, Clone, Copy, Serialize, Deserialize)]
pub(crate) struct CredentialStats {
mixnet_entry_spent: u32,
vpn_entry_spent: u32,
mixnet_exit_spent: u32,
vpn_exit_spent: u32,
}
/// Event space for Nym API statistics tracking
#[derive(Debug)]
pub enum CredentialStatsEvent {
/// ecash ticket was spend
TicketSpent { typ: TicketType, amount: u32 },
}
impl From<CredentialStatsEvent> for ClientStatsEvents {
fn from(event: CredentialStatsEvent) -> ClientStatsEvents {
ClientStatsEvents::Credential(event)
}
}
/// Nym API statistics tracking object
#[derive(Default)]
pub struct CredentialStatsControl {
// Keep track of packet statistics over time
stats: CredentialStats,
}
impl CredentialStatsControl {
pub(crate) fn handle_event(&mut self, event: CredentialStatsEvent) {
match event {
CredentialStatsEvent::TicketSpent { typ, amount } => match typ {
TicketType::V1MixnetEntry => self.stats.mixnet_entry_spent += amount,
TicketType::V1MixnetExit => self.stats.mixnet_exit_spent += amount,
TicketType::V1WireguardEntry => self.stats.vpn_entry_spent += amount,
TicketType::V1WireguardExit => self.stats.vpn_exit_spent += amount,
},
}
}
pub(crate) fn report(&self) -> CredentialStats {
self.stats
}
}
+9
View File
@@ -16,6 +16,8 @@ pub mod nym_api_statistics;
/// Packet count based statistics.
pub mod packet_statistics;
pub mod credential;
/// Channel receiving generic stats events to be used by a statistics aggregator.
pub type ClientStatsReceiver = tokio::sync::mpsc::UnboundedReceiver<ClientStatsEvents>;
@@ -49,6 +51,8 @@ pub enum ClientStatsEvents {
GatewayConn(gateway_conn_statistics::GatewayStatsEvent),
/// Nym API connection events
NymApi(nym_api_statistics::NymApiStatsEvent),
/// Credential events
Credential(credential::CredentialStatsEvent),
}
/// Controls stats event handling and reporting
@@ -63,6 +67,7 @@ pub struct ClientStatsController {
packet_stats: packet_statistics::PacketStatisticsControl,
gateway_conn_stats: gateway_conn_statistics::GatewayStatsControl,
nym_api_stats: nym_api_statistics::NymApiStatsControl,
credential_stats: credential::CredentialStatsControl,
}
impl ClientStatsController {
@@ -76,6 +81,7 @@ impl ClientStatsController {
packet_stats: Default::default(),
gateway_conn_stats: Default::default(),
nym_api_stats: Default::default(),
credential_stats: Default::default(),
}
}
/// Returns a static ClientStatsReport that can be sent somewhere
@@ -88,6 +94,7 @@ impl ClientStatsController {
packet_stats: self.packet_stats.report(),
gateway_conn_stats: self.gateway_conn_stats.report(),
nym_api_stats: self.nym_api_stats.report(),
credential_stats: self.credential_stats.report(),
}
}
@@ -97,6 +104,7 @@ impl ClientStatsController {
ClientStatsEvents::PacketStatistics(event) => self.packet_stats.handle_event(event),
ClientStatsEvents::GatewayConn(event) => self.gateway_conn_stats.handle_event(event),
ClientStatsEvents::NymApi(event) => self.nym_api_stats.handle_event(event),
ClientStatsEvents::Credential(event) => self.credential_stats.handle_event(event),
}
}
@@ -106,6 +114,7 @@ impl ClientStatsController {
pub fn reset(&mut self) {
self.nym_api_stats = Default::default();
self.gateway_conn_stats = Default::default();
self.credential_stats = Default::default();
//no periodic reset for packet stats
self.last_update_time = ClientStatsController::get_update_time();
+3 -2
View File
@@ -2,8 +2,8 @@
// SPDX-License-Identifier: Apache-2.0
use crate::clients::{
gateway_conn_statistics::GatewayStats, nym_api_statistics::NymApiStats,
packet_statistics::PacketStatistics,
credential::CredentialStats, gateway_conn_statistics::GatewayStats,
nym_api_statistics::NymApiStats, packet_statistics::PacketStatistics,
};
use super::error::StatsError;
@@ -22,6 +22,7 @@ pub struct ClientStatsReport {
pub(crate) packet_stats: PacketStatistics,
pub(crate) gateway_conn_stats: GatewayStats,
pub(crate) nym_api_stats: NymApiStats,
pub(crate) credential_stats: CredentialStats,
}
impl From<ClientStatsReport> for Vec<u8> {
+1
View File
@@ -30,6 +30,7 @@ nym-crypto = { path = "../../crypto", features = ["asymmetric", "serde"] }
nym-gateway-client = { path = "../../client-libs/gateway-client", default-features = false, features = ["wasm"] }
nym-sphinx = { path = "../../nymsphinx" }
nym-sphinx-acknowledgements = { path = "../../nymsphinx/acknowledgements", features = ["serde"]}
nym-statistics-common = { path = "../../statistics" }
nym-task = { path = "../../task" }
nym-topology = { path = "../../topology", features = ["serializable", "wasm-serde-types"] }
nym-validator-client = { path = "../../client-libs/validator-client", default-features = false }
+1
View File
@@ -26,6 +26,7 @@ pub use nym_sphinx::{
params::PacketType,
receiver::ReconstructedMessage,
};
pub use nym_statistics_common::clients::ClientStatsSender;
pub use nym_task;
pub use nym_topology::{HardcodedTopologyProvider, MixLayer, NymTopology, TopologyProvider};
pub use nym_validator_client::nym_api::Client as ApiClient;
+1
View File
@@ -119,6 +119,7 @@ nym-node-requests = { path = "../nym-node/nym-node-requests" }
nym-types = { path = "../common/types" }
nym-http-api-common = { path = "../common/http-api-common", features = ["utoipa"] }
nym-serde-helpers = { path = "../common/serde-helpers", features = ["date"] }
nym-statistics-common = {path ="../common/statistics" }
[features]
no-reward = []
@@ -213,6 +213,7 @@ impl PacketSender {
None,
gateway_packet_router,
Some(fresh_gateway_client_data.bandwidth_controller.clone()),
nym_statistics_common::clients::ClientStatsSender::new(None),
task_client,
);
+5 -3
View File
@@ -34,9 +34,9 @@ use wasm_client_core::helpers::{
use wasm_client_core::storage::ClientStorage;
use wasm_client_core::topology::SerializableNymTopology;
use wasm_client_core::{
nym_task, BandwidthController, ClientKeys, GatewayClient, GatewayClientConfig, GatewayConfig,
IdentityKey, InitialisationResult, NodeIdentity, NymTopology, QueryReqwestRpcNyxdClient,
Recipient,
nym_task, BandwidthController, ClientKeys, ClientStatsSender, GatewayClient,
GatewayClientConfig, GatewayConfig, IdentityKey, InitialisationResult, NodeIdentity,
NymTopology, QueryReqwestRpcNyxdClient, Recipient,
};
use wasm_utils::check_promise_result;
use wasm_utils::error::PromisableResult;
@@ -194,6 +194,7 @@ impl NymNodeTesterBuilder {
existing_client.upgrade(
packet_router,
self.bandwidth_controller.take(),
ClientStatsSender::new(None),
gateway_task,
)
} else {
@@ -209,6 +210,7 @@ impl NymNodeTesterBuilder {
Some(gateway_info.shared_key),
packet_router,
self.bandwidth_controller.take(),
ClientStatsSender::new(None),
gateway_task,
)
};