revamped ticketbook serialisation and exposed additional cli methods

This commit is contained in:
Jędrzej Stuczyński
2024-08-30 17:35:57 +01:00
parent 230e4393c5
commit fb0b9da14f
92 changed files with 2158 additions and 403 deletions
Generated
+3
View File
@@ -4412,6 +4412,7 @@ dependencies = [
"serde",
"serde_json",
"tap",
"tempfile",
"thiserror",
"time",
"tokio",
@@ -4754,6 +4755,7 @@ dependencies = [
"nym-ecash-contract-common",
"nym-ecash-time",
"nym-network-defaults",
"nym-serde-helpers",
"nym-validator-client",
"rand",
"serde",
@@ -5670,6 +5672,7 @@ dependencies = [
"base64 0.22.1",
"bs58",
"serde",
"time",
]
[[package]]
@@ -0,0 +1,16 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::commands::CliNativeClient;
use crate::error::ClientError;
use nym_client_core::cli_helpers::client_import_coin_index_signatures::{
import_coin_index_signatures, CommonClientImportCoinIndexSignaturesArgs,
};
pub(crate) async fn execute(
args: CommonClientImportCoinIndexSignaturesArgs,
) -> Result<(), ClientError> {
import_coin_index_signatures::<CliNativeClient, _>(args).await?;
println!("successfully imported coin index signatures!");
Ok(())
}
@@ -4,10 +4,10 @@
use crate::commands::CliNativeClient;
use crate::error::ClientError;
use nym_client_core::cli_helpers::client_import_credential::{
import_credential, CommonClientImportCredentialArgs,
import_credential, CommonClientImportTicketBookArgs,
};
pub(crate) async fn execute(args: CommonClientImportCredentialArgs) -> Result<(), ClientError> {
pub(crate) async fn execute(args: CommonClientImportTicketBookArgs) -> Result<(), ClientError> {
import_credential::<CliNativeClient, _>(args).await?;
println!("successfully imported credential!");
Ok(())
@@ -0,0 +1,16 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::commands::CliNativeClient;
use crate::error::ClientError;
use nym_client_core::cli_helpers::client_import_expiration_date_signatures::{
import_expiration_date_signatures, CommonClientImportExpirationDateSignaturesArgs,
};
pub(crate) async fn execute(
args: CommonClientImportExpirationDateSignaturesArgs,
) -> Result<(), ClientError> {
import_expiration_date_signatures::<CliNativeClient, _>(args).await?;
println!("successfully imported expiration date signatures!");
Ok(())
}
@@ -0,0 +1,16 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::commands::CliNativeClient;
use crate::error::ClientError;
use nym_client_core::cli_helpers::client_import_master_verification_key::{
import_master_verification_key, CommonClientImportMasterVerificationKeyArgs,
};
pub(crate) async fn execute(
args: CommonClientImportMasterVerificationKeyArgs,
) -> Result<(), ClientError> {
import_master_verification_key::<CliNativeClient, _>(args).await?;
println!("successfully imported master verification key!");
Ok(())
}
+59
View File
@@ -0,0 +1,59 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use clap::{Args, Subcommand};
use nym_client_core::cli_helpers::client_import_coin_index_signatures::CommonClientImportCoinIndexSignaturesArgs;
use nym_client_core::cli_helpers::client_import_credential::CommonClientImportTicketBookArgs;
use nym_client_core::cli_helpers::client_import_expiration_date_signatures::CommonClientImportExpirationDateSignaturesArgs;
use nym_client_core::cli_helpers::client_import_master_verification_key::CommonClientImportMasterVerificationKeyArgs;
use std::error::Error;
pub(crate) mod import_coin_index_signatures;
pub(crate) mod import_credential;
pub(crate) mod import_expiration_date_signatures;
pub(crate) mod import_master_verification_key;
pub(crate) mod show_ticketbooks;
#[derive(Args)]
#[clap(args_conflicts_with_subcommands = true, subcommand_required = true)]
pub struct Ecash {
#[clap(subcommand)]
pub command: EcashCommands,
}
impl Ecash {
pub async fn execute(self) -> Result<(), Box<dyn Error + Send + Sync>> {
match self.command {
EcashCommands::ShowTicketBooks(args) => show_ticketbooks::execute(args).await?,
EcashCommands::ImportTicketBook(args) => import_credential::execute(args).await?,
EcashCommands::ImportCoinIndexSignatures(args) => {
import_coin_index_signatures::execute(args).await?
}
EcashCommands::ImportExpirationDateSignatures(args) => {
import_expiration_date_signatures::execute(args).await?
}
EcashCommands::ImportMasterVerificationKey(args) => {
import_master_verification_key::execute(args).await?
}
}
Ok(())
}
}
#[derive(Subcommand)]
pub enum EcashCommands {
/// Display information associated with the imported ticketbooks,
ShowTicketBooks(show_ticketbooks::Args),
/// Import a pre-generated ticketbook
ImportTicketBook(CommonClientImportTicketBookArgs),
/// Import coin index signatures needed for ticketbooks
ImportCoinIndexSignatures(CommonClientImportCoinIndexSignaturesArgs),
/// Import expiration date signatures needed for ticketbooks
ImportExpirationDateSignatures(CommonClientImportExpirationDateSignaturesArgs),
/// Import master verification key needed for ticketbooks
ImportMasterVerificationKey(CommonClientImportMasterVerificationKeyArgs),
}
+5 -10
View File
@@ -6,13 +6,13 @@ use crate::client::config::old_config_v1_1_20::ConfigV1_1_20;
use crate::client::config::old_config_v1_1_20_2::ConfigV1_1_20_2;
use crate::client::config::old_config_v1_1_33::ConfigV1_1_33;
use crate::client::config::{BaseClientConfig, Config};
use crate::commands::ecash::Ecash;
use crate::error::ClientError;
use clap::CommandFactory;
use clap::{Parser, Subcommand};
use log::{error, info};
use nym_bin_common::bin_info;
use nym_bin_common::completions::{fig_generate, ArgShell};
use nym_client_core::cli_helpers::client_import_credential::CommonClientImportCredentialArgs;
use nym_client_core::cli_helpers::CliClient;
use nym_client_core::client::base_client::storage::migration_helpers::v1_1_33;
use nym_config::OptionalSet;
@@ -22,11 +22,10 @@ use std::sync::OnceLock;
mod add_gateway;
pub(crate) mod build_info;
pub(crate) mod import_credential;
pub(crate) mod ecash;
pub(crate) mod init;
mod list_gateways;
pub(crate) mod run;
mod show_ticketbooks;
mod switch_gateway;
pub(crate) struct CliNativeClient;
@@ -73,8 +72,8 @@ pub(crate) enum Commands {
/// Run the Nym client with provided configuration client optionally overriding set parameters
Run(run::Run),
/// Import a pre-generated credential
ImportCredential(CommonClientImportCredentialArgs),
/// Ecash-related functionalities
Ecash(Ecash),
/// List all registered with gateways
ListGateways(list_gateways::Args),
@@ -85,9 +84,6 @@ pub(crate) enum Commands {
/// Change the currently active gateway. Note that you must have already registered with the new gateway!
SwitchGateway(switch_gateway::Args),
/// Display information associated with the imported ticketbooks,
ShowTicketbooks(show_ticketbooks::Args),
/// Show build information of this binary
BuildInfo(build_info::BuildInfo),
@@ -116,11 +112,10 @@ pub(crate) async fn execute(args: Cli) -> Result<(), Box<dyn Error + Send + Sync
match args.command {
Commands::Init(m) => init::execute(m).await?,
Commands::Run(m) => run::execute(m).await?,
Commands::ImportCredential(m) => import_credential::execute(m).await?,
Commands::Ecash(ecash) => ecash.execute().await?,
Commands::ListGateways(args) => list_gateways::execute(args).await?,
Commands::AddGateway(args) => add_gateway::execute(args).await?,
Commands::SwitchGateway(args) => switch_gateway::execute(args).await?,
Commands::ShowTicketbooks(args) => show_ticketbooks::execute(args).await?,
Commands::BuildInfo(m) => build_info::execute(m),
Commands::Completions(s) => s.generate(&mut Cli::command(), bin_name),
Commands::GenerateFigSpec => fig_generate(&mut Cli::command(), bin_name),
@@ -0,0 +1,16 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::commands::CliSocks5Client;
use crate::error::Socks5ClientError;
use nym_client_core::cli_helpers::client_import_coin_index_signatures::{
import_coin_index_signatures, CommonClientImportCoinIndexSignaturesArgs,
};
pub(crate) async fn execute(
args: CommonClientImportCoinIndexSignaturesArgs,
) -> Result<(), Socks5ClientError> {
import_coin_index_signatures::<CliSocks5Client, _>(args).await?;
println!("successfully imported coin index signatures!");
Ok(())
}
@@ -4,12 +4,10 @@
use crate::commands::CliSocks5Client;
use crate::error::Socks5ClientError;
use nym_client_core::cli_helpers::client_import_credential::{
import_credential, CommonClientImportCredentialArgs,
import_credential, CommonClientImportTicketBookArgs,
};
pub(crate) async fn execute(
args: CommonClientImportCredentialArgs,
) -> Result<(), Socks5ClientError> {
pub async fn execute(args: CommonClientImportTicketBookArgs) -> Result<(), Socks5ClientError> {
import_credential::<CliSocks5Client, _>(args).await?;
println!("successfully imported credential!");
Ok(())
@@ -0,0 +1,16 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::commands::CliSocks5Client;
use crate::error::Socks5ClientError;
use nym_client_core::cli_helpers::client_import_expiration_date_signatures::{
import_expiration_date_signatures, CommonClientImportExpirationDateSignaturesArgs,
};
pub(crate) async fn execute(
args: CommonClientImportExpirationDateSignaturesArgs,
) -> Result<(), Socks5ClientError> {
import_expiration_date_signatures::<CliSocks5Client, _>(args).await?;
println!("successfully imported expiration date signatures!");
Ok(())
}
@@ -0,0 +1,16 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::commands::CliSocks5Client;
use crate::error::Socks5ClientError;
use nym_client_core::cli_helpers::client_import_master_verification_key::{
import_master_verification_key, CommonClientImportMasterVerificationKeyArgs,
};
pub(crate) async fn execute(
args: CommonClientImportMasterVerificationKeyArgs,
) -> Result<(), Socks5ClientError> {
import_master_verification_key::<CliSocks5Client, _>(args).await?;
println!("successfully imported master verification key!");
Ok(())
}
+59
View File
@@ -0,0 +1,59 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use clap::{Args, Subcommand};
use nym_client_core::cli_helpers::client_import_coin_index_signatures::CommonClientImportCoinIndexSignaturesArgs;
use nym_client_core::cli_helpers::client_import_credential::CommonClientImportTicketBookArgs;
use nym_client_core::cli_helpers::client_import_expiration_date_signatures::CommonClientImportExpirationDateSignaturesArgs;
use nym_client_core::cli_helpers::client_import_master_verification_key::CommonClientImportMasterVerificationKeyArgs;
use std::error::Error;
pub(crate) mod import_coin_index_signatures;
pub(crate) mod import_credential;
pub(crate) mod import_expiration_date_signatures;
pub(crate) mod import_master_verification_key;
pub(crate) mod show_ticketbooks;
#[derive(Args)]
#[clap(args_conflicts_with_subcommands = true, subcommand_required = true)]
pub struct Ecash {
#[clap(subcommand)]
pub command: EcashCommands,
}
impl Ecash {
pub async fn execute(self) -> Result<(), Box<dyn Error + Send + Sync>> {
match self.command {
EcashCommands::ShowTicketBooks(args) => show_ticketbooks::execute(args).await?,
EcashCommands::ImportTicketBook(args) => import_credential::execute(args).await?,
EcashCommands::ImportCoinIndexSignatures(args) => {
import_coin_index_signatures::execute(args).await?
}
EcashCommands::ImportExpirationDateSignatures(args) => {
import_expiration_date_signatures::execute(args).await?
}
EcashCommands::ImportMasterVerificationKey(args) => {
import_master_verification_key::execute(args).await?
}
}
Ok(())
}
}
#[derive(Subcommand)]
pub enum EcashCommands {
/// Display information associated with the imported ticketbooks,
ShowTicketBooks(show_ticketbooks::Args),
/// Import a pre-generated ticketbook
ImportTicketBook(CommonClientImportTicketBookArgs),
/// Import coin index signatures needed for ticketbooks
ImportCoinIndexSignatures(CommonClientImportCoinIndexSignaturesArgs),
/// Import expiration date signatures needed for ticketbooks
ImportExpirationDateSignatures(CommonClientImportExpirationDateSignaturesArgs),
/// Import master verification key needed for ticketbooks
ImportMasterVerificationKey(CommonClientImportMasterVerificationKeyArgs),
}
@@ -9,7 +9,7 @@ use nym_client_core::cli_helpers::client_show_ticketbooks::{
};
#[derive(clap::Args)]
pub(crate) struct Args {
pub struct Args {
#[command(flatten)]
common_args: CommonShowTicketbooksArgs,
@@ -23,7 +23,7 @@ impl AsRef<CommonShowTicketbooksArgs> for Args {
}
}
pub(crate) async fn execute(args: Args) -> Result<(), Socks5ClientError> {
pub async fn execute(args: Args) -> Result<(), Socks5ClientError> {
let output = args.output;
let res = show_ticketbooks::<CliSocks5Client, _>(args).await?;
+5 -10
View File
@@ -1,6 +1,7 @@
// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::commands::ecash::Ecash;
use crate::config::old_config_v1_1_13::OldConfigV1_1_13;
use crate::config::old_config_v1_1_20::ConfigV1_1_20;
use crate::config::old_config_v1_1_20_2::ConfigV1_1_20_2;
@@ -13,7 +14,6 @@ use clap::{Parser, Subcommand};
use log::{error, info};
use nym_bin_common::bin_info;
use nym_bin_common::completions::{fig_generate, ArgShell};
use nym_client_core::cli_helpers::client_import_credential::CommonClientImportCredentialArgs;
use nym_client_core::cli_helpers::CliClient;
use nym_client_core::client::base_client::storage::migration_helpers::v1_1_33;
use nym_client_core::client::topology_control::geo_aware_provider::CountryGroup;
@@ -26,11 +26,10 @@ use std::sync::OnceLock;
mod add_gateway;
pub(crate) mod build_info;
mod import_credential;
pub mod ecash;
pub mod init;
mod list_gateways;
pub(crate) mod run;
mod show_ticketbooks;
mod switch_gateway;
pub(crate) struct CliSocks5Client;
@@ -77,8 +76,8 @@ pub(crate) enum Commands {
/// Run the Nym client with provided configuration client optionally overriding set parameters
Run(run::Run),
/// Import a pre-generated credential
ImportCredential(CommonClientImportCredentialArgs),
/// Ecash-related functionalities
Ecash(Ecash),
/// List all registered with gateways
ListGateways(list_gateways::Args),
@@ -89,9 +88,6 @@ pub(crate) enum Commands {
/// Change the currently active gateway. Note that you must have already registered with the new gateway!
SwitchGateway(switch_gateway::Args),
/// Display information associated with the imported ticketbooks,
ShowTicketbooks(show_ticketbooks::Args),
/// Show build information of this binary
BuildInfo(build_info::BuildInfo),
@@ -123,11 +119,10 @@ pub(crate) async fn execute(args: Cli) -> Result<(), Box<dyn Error + Send + Sync
match args.command {
Commands::Init(m) => init::execute(m).await?,
Commands::Run(m) => run::execute(m).await?,
Commands::ImportCredential(m) => import_credential::execute(m).await?,
Commands::Ecash(ecash) => ecash.execute().await?,
Commands::ListGateways(args) => list_gateways::execute(args).await?,
Commands::AddGateway(args) => add_gateway::execute(args).await?,
Commands::SwitchGateway(args) => switch_gateway::execute(args).await?,
Commands::ShowTicketbooks(args) => show_ticketbooks::execute(args).await?,
Commands::BuildInfo(m) => build_info::execute(m),
Commands::Completions(s) => s.generate(&mut Cli::command(), bin_name),
Commands::GenerateFigSpec => fig_generate(&mut Cli::command(), bin_name),
+26 -6
View File
@@ -4,6 +4,10 @@
use crate::error::BandwidthControllerError;
use log::warn;
use nym_credential_storage::storage::Storage;
use nym_credentials::ecash::bandwidth::serialiser::keys::EpochVerificationKey;
use nym_credentials::ecash::bandwidth::serialiser::signatures::{
AggregatedCoinIndicesSignatures, AggregatedExpirationDateSignatures,
};
use nym_credentials_interface::{
AnnotatedCoinIndexSignature, AnnotatedExpirationDateSignature, VerificationKeyAuth,
};
@@ -94,13 +98,18 @@ where
.await?
.key;
let full = EpochVerificationKey {
epoch_id,
key: master_vk,
};
// store the retrieved key
storage
.insert_master_verification_key(epoch_id, &master_vk)
.insert_master_verification_key(&full)
.await
.map_err(BandwidthControllerError::credential_storage_error)?;
Ok(master_vk)
Ok(full.key)
}
pub(crate) async fn get_coin_index_signatures<St>(
@@ -132,13 +141,18 @@ where
.await?
.signatures;
let aggregated = AggregatedCoinIndicesSignatures {
epoch_id,
signatures: index_sigs,
};
// store the retrieved key
storage
.insert_coin_index_signatures(epoch_id, &index_sigs)
.insert_coin_index_signatures(&aggregated)
.await
.map_err(BandwidthControllerError::credential_storage_error)?;
Ok(index_sigs)
Ok(aggregated.signatures)
}
pub(crate) async fn get_expiration_date_signatures<St>(
@@ -171,11 +185,17 @@ where
.await?
.signatures;
let aggregated = AggregatedExpirationDateSignatures {
epoch_id,
expiration_date,
signatures: expiration_sigs,
};
// store the retrieved key
storage
.insert_expiration_date_signatures(epoch_id, expiration_date, &expiration_sigs)
.insert_expiration_date_signatures(&aggregated)
.await
.map_err(BandwidthControllerError::credential_storage_error)?;
Ok(expiration_sigs)
Ok(aggregated.signatures)
}
@@ -0,0 +1,68 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::cli_helpers::{CliClient, CliClientConfig};
use std::fs;
use std::path::PathBuf;
#[cfg(feature = "cli")]
fn parse_encoded_signatures_data(raw: &str) -> bs58::decode::Result<Vec<u8>> {
bs58::decode(raw).into_vec()
}
#[cfg_attr(feature = "cli", derive(clap::Args))]
#[cfg_attr(feature = "cli",
clap(
group(clap::ArgGroup::new("signatures_data").required(true)),
))
]
pub struct CommonClientImportCoinIndexSignaturesArgs {
/// Id of client that is going to import the signatures
#[cfg_attr(feature = "cli", clap(long))]
pub id: String,
/// Config file of the client that is supposed to use the signatures.
#[cfg_attr(feature = "cli", clap(long))]
pub(crate) client_config: PathBuf,
/// Explicitly provide the encoded signatures data (as base58)
#[cfg_attr(feature = "cli", clap(long, group = "signatures_data", value_parser = parse_encoded_signatures_data))]
pub(crate) signatures_data: Option<Vec<u8>>,
/// Specifies the path to file containing binary signatures data
#[cfg_attr(feature = "cli", clap(long, group = "signatures_data"))]
pub(crate) signatures_path: Option<PathBuf>,
// currently hidden as there exists only a single serialization standard
#[cfg_attr(feature = "cli", clap(long, hide = true))]
pub(crate) version: Option<u8>,
}
pub async fn import_coin_index_signatures<C, A>(args: A) -> Result<(), C::Error>
where
A: Into<CommonClientImportCoinIndexSignaturesArgs>,
C: CliClient,
C::Error: From<std::io::Error> + From<nym_id::NymIdError>,
{
let common_args = args.into();
let id = &common_args.id;
let config = C::try_load_current_config(id).await?;
let paths = config.common_paths();
let credentials_store =
nym_credential_storage::initialise_persistent_storage(&paths.credentials_database).await;
let version = common_args.version;
let raw_key = match common_args.signatures_data {
Some(data) => data,
None => {
// SAFETY: one of those arguments must have been set
fs::read(common_args.signatures_path.unwrap())?
}
};
nym_id::import_coin_index_signatures(credentials_store, raw_key, version).await?;
Ok(())
}
@@ -11,9 +11,14 @@ fn parse_encoded_credential_data(raw: &str) -> bs58::decode::Result<Vec<u8>> {
}
#[cfg_attr(feature = "cli", derive(clap::Args))]
#[cfg_attr(feature = "cli", clap(group(clap::ArgGroup::new("cred_data").required(true))))]
#[cfg_attr(feature = "cli",
clap(
group(clap::ArgGroup::new("cred_data").required(true)),
group(clap::ArgGroup::new("type").required(true)),
))
]
#[derive(Debug, Clone)]
pub struct CommonClientImportCredentialArgs {
pub struct CommonClientImportTicketBookArgs {
/// Id of client that is going to import the credential
#[cfg_attr(feature = "cli", clap(long))]
pub id: String,
@@ -26,6 +31,15 @@ pub struct CommonClientImportCredentialArgs {
#[cfg_attr(feature = "cli", clap(long, group = "cred_data"))]
pub(crate) credential_path: Option<PathBuf>,
/// Specifies whether we're attempting to import a standalone ticketbook (i.e. serialised `IssuedTicketBook`)
#[cfg_attr(feature = "cli", clap(long, group = "type"))]
pub(crate) standalone: bool,
/// Specifies whether we're attempting to import full ticketboot
/// (i.e. one that **might** contain required global signatures; that is serialised `ImportableTicketBook`)
#[cfg_attr(feature = "cli", clap(long, group = "type"))]
pub(crate) full: bool,
// currently hidden as there exists only a single serialization standard
#[cfg_attr(feature = "cli", clap(long, hide = true))]
pub(crate) version: Option<u8>,
@@ -33,7 +47,7 @@ pub struct CommonClientImportCredentialArgs {
pub async fn import_credential<C, A>(args: A) -> Result<(), C::Error>
where
A: Into<CommonClientImportCredentialArgs>,
A: Into<CommonClientImportTicketBookArgs>,
C: CliClient,
C::Error: From<std::io::Error> + From<nym_id::NymIdError>,
{
@@ -54,6 +68,19 @@ where
}
};
nym_id::import_credential(credentials_store, raw_credential, common_args.version).await?;
if common_args.standalone {
nym_id::import_standalone_ticketbook(
credentials_store,
raw_credential,
common_args.version,
)
.await?;
} else {
// sanity check; clap should have ensured it
assert!(common_args.full);
nym_id::import_full_ticketbook(credentials_store, raw_credential, common_args.version)
.await?;
}
Ok(())
}
@@ -0,0 +1,68 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::cli_helpers::{CliClient, CliClientConfig};
use std::fs;
use std::path::PathBuf;
#[cfg(feature = "cli")]
fn parse_encoded_signatures_data(raw: &str) -> bs58::decode::Result<Vec<u8>> {
bs58::decode(raw).into_vec()
}
#[cfg_attr(feature = "cli", derive(clap::Args))]
#[cfg_attr(feature = "cli",
clap(
group(clap::ArgGroup::new("signatures_data").required(true)),
))
]
pub struct CommonClientImportExpirationDateSignaturesArgs {
/// Id of client that is going to import the signatures
#[cfg_attr(feature = "cli", clap(long))]
pub id: String,
/// Config file of the client that is supposed to use the signatures.
#[cfg_attr(feature = "cli", clap(long))]
pub(crate) client_config: PathBuf,
/// Explicitly provide the encoded signatures data (as base58)
#[cfg_attr(feature = "cli", clap(long, group = "signatures_data", value_parser = parse_encoded_signatures_data))]
pub(crate) signatures_data: Option<Vec<u8>>,
/// Specifies the path to file containing binary signatures data
#[cfg_attr(feature = "cli", clap(long, group = "signatures_data"))]
pub(crate) signatures_path: Option<PathBuf>,
// currently hidden as there exists only a single serialization standard
#[cfg_attr(feature = "cli", clap(long, hide = true))]
pub(crate) version: Option<u8>,
}
pub async fn import_expiration_date_signatures<C, A>(args: A) -> Result<(), C::Error>
where
A: Into<CommonClientImportExpirationDateSignaturesArgs>,
C: CliClient,
C::Error: From<std::io::Error> + From<nym_id::NymIdError>,
{
let common_args = args.into();
let id = &common_args.id;
let config = C::try_load_current_config(id).await?;
let paths = config.common_paths();
let credentials_store =
nym_credential_storage::initialise_persistent_storage(&paths.credentials_database).await;
let version = common_args.version;
let raw_key = match common_args.signatures_data {
Some(data) => data,
None => {
// SAFETY: one of those arguments must have been set
fs::read(common_args.signatures_path.unwrap())?
}
};
nym_id::import_expiration_date_signatures(credentials_store, raw_key, version).await?;
Ok(())
}
@@ -0,0 +1,68 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::cli_helpers::{CliClient, CliClientConfig};
use std::fs;
use std::path::PathBuf;
#[cfg(feature = "cli")]
fn parse_encoded_key_data(raw: &str) -> bs58::decode::Result<Vec<u8>> {
bs58::decode(raw).into_vec()
}
#[cfg_attr(feature = "cli", derive(clap::Args))]
#[cfg_attr(feature = "cli",
clap(
group(clap::ArgGroup::new("key_data").required(true)),
))
]
pub struct CommonClientImportMasterVerificationKeyArgs {
/// Id of client that is going to import the key
#[cfg_attr(feature = "cli", clap(long))]
pub id: String,
/// Config file of the client that is supposed to use the key.
#[cfg_attr(feature = "cli", clap(long))]
pub(crate) client_config: PathBuf,
/// Explicitly provide the encoded key data (as base58)
#[cfg_attr(feature = "cli", clap(long, group = "key_data", value_parser = parse_encoded_key_data))]
pub(crate) key_data: Option<Vec<u8>>,
/// Specifies the path to file containing binary key data
#[cfg_attr(feature = "cli", clap(long, group = "key_data"))]
pub(crate) key_path: Option<PathBuf>,
// currently hidden as there exists only a single serialization standard
#[cfg_attr(feature = "cli", clap(long, hide = true))]
pub(crate) version: Option<u8>,
}
pub async fn import_master_verification_key<C, A>(args: A) -> Result<(), C::Error>
where
A: Into<CommonClientImportMasterVerificationKeyArgs>,
C: CliClient,
C::Error: From<std::io::Error> + From<nym_id::NymIdError>,
{
let common_args = args.into();
let id = &common_args.id;
let config = C::try_load_current_config(id).await?;
let paths = config.common_paths();
let credentials_store =
nym_credential_storage::initialise_persistent_storage(&paths.credentials_database).await;
let version = common_args.version;
let raw_key = match common_args.key_data {
Some(data) => data,
None => {
// SAFETY: one of those arguments must have been set
fs::read(common_args.key_path.unwrap())?
}
};
nym_id::import_master_verification_key(credentials_store, raw_key, version).await?;
Ok(())
}
@@ -2,7 +2,10 @@
// SPDX-License-Identifier: Apache-2.0
pub mod client_add_gateway;
pub mod client_import_coin_index_signatures;
pub mod client_import_credential;
pub mod client_import_expiration_date_signatures;
pub mod client_import_master_verification_key;
pub mod client_init;
pub mod client_list_gateways;
pub mod client_run;
+2 -1
View File
@@ -25,8 +25,9 @@ rand = { workspace = true, features = ["std"] }
serde = { workspace = true, features = ["derive"] }
serde_json = { workspace = true }
thiserror = { workspace = true }
tempfile = { workspace = true }
time = { workspace = true, features = ["parsing", "formatting"] }
tokio = { workspace = true, features = ["sync"]}
tokio = { workspace = true, features = ["sync"] }
toml = "0.5.6"
url = { workspace = true }
tap = { workspace = true }
@@ -1,56 +0,0 @@
// Copyright 2022-2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::context::SigningClient;
use crate::utils::CommonConfigsWrapper;
use anyhow::bail;
use clap::Parser;
use nym_credential_storage::initialise_persistent_storage;
use nym_credential_utils::utils;
use nym_credentials_interface::TicketType;
use nym_crypto::asymmetric::identity;
use std::path::PathBuf;
#[derive(Debug, Parser)]
pub struct Args {
/// Specify which type of ticketbook should be issued
#[clap(long, default_value_t = TicketType::V1MixnetEntry)]
pub(crate) ticketbook_type: TicketType,
/// Config file of the client that is supposed to use the credential.
#[clap(long)]
pub(crate) client_config: PathBuf,
}
pub async fn execute(args: Args, client: SigningClient) -> anyhow::Result<()> {
let loaded = CommonConfigsWrapper::try_load(args.client_config)?;
if let Ok(id) = loaded.try_get_id() {
println!("loaded config file for client '{id}'");
}
let Ok(credentials_store) = loaded.try_get_credentials_store() else {
bail!("the loaded config does not have a credentials store information")
};
let Ok(private_id_key) = loaded.try_get_private_id_key() else {
bail!("the loaded config does not have a public id key information")
};
println!(
"using credentials store at '{}'",
credentials_store.display()
);
let persistent_storage = initialise_persistent_storage(credentials_store).await;
let private_id_key: identity::PrivateKey = nym_pemstore::load_key(private_id_key)?;
utils::issue_credential(
&client,
&persistent_storage,
&private_id_key.to_bytes(),
args.ticketbook_type,
)
.await?;
Ok(())
}
@@ -0,0 +1,76 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::utils::CommonConfigsWrapper;
use anyhow::bail;
use clap::ArgGroup;
use clap::Parser;
use nym_credential_storage::initialise_persistent_storage;
use nym_id::import_credential::import_expiration_date_signatures;
use std::fs;
use std::path::PathBuf;
fn parse_encoded_signatures_data(raw: &str) -> bs58::decode::Result<Vec<u8>> {
bs58::decode(raw).into_vec()
}
#[derive(Debug, Parser)]
#[clap(
group(ArgGroup::new("signatures_data").required(true)),
)]
pub struct Args {
/// Config file of the client that is supposed to use the signatures.
#[clap(long)]
pub(crate) client_config: PathBuf,
/// Explicitly provide the encoded signatures data (as base58)
#[clap(long, group = "signatures_data", value_parser = parse_encoded_signatures_data)]
pub(crate) signatures_data: Option<Vec<u8>>,
/// Specifies the path to file containing binary signatures data
#[clap(long, group = "signatures_data")]
pub(crate) signatures_path: Option<PathBuf>,
// currently hidden as there exists only a single serialization standard
#[clap(long, hide = true)]
pub(crate) version: Option<u8>,
}
impl Args {
fn signatures_data(self) -> anyhow::Result<Vec<u8>> {
let data = match self.signatures_data {
Some(data) => data,
None => {
// SAFETY: one of those arguments must have been set
#[allow(clippy::unwrap_used)]
fs::read(self.signatures_path.unwrap())?
}
};
Ok(data)
}
}
pub async fn execute(args: Args) -> anyhow::Result<()> {
let loaded = CommonConfigsWrapper::try_load(&args.client_config)?;
if let Ok(id) = loaded.try_get_id() {
println!("loaded config file for client '{id}'");
}
let Ok(credentials_store) = loaded.try_get_credentials_store() else {
bail!("the loaded config does not have a credentials store information")
};
println!(
"using credentials store at '{}'",
credentials_store.display()
);
let credentials_store = initialise_persistent_storage(credentials_store).await;
let version = args.version;
let raw_signatures = args.signatures_data()?;
import_expiration_date_signatures(credentials_store, raw_signatures, version).await?;
Ok(())
}
@@ -0,0 +1,76 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::utils::CommonConfigsWrapper;
use anyhow::bail;
use clap::ArgGroup;
use clap::Parser;
use nym_credential_storage::initialise_persistent_storage;
use nym_id::import_credential::import_expiration_date_signatures;
use std::fs;
use std::path::PathBuf;
fn parse_encoded_signatures_data(raw: &str) -> bs58::decode::Result<Vec<u8>> {
bs58::decode(raw).into_vec()
}
#[derive(Debug, Parser)]
#[clap(
group(ArgGroup::new("signatures_data").required(true)),
)]
pub struct Args {
/// Config file of the client that is supposed to use the signatures.
#[clap(long)]
pub(crate) client_config: PathBuf,
/// Explicitly provide the encoded signatures data (as base58)
#[clap(long, group = "signatures_data", value_parser = parse_encoded_signatures_data)]
pub(crate) signatures_data: Option<Vec<u8>>,
/// Specifies the path to file containing binary signatures data
#[clap(long, group = "signatures_data")]
pub(crate) signatures_path: Option<PathBuf>,
// currently hidden as there exists only a single serialization standard
#[clap(long, hide = true)]
pub(crate) version: Option<u8>,
}
impl Args {
fn signatures_data(self) -> anyhow::Result<Vec<u8>> {
let data = match self.signatures_data {
Some(data) => data,
None => {
// SAFETY: one of those arguments must have been set
#[allow(clippy::unwrap_used)]
fs::read(self.signatures_path.unwrap())?
}
};
Ok(data)
}
}
pub async fn execute(args: Args) -> anyhow::Result<()> {
let loaded = CommonConfigsWrapper::try_load(&args.client_config)?;
if let Ok(id) = loaded.try_get_id() {
println!("loaded config file for client '{id}'");
}
let Ok(credentials_store) = loaded.try_get_credentials_store() else {
bail!("the loaded config does not have a credentials store information")
};
println!(
"using credentials store at '{}'",
credentials_store.display()
);
let credentials_store = initialise_persistent_storage(credentials_store).await;
let version = args.version;
let raw_signatures = args.signatures_data()?;
import_expiration_date_signatures(credentials_store, raw_signatures, version).await?;
Ok(())
}
@@ -0,0 +1,76 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::utils::CommonConfigsWrapper;
use anyhow::bail;
use clap::ArgGroup;
use clap::Parser;
use nym_credential_storage::initialise_persistent_storage;
use nym_id::import_credential::import_master_verification_key;
use std::fs;
use std::path::PathBuf;
fn parse_encoded_key_data(raw: &str) -> bs58::decode::Result<Vec<u8>> {
bs58::decode(raw).into_vec()
}
#[derive(Debug, Parser)]
#[clap(
group(ArgGroup::new("key_data").required(true)),
)]
pub struct Args {
/// Config file of the client that is supposed to use the key.
#[clap(long)]
pub(crate) client_config: PathBuf,
/// Explicitly provide the encoded key data (as base58)
#[clap(long, group = "key_data", value_parser = parse_encoded_key_data)]
pub(crate) key_data: Option<Vec<u8>>,
/// Specifies the path to file containing binary key data
#[clap(long, group = "key_data")]
pub(crate) key_path: Option<PathBuf>,
// currently hidden as there exists only a single serialization standard
#[clap(long, hide = true)]
pub(crate) version: Option<u8>,
}
impl Args {
fn key_data(self) -> anyhow::Result<Vec<u8>> {
let data = match self.key_data {
Some(data) => data,
None => {
// SAFETY: one of those arguments must have been set
#[allow(clippy::unwrap_used)]
fs::read(self.key_path.unwrap())?
}
};
Ok(data)
}
}
pub async fn execute(args: Args) -> anyhow::Result<()> {
let loaded = CommonConfigsWrapper::try_load(&args.client_config)?;
if let Ok(id) = loaded.try_get_id() {
println!("loaded config file for client '{id}'");
}
let Ok(credentials_store) = loaded.try_get_credentials_store() else {
bail!("the loaded config does not have a credentials store information")
};
println!(
"using credentials store at '{}'",
credentials_store.display()
);
let credentials_store = initialise_persistent_storage(credentials_store).await;
let version = args.version;
let raw_key = args.key_data()?;
import_master_verification_key(credentials_store, raw_key, version).await?;
Ok(())
}
@@ -6,7 +6,8 @@ use anyhow::bail;
use clap::ArgGroup;
use clap::Parser;
use nym_credential_storage::initialise_persistent_storage;
use nym_id::import_credential;
use nym_id::import_credential::import_full_ticketbook;
use nym_id::import_standalone_ticketbook;
use std::fs;
use std::path::PathBuf;
@@ -15,7 +16,10 @@ fn parse_encoded_credential_data(raw: &str) -> bs58::decode::Result<Vec<u8>> {
}
#[derive(Debug, Parser)]
#[clap(group(ArgGroup::new("cred_data").required(true)))]
#[clap(
group(ArgGroup::new("cred_data").required(true)),
group(ArgGroup::new("type").required(true)),
)]
pub struct Args {
/// Config file of the client that is supposed to use the credential.
#[clap(long)]
@@ -29,13 +33,36 @@ pub struct Args {
#[clap(long, group = "cred_data")]
pub(crate) credential_path: Option<PathBuf>,
/// Specifies whether we're attempting to import a standalone ticketbook (i.e. serialised `IssuedTicketBook`)
#[clap(long, group = "type")]
pub(crate) standalone: bool,
/// Specifies whether we're attempting to import full ticketboot
/// (i.e. one that **might** contain required global signatures; that is serialised `ImportableTicketBook`)
#[clap(long, group = "type")]
pub(crate) full: bool,
// currently hidden as there exists only a single serialization standard
#[clap(long, hide = true)]
pub(crate) version: Option<u8>,
}
impl Args {
fn credential_data(self) -> anyhow::Result<Vec<u8>> {
let data = match self.credential_data {
Some(data) => data,
None => {
// SAFETY: one of those arguments must have been set
#[allow(clippy::unwrap_used)]
fs::read(self.credential_path.unwrap())?
}
};
Ok(data)
}
}
pub async fn execute(args: Args) -> anyhow::Result<()> {
let loaded = CommonConfigsWrapper::try_load(args.client_config)?;
let loaded = CommonConfigsWrapper::try_load(&args.client_config)?;
if let Ok(id) = loaded.try_get_id() {
println!("loaded config file for client '{id}'");
@@ -51,14 +78,18 @@ pub async fn execute(args: Args) -> anyhow::Result<()> {
);
let credentials_store = initialise_persistent_storage(credentials_store).await;
let raw_credential = match args.credential_data {
Some(data) => data,
None => {
// SAFETY: one of those arguments must have been set
fs::read(args.credential_path.unwrap())?
}
};
let version = args.version;
let standalone = args.standalone;
let full = args.full;
let raw_credential = args.credential_data()?;
if standalone {
import_standalone_ticketbook(credentials_store, raw_credential, version).await?;
} else {
// sanity check; clap should have ensured it
assert!(full);
import_full_ticketbook(credentials_store, raw_credential, version).await?;
}
import_credential(credentials_store, raw_credential, args.version).await?;
Ok(())
}
@@ -0,0 +1,170 @@
// Copyright 2022-2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::context::SigningClient;
use crate::utils::CommonConfigsWrapper;
use anyhow::{anyhow, bail};
use clap::ArgGroup;
use clap::Parser;
use nym_credential_storage::initialise_persistent_storage;
use nym_credential_storage::storage::Storage;
use nym_credential_utils::utils;
use nym_credentials::ecash::bandwidth::serialiser::VersionedSerialise;
use nym_credentials::{
AggregatedCoinIndicesSignatures, AggregatedExpirationDateSignatures, EpochVerificationKey,
};
use nym_credentials_interface::TicketType;
use nym_crypto::asymmetric::identity;
use std::fs;
use std::path::PathBuf;
use tempfile::NamedTempFile;
#[derive(Debug, Parser)]
#[clap(
group(ArgGroup::new("output").required(true)),
)]
pub struct Args {
/// Specify which type of ticketbook should be issued
#[clap(long, default_value_t = TicketType::V1MixnetEntry)]
pub(crate) ticketbook_type: TicketType,
/// Config file of the client that is supposed to use the credential.
#[clap(long, group = "output")]
pub(crate) client_config: Option<PathBuf>,
/// Output file for the ticketbook
#[clap(long, group = "output", requires = "bs58_encoded_client_secret")]
pub(crate) output_file: Option<PathBuf>,
/// Specifies whether the output file should use binary or bs58 encoded data
#[clap(long, requires = "output_file")]
pub(crate) bs58_output: bool,
/// Specifies whether the file output should contain expiration date signatures
#[clap(long, requires = "output_file")]
pub(crate) include_expiration_date_signatures: bool,
/// Specifies whether the file output should contain coin index signatures
#[clap(long, requires = "output_file")]
pub(crate) include_coin_index_signatures: bool,
/// Specifies whether the file output should contain master verification key
#[clap(long, requires = "output_file")]
pub(crate) include_master_verification_key: bool,
/// Secret value that's used for deriving underlying ecash keypair
#[clap(long)]
pub(crate) bs58_encoded_client_secret: Option<String>,
}
async fn issue_client_ticketbook(
config_path: PathBuf,
ticketbook_type: TicketType,
client: SigningClient,
) -> anyhow::Result<()> {
let loaded = CommonConfigsWrapper::try_load(config_path)?;
if let Ok(id) = loaded.try_get_id() {
println!("loaded config file for client '{id}'");
}
let Ok(credentials_store) = loaded.try_get_credentials_store() else {
bail!("the loaded config does not have a credentials store information")
};
let Ok(private_id_key) = loaded.try_get_private_id_key() else {
bail!("the loaded config does not have a public id key information")
};
println!(
"using credentials store at '{}'",
credentials_store.display()
);
let persistent_storage = initialise_persistent_storage(credentials_store).await;
let private_id_key: identity::PrivateKey = nym_pemstore::load_key(private_id_key)?;
utils::issue_credential(
&client,
&persistent_storage,
&private_id_key.to_bytes(),
ticketbook_type,
)
.await?;
Ok(())
}
async fn issue_to_file(args: Args, client: SigningClient) -> anyhow::Result<()> {
// those MUST HAVE been specified; clap ensures it
let output_file = args.output_file.unwrap();
let secret = bs58::decode(&args.bs58_encoded_client_secret.unwrap()).into_vec()?;
let temp_credential_store_file = NamedTempFile::new()?;
let credential_store_path = temp_credential_store_file.into_temp_path();
let credentials_store = initialise_persistent_storage(credential_store_path).await;
utils::issue_credential(&client, &credentials_store, &secret, args.ticketbook_type).await?;
let ticketbook = credentials_store
.get_next_unspent_usable_ticketbook(0)
.await?
.ok_or(anyhow!("we just issued a ticketbook, it must be present!"))?
.ticketbook;
let expiration_date = ticketbook.expiration_date();
let epoch_id = ticketbook.epoch_id();
let mut exported = ticketbook.begin_export();
if args.include_expiration_date_signatures {
let signatures = credentials_store
.get_expiration_date_signatures(expiration_date)
.await?
.ok_or(anyhow!("missing expiration date signatures!"))?;
exported.with_expiration_date_signatures(&AggregatedExpirationDateSignatures {
epoch_id,
expiration_date,
signatures,
});
}
if args.include_coin_index_signatures {
let signatures = credentials_store
.get_coin_index_signatures(epoch_id)
.await?
.ok_or(anyhow!("missing coin index signatures!"))?;
exported.with_coin_index_signatures(&AggregatedCoinIndicesSignatures {
epoch_id,
signatures,
});
}
if args.include_master_verification_key {
let key = credentials_store
.get_master_verification_key(epoch_id)
.await?
.ok_or(anyhow!("missing master verification key!"))?;
exported.with_master_verification_key(&EpochVerificationKey { epoch_id, key });
}
let data = exported.pack().data;
if args.bs58_output {
fs::write(output_file, bs58::encode(&data).into_string())?;
} else {
fs::write(output_file, &data)?;
}
Ok(())
}
pub async fn execute(args: Args, client: SigningClient) -> anyhow::Result<()> {
if let Some(client_config) = args.client_config {
return issue_client_ticketbook(client_config, args.ticketbook_type, client).await;
}
issue_to_file(args, client).await
}
@@ -3,6 +3,9 @@
use clap::{Args, Subcommand};
pub mod import_coin_index_signatures;
pub mod import_expiration_date_signatures;
pub mod import_master_verification_key;
pub mod import_ticket_book;
pub mod issue_ticket_book;
pub mod recover_ticket_book;
@@ -19,4 +22,7 @@ pub enum EcashCommands {
IssueTicketBook(issue_ticket_book::Args),
RecoverTicketBook(recover_ticket_book::Args),
ImportTicketBook(import_ticket_book::Args),
ImportCoinIndexSignatures(import_coin_index_signatures::Args),
ImportExpirationDateSignatures(import_expiration_date_signatures::Args),
ImportMasterVerificationKey(import_master_verification_key::Args),
}
+1 -1
View File
@@ -1,7 +1,7 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
pub mod coconut;
pub mod context;
pub mod ecash;
pub mod utils;
pub mod validator;
@@ -0,0 +1,13 @@
/*
* Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
* SPDX-License-Identifier: Apache-2.0
*/
ALTER TABLE master_verification_key
ADD COLUMN serialization_revision INTEGER NOT NULL default 1;
ALTER TABLE coin_indices_signatures
ADD COLUMN serialization_revision INTEGER NOT NULL default 1;
ALTER TABLE expiration_date_signatures
ADD COLUMN serialization_revision INTEGER NOT NULL default 1;
@@ -5,6 +5,10 @@ use crate::models::{BasicTicketbookInformation, RetrievedPendingTicketbook, Retr
use nym_compact_ecash::scheme::coin_indices_signatures::AnnotatedCoinIndexSignature;
use nym_compact_ecash::scheme::expiration_date_signatures::AnnotatedExpirationDateSignature;
use nym_compact_ecash::VerificationKeyAuth;
use nym_credentials::ecash::bandwidth::serialiser::keys::EpochVerificationKey;
use nym_credentials::ecash::bandwidth::serialiser::signatures::{
AggregatedCoinIndicesSignatures, AggregatedExpirationDateSignatures,
};
use nym_credentials::ecash::bandwidth::serialiser::VersionedSerialise;
use nym_credentials::{IssuanceTicketBook, IssuedTicketBook};
use nym_ecash_time::Date;
@@ -192,14 +196,10 @@ impl MemoryEcachTicketbookManager {
guard.master_vk.get(&epoch_id).cloned()
}
pub(crate) async fn insert_master_verification_key(
&self,
epoch_id: u64,
key: &VerificationKeyAuth,
) {
pub(crate) async fn insert_master_verification_key(&self, key: &EpochVerificationKey) {
let mut guard = self.inner.write().await;
guard.master_vk.insert(epoch_id, key.clone());
guard.master_vk.insert(key.epoch_id, key.key.clone());
}
pub(crate) async fn get_coin_index_signatures(
@@ -213,12 +213,13 @@ impl MemoryEcachTicketbookManager {
pub(crate) async fn insert_coin_index_signatures(
&self,
epoch_id: u64,
sigs: &[AnnotatedCoinIndexSignature],
sigs: &AggregatedCoinIndicesSignatures,
) {
let mut guard = self.inner.write().await;
guard.coin_indices_sigs.insert(epoch_id, sigs.to_vec());
guard
.coin_indices_sigs
.insert(sigs.epoch_id, sigs.signatures.clone());
}
pub(crate) async fn get_expiration_date_signatures(
@@ -232,14 +233,12 @@ impl MemoryEcachTicketbookManager {
pub(crate) async fn insert_expiration_date_signatures(
&self,
_epoch_id: u64,
expiration_date: Date,
sigs: &[AnnotatedExpirationDateSignature],
sigs: &AggregatedExpirationDateSignatures,
) {
let mut guard = self.inner.write().await;
guard
.expiration_date_sigs
.insert(expiration_date, sigs.to_vec());
.insert(sigs.expiration_date, sigs.signatures.clone());
}
}
@@ -2,8 +2,8 @@
// SPDX-License-Identifier: Apache-2.0
use crate::models::{
BasicTicketbookInformation, RawExpirationDateSignatures, StoredIssuedTicketbook,
StoredPendingTicketbook,
BasicTicketbookInformation, RawCoinIndexSignatures, RawExpirationDateSignatures,
RawVerificationKey, StoredIssuedTicketbook, StoredPendingTicketbook,
};
use nym_ecash_time::Date;
use sqlx::{Executor, Sqlite, Transaction};
@@ -151,25 +151,30 @@ impl SqliteEcashTicketbookManager {
pub(crate) async fn get_master_verification_key(
&self,
epoch_id: i64,
) -> Result<Option<Vec<u8>>, sqlx::Error> {
sqlx::query!(
"SELECT serialised_key FROM master_verification_key WHERE epoch_id = ?",
) -> Result<Option<RawVerificationKey>, sqlx::Error> {
sqlx::query_as!(
RawVerificationKey,
r#"
SELECT epoch_id as "epoch_id: u32", serialised_key, serialization_revision as "serialization_revision: u8"
FROM master_verification_key WHERE epoch_id = ?
"#,
epoch_id
)
.fetch_optional(&self.connection_pool)
.await
.map(|maybe_record| maybe_record.map(|r| r.serialised_key))
}
pub(crate) async fn insert_master_verification_key(
&self,
serialisation_revision: u8,
epoch_id: i64,
data: &[u8],
) -> Result<(), sqlx::Error> {
sqlx::query!(
"INSERT INTO master_verification_key(epoch_id, serialised_key) VALUES (?, ?)",
"INSERT INTO master_verification_key(epoch_id, serialised_key, serialization_revision) VALUES (?, ?, ?)",
epoch_id,
data
data,
serialisation_revision
)
.execute(&self.connection_pool)
.await?;
@@ -179,25 +184,30 @@ impl SqliteEcashTicketbookManager {
pub(crate) async fn get_coin_index_signatures(
&self,
epoch_id: i64,
) -> Result<Option<Vec<u8>>, sqlx::Error> {
sqlx::query!(
"SELECT serialised_signatures FROM coin_indices_signatures WHERE epoch_id = ?",
) -> Result<Option<RawCoinIndexSignatures>, sqlx::Error> {
sqlx::query_as!(
RawCoinIndexSignatures,
r#"
SELECT epoch_id as "epoch_id: u32", serialised_signatures, serialization_revision as "serialization_revision: u8"
FROM coin_indices_signatures WHERE epoch_id = ?
"#,
epoch_id
)
.fetch_optional(&self.connection_pool)
.await
.map(|maybe_record| maybe_record.map(|r| r.serialised_signatures))
}
pub(crate) async fn insert_coin_index_signatures(
&self,
serialisation_revision: u8,
epoch_id: i64,
data: &[u8],
) -> Result<(), sqlx::Error> {
sqlx::query!(
"INSERT INTO coin_indices_signatures(epoch_id, serialised_signatures) VALUES (?, ?)",
"INSERT INTO coin_indices_signatures(epoch_id, serialised_signatures, serialization_revision) VALUES (?, ?, ?)",
epoch_id,
data
data,
serialisation_revision
)
.execute(&self.connection_pool)
.await?;
@@ -211,7 +221,7 @@ impl SqliteEcashTicketbookManager {
sqlx::query_as!(
RawExpirationDateSignatures,
r#"
SELECT epoch_id as "epoch_id: u32", serialised_signatures
SELECT epoch_id as "epoch_id: u32", serialised_signatures, serialization_revision as "serialization_revision: u8"
FROM expiration_date_signatures
WHERE expiration_date = ?
"#,
@@ -223,15 +233,20 @@ impl SqliteEcashTicketbookManager {
pub(crate) async fn insert_expiration_date_signatures(
&self,
serialisation_revision: u8,
epoch_id: i64,
expiration_date: Date,
data: &[u8],
) -> Result<(), sqlx::Error> {
sqlx::query!(
"INSERT INTO expiration_date_signatures(expiration_date, epoch_id, serialised_signatures) VALUES (?, ?, ?)",
r#"
INSERT INTO expiration_date_signatures(expiration_date, epoch_id, serialised_signatures, serialization_revision)
VALUES (?, ?, ?, ?)
"#,
expiration_date,
epoch_id,
data
data,
serialisation_revision
)
.execute(&self.connection_pool)
.await?;
@@ -9,6 +9,10 @@ use async_trait::async_trait;
use nym_compact_ecash::scheme::coin_indices_signatures::AnnotatedCoinIndexSignature;
use nym_compact_ecash::scheme::expiration_date_signatures::AnnotatedExpirationDateSignature;
use nym_compact_ecash::VerificationKeyAuth;
use nym_credentials::ecash::bandwidth::serialiser::keys::EpochVerificationKey;
use nym_credentials::ecash::bandwidth::serialiser::signatures::{
AggregatedCoinIndicesSignatures, AggregatedExpirationDateSignatures,
};
use nym_credentials::{IssuanceTicketBook, IssuedTicketBook};
use nym_ecash_time::Date;
use std::fmt::{self, Debug, Formatter};
@@ -119,11 +123,10 @@ impl Storage for EphemeralStorage {
async fn insert_master_verification_key(
&self,
epoch_id: u64,
key: &VerificationKeyAuth,
key: &EpochVerificationKey,
) -> Result<(), Self::StorageError> {
self.storage_manager
.insert_master_verification_key(epoch_id, key)
.insert_master_verification_key(key)
.await;
Ok(())
}
@@ -140,11 +143,10 @@ impl Storage for EphemeralStorage {
async fn insert_coin_index_signatures(
&self,
epoch_id: u64,
data: &[AnnotatedCoinIndexSignature],
signatures: &AggregatedCoinIndicesSignatures,
) -> Result<(), Self::StorageError> {
self.storage_manager
.insert_coin_index_signatures(epoch_id, data)
.insert_coin_index_signatures(signatures)
.await;
Ok(())
}
@@ -161,12 +163,10 @@ impl Storage for EphemeralStorage {
async fn insert_expiration_date_signatures(
&self,
epoch_id: u64,
expiration_date: Date,
data: &[AnnotatedExpirationDateSignature],
signatures: &AggregatedExpirationDateSignatures,
) -> Result<(), Self::StorageError> {
self.storage_manager
.insert_expiration_date_signatures(epoch_id, expiration_date, data)
.insert_expiration_date_signatures(signatures)
.await;
Ok(())
}
+15
View File
@@ -62,4 +62,19 @@ pub struct StoredPendingTicketbook {
pub struct RawExpirationDateSignatures {
pub epoch_id: u32,
pub serialised_signatures: Vec<u8>,
pub serialization_revision: u8,
}
#[cfg_attr(not(target_arch = "wasm32"), derive(sqlx::FromRow))]
pub struct RawCoinIndexSignatures {
pub epoch_id: u32,
pub serialised_signatures: Vec<u8>,
pub serialization_revision: u8,
}
#[cfg_attr(not(target_arch = "wasm32"), derive(sqlx::FromRow))]
pub struct RawVerificationKey {
pub epoch_id: u32,
pub serialised_key: Vec<u8>,
pub serialization_revision: u8,
}
@@ -1,54 +0,0 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::error::StorageError;
use bincode::Options;
use nym_compact_ecash::scheme::coin_indices_signatures::AnnotatedCoinIndexSignature;
use nym_compact_ecash::scheme::expiration_date_signatures::AnnotatedExpirationDateSignature;
use serde::{Deserialize, Serialize};
#[derive(Serialize)]
struct StorageBorrowedSerdeWrapper<'a, T>(&'a T);
#[derive(Serialize, Deserialize)]
struct StorageSerdeWrapper<T>(T);
pub(crate) fn serialise_coin_index_signatures(sigs: &[AnnotatedCoinIndexSignature]) -> Vec<u8> {
storage_serialiser()
.serialize(&StorageBorrowedSerdeWrapper(&sigs))
.unwrap()
}
pub(crate) fn deserialise_coin_index_signatures(
raw: &[u8],
) -> Result<Vec<AnnotatedCoinIndexSignature>, StorageError> {
let de: StorageSerdeWrapper<_> = storage_serialiser().deserialize(raw).map_err(|_| {
StorageError::database_inconsistency("malformed stored coin index signatures")
})?;
Ok(de.0)
}
pub(crate) fn serialise_expiration_date_signatures(
sigs: &[AnnotatedExpirationDateSignature],
) -> Vec<u8> {
storage_serialiser()
.serialize(&StorageBorrowedSerdeWrapper(&sigs))
.unwrap()
}
pub(crate) fn deserialise_expiration_date_signatures(
raw: &[u8],
) -> Result<Vec<AnnotatedExpirationDateSignature>, StorageError> {
let de: StorageSerdeWrapper<_> = storage_serialiser().deserialize(raw).map_err(|_| {
StorageError::database_inconsistency("malformed expiration date signatures")
})?;
Ok(de.0)
}
// storage serialiser used for non-critical data, such as global expiration signatures or master verification keys,
// i.e. data that could always be queried for again if malformed
fn storage_serialiser() -> impl bincode::Options {
bincode::DefaultOptions::new()
.with_big_endian()
.with_varint_encoding()
}
@@ -0,0 +1,44 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::error::StorageError;
use bincode::Options;
use nym_compact_ecash::scheme::coin_indices_signatures::AnnotatedCoinIndexSignature;
use nym_compact_ecash::scheme::expiration_date_signatures::AnnotatedExpirationDateSignature;
use nym_compact_ecash::VerificationKeyAuth;
use serde::Deserialize;
#[derive(Deserialize)]
struct StorageSerdeWrapper<T>(T);
pub(crate) fn deserialise_v1_expiration_date_signatures(
raw: &[u8],
) -> Result<Vec<AnnotatedExpirationDateSignature>, StorageError> {
let de: StorageSerdeWrapper<_> = v1_signatures_serialiser().deserialize(raw).map_err(|_| {
StorageError::database_inconsistency("malformed expiration date signatures")
})?;
Ok(de.0)
}
pub(crate) fn deserialise_v1_coin_index_signatures(
raw: &[u8],
) -> Result<Vec<AnnotatedCoinIndexSignature>, StorageError> {
let de: StorageSerdeWrapper<_> = v1_signatures_serialiser().deserialize(raw).map_err(|_| {
StorageError::database_inconsistency("malformed stored coin index signatures")
})?;
Ok(de.0)
}
pub(crate) fn deserialise_v1_master_verification_key(
raw: &[u8],
) -> Result<VerificationKeyAuth, StorageError> {
VerificationKeyAuth::from_bytes(raw).map_err(|_| {
StorageError::database_inconsistency("malformed stored master verification key")
})
}
fn v1_signatures_serialiser() -> impl bincode::Options {
bincode::DefaultOptions::new()
.with_big_endian()
.with_varint_encoding()
}
@@ -1,14 +1,16 @@
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
mod legacy_helpers;
use crate::backends::sqlite::{
get_next_unspent_ticketbook, increase_used_ticketbook_tickets, SqliteEcashTicketbookManager,
};
use crate::error::StorageError;
use crate::models::{BasicTicketbookInformation, RetrievedPendingTicketbook, RetrievedTicketbook};
use crate::persistent_storage::helpers::{
deserialise_coin_index_signatures, deserialise_expiration_date_signatures,
serialise_coin_index_signatures, serialise_expiration_date_signatures,
use crate::persistent_storage::legacy_helpers::{
deserialise_v1_coin_index_signatures, deserialise_v1_expiration_date_signatures,
deserialise_v1_master_verification_key,
};
use crate::storage::Storage;
use async_trait::async_trait;
@@ -16,6 +18,10 @@ use log::{debug, error};
use nym_compact_ecash::scheme::coin_indices_signatures::AnnotatedCoinIndexSignature;
use nym_compact_ecash::scheme::expiration_date_signatures::AnnotatedExpirationDateSignature;
use nym_compact_ecash::VerificationKeyAuth;
use nym_credentials::ecash::bandwidth::serialiser::keys::EpochVerificationKey;
use nym_credentials::ecash::bandwidth::serialiser::signatures::{
AggregatedCoinIndicesSignatures, AggregatedExpirationDateSignatures,
};
use nym_credentials::ecash::bandwidth::serialiser::VersionedSerialise;
use nym_credentials::{IssuanceTicketBook, IssuedTicketBook};
use nym_ecash_time::{ecash_today, Date, EcashTime};
@@ -23,8 +29,6 @@ use sqlx::ConnectOptions;
use std::path::Path;
use zeroize::Zeroizing;
mod helpers;
// note that clone here is fine as upon cloning the same underlying pool will be used
#[derive(Clone)]
pub struct PersistentStorage {
@@ -229,21 +233,24 @@ impl Storage for PersistentStorage {
return Ok(None);
};
let master_vk = VerificationKeyAuth::from_bytes(&raw).map_err(|_| {
StorageError::database_inconsistency("malformed stored master verification key")
})?;
Ok(Some(master_vk))
match raw.serialization_revision {
1 => deserialise_v1_master_verification_key(&raw.serialised_key).map(Some),
other => {
let deserialised = EpochVerificationKey::try_unpack(&raw.serialised_key, other)
.map_err(|err| StorageError::database_inconsistency(err.to_string()))?;
Ok(Some(deserialised.key))
}
}
}
async fn insert_master_verification_key(
&self,
epoch_id: u64,
key: &VerificationKeyAuth,
key: &EpochVerificationKey,
) -> Result<(), Self::StorageError> {
let packed = key.pack();
Ok(self
.storage_manager
.insert_master_verification_key(epoch_id as i64, &key.to_bytes())
.insert_master_verification_key(packed.revision, key.epoch_id as i64, &packed.data)
.await?)
}
@@ -259,16 +266,24 @@ impl Storage for PersistentStorage {
return Ok(None);
};
Ok(Some(deserialise_coin_index_signatures(&raw)?))
match raw.serialization_revision {
1 => deserialise_v1_coin_index_signatures(&raw.serialised_signatures).map(Some),
other => {
let deserialised =
AggregatedCoinIndicesSignatures::try_unpack(&raw.serialised_signatures, other)
.map_err(|err| StorageError::database_inconsistency(err.to_string()))?;
Ok(Some(deserialised.signatures))
}
}
}
async fn insert_coin_index_signatures(
&self,
epoch_id: u64,
sigs: &[AnnotatedCoinIndexSignature],
signatures: &AggregatedCoinIndicesSignatures,
) -> Result<(), Self::StorageError> {
let packed = signatures.pack();
self.storage_manager
.insert_coin_index_signatures(epoch_id as i64, &serialise_coin_index_signatures(sigs))
.insert_coin_index_signatures(packed.revision, signatures.epoch_id as i64, &packed.data)
.await?;
Ok(())
}
@@ -285,22 +300,30 @@ impl Storage for PersistentStorage {
return Ok(None);
};
Ok(Some(deserialise_expiration_date_signatures(
&raw.serialised_signatures,
)?))
match raw.serialization_revision {
1 => deserialise_v1_expiration_date_signatures(&raw.serialised_signatures).map(Some),
other => {
let deserialised = AggregatedExpirationDateSignatures::try_unpack(
&raw.serialised_signatures,
other,
)
.map_err(|err| StorageError::database_inconsistency(err.to_string()))?;
Ok(Some(deserialised.signatures))
}
}
}
async fn insert_expiration_date_signatures(
&self,
epoch_id: u64,
expiration_date: Date,
sigs: &[AnnotatedExpirationDateSignature],
signatures: &AggregatedExpirationDateSignatures,
) -> Result<(), Self::StorageError> {
let packed = signatures.pack();
self.storage_manager
.insert_expiration_date_signatures(
epoch_id as i64,
expiration_date,
&serialise_expiration_date_signatures(sigs),
packed.revision,
signatures.epoch_id as i64,
signatures.expiration_date,
&packed.data,
)
.await?;
Ok(())
+7 -7
View File
@@ -6,6 +6,10 @@ use async_trait::async_trait;
use nym_compact_ecash::scheme::coin_indices_signatures::AnnotatedCoinIndexSignature;
use nym_compact_ecash::scheme::expiration_date_signatures::AnnotatedExpirationDateSignature;
use nym_compact_ecash::VerificationKeyAuth;
use nym_credentials::ecash::bandwidth::serialiser::keys::EpochVerificationKey;
use nym_credentials::ecash::bandwidth::serialiser::signatures::{
AggregatedCoinIndicesSignatures, AggregatedExpirationDateSignatures,
};
use nym_credentials::{IssuanceTicketBook, IssuedTicketBook};
use nym_ecash_time::Date;
use std::error::Error;
@@ -64,8 +68,7 @@ pub trait Storage: Send + Sync {
async fn insert_master_verification_key(
&self,
epoch_id: u64,
key: &VerificationKeyAuth,
key: &EpochVerificationKey,
) -> Result<(), Self::StorageError>;
async fn get_coin_index_signatures(
@@ -75,8 +78,7 @@ pub trait Storage: Send + Sync {
async fn insert_coin_index_signatures(
&self,
epoch_id: u64,
data: &[AnnotatedCoinIndexSignature],
signatures: &AggregatedCoinIndicesSignatures,
) -> Result<(), Self::StorageError>;
async fn get_expiration_date_signatures(
@@ -86,8 +88,6 @@ pub trait Storage: Send + Sync {
async fn insert_expiration_date_signatures(
&self,
epoch_id: u64,
expiration_date: Date,
data: &[AnnotatedExpirationDateSignature],
signatures: &AggregatedExpirationDateSignatures,
) -> Result<(), Self::StorageError>;
}
+1 -1
View File
@@ -28,7 +28,7 @@ pub use nym_compact_ecash::{
withdrawal_request, Base58, BlindedSignature, Bytable, EncodedDate, EncodedTicketType,
PartialWallet, PayInfo, PublicKeyUser, SecretKeyUser, VerificationKeyAuth, WithdrawalRequest,
};
use nym_ecash_time::{ecash_today, EcashTime};
pub use nym_ecash_time::{ecash_today, EcashTime};
#[derive(Debug, Clone)]
pub struct CredentialSigningData {
+1
View File
@@ -25,6 +25,7 @@ nym-api-requests = { path = "../../nym-api/nym-api-requests" }
nym-validator-client = { path = "../client-libs/validator-client", default-features = false }
nym-ecash-contract-common = { path = "../cosmwasm-smart-contracts/ecash-contract" }
nym-network-defaults = { path = "../network-defaults" }
nym-serde-helpers = { path = "../serde-helpers", features = ["date"] }
[dev-dependencies]
rand = { workspace = true }
@@ -0,0 +1,118 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::ecash::bandwidth::serialiser::keys::EpochVerificationKey;
use crate::ecash::bandwidth::serialiser::signatures::{
AggregatedCoinIndicesSignatures, AggregatedExpirationDateSignatures,
};
use crate::ecash::bandwidth::{
issued::IssuedTicketBook,
serialiser::{VersionSerialised, VersionedSerialise},
};
use crate::Error;
use serde::de::DeserializeOwned;
use serde::{Deserialize, Serialize};
use zeroize::{Zeroize, ZeroizeOnDrop};
pub struct DecodedImportableTicketBook {
pub ticketbook: IssuedTicketBook,
pub expiration_date_signatures: Option<AggregatedExpirationDateSignatures>,
pub coin_index_signatures: Option<AggregatedCoinIndicesSignatures>,
pub master_verification_key: Option<EpochVerificationKey>,
}
#[derive(Zeroize, ZeroizeOnDrop, Serialize, Deserialize)]
pub struct ImportableTicketBook {
pub serialised_ticketbook: VersionSerialised<IssuedTicketBook>,
#[zeroize(skip)]
pub serialised_expiration_date_signatures:
Option<VersionSerialised<AggregatedExpirationDateSignatures>>,
#[zeroize(skip)]
pub serialised_coin_index_signatures:
Option<VersionSerialised<AggregatedCoinIndicesSignatures>>,
#[zeroize(skip)]
pub serialised_master_verification_key: Option<VersionSerialised<EpochVerificationKey>>,
}
impl From<IssuedTicketBook> for ImportableTicketBook {
fn from(ticketbook: IssuedTicketBook) -> Self {
ImportableTicketBook {
serialised_ticketbook: ticketbook.pack(),
serialised_expiration_date_signatures: None,
serialised_coin_index_signatures: None,
serialised_master_verification_key: None,
}
}
}
impl ImportableTicketBook {
pub fn with_expiration_date_signatures(
&mut self,
signatures: &AggregatedExpirationDateSignatures,
) -> &mut Self {
self.serialised_expiration_date_signatures = Some(signatures.pack());
self
}
pub fn with_coin_index_signatures(
&mut self,
signatures: &AggregatedCoinIndicesSignatures,
) -> &mut Self {
self.serialised_coin_index_signatures = Some(signatures.pack());
self
}
pub fn with_master_verification_key(&mut self, key: &EpochVerificationKey) -> &mut Self {
self.serialised_master_verification_key = Some(key.pack());
self
}
pub fn finalize_export(self) -> Vec<u8> {
self.pack().data
}
pub fn try_unpack_full(&self) -> Result<DecodedImportableTicketBook, Error> {
Ok(DecodedImportableTicketBook {
ticketbook: self.serialised_ticketbook.try_unpack()?,
expiration_date_signatures: self
.serialised_expiration_date_signatures
.as_ref()
.map(|sigs| sigs.try_unpack())
.transpose()?,
coin_index_signatures: self
.serialised_coin_index_signatures
.as_ref()
.map(|sigs| sigs.try_unpack())
.transpose()?,
master_verification_key: self
.serialised_master_verification_key
.as_ref()
.map(|key| key.try_unpack())
.transpose()?,
})
}
}
impl VersionedSerialise for ImportableTicketBook {
const CURRENT_SERIALISATION_REVISION: u8 = 1;
fn try_unpack(b: &[u8], revision: impl Into<Option<u8>>) -> Result<Self, Error>
where
Self: DeserializeOwned,
{
let revision = revision
.into()
.unwrap_or(<Self as VersionedSerialise>::CURRENT_SERIALISATION_REVISION);
match revision {
1 => Self::try_unpack_current(b),
_ => Err(Error::UnknownSerializationRevision { revision }),
}
}
}
@@ -177,7 +177,7 @@ impl IssuanceTicketBook {
}
// ideally this would have been generic over credential type, but we really don't need secp256k1 keys for bandwidth vouchers
pub async fn obtain_partial_bandwidth_voucher_credential(
pub async fn obtain_partial_ticketbook_credential(
&self,
client: &nym_validator_client::client::NymApiClient,
signer_index: u64,
@@ -191,13 +191,6 @@ impl IssuanceTicketBook {
self.unblind_signature(validator_vk, &signing_data, blinded_signature, signer_index)
}
// pub fn unchecked_aggregate_signature_shares(
// &self,
// shares: &[SignatureShare],
// ) -> Result<Signature, Error> {
// aggregate_signature_shares(shares).map_err(Error::SignatureAggregationError)
// }
pub fn aggregate_signature_shares(
&self,
verification_key: &VerificationKeyAuth,
@@ -1,6 +1,7 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::ecash::bandwidth::importable::ImportableTicketBook;
use crate::ecash::bandwidth::serialiser::VersionedSerialise;
use crate::ecash::bandwidth::CredentialSpendingData;
use crate::ecash::utils::ecash_today;
@@ -153,6 +154,10 @@ impl IssuedTicketBook {
epoch_id: self.epoch_id,
})
}
pub fn begin_export(self) -> ImportableTicketBook {
self.into()
}
}
impl VersionedSerialise for IssuedTicketBook {
@@ -5,6 +5,7 @@ pub use issuance::IssuanceTicketBook;
pub use issued::IssuedTicketBook;
pub use nym_credentials_interface::{CredentialSigningData, CredentialSpendingData};
pub mod importable;
pub mod issuance;
pub mod issued;
pub mod serialiser;
@@ -0,0 +1,35 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::ecash::bandwidth::serialiser::VersionedSerialise;
use crate::Error;
use nym_credentials_interface::VerificationKeyAuth;
use serde::de::DeserializeOwned;
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct EpochVerificationKey {
pub epoch_id: u64,
pub key: VerificationKeyAuth,
}
impl VersionedSerialise for EpochVerificationKey {
// we start with revision 2 as the initial, 1, only contained the inner `key` field data
const CURRENT_SERIALISATION_REVISION: u8 = 2;
fn try_unpack(b: &[u8], revision: impl Into<Option<u8>>) -> Result<Self, Error>
where
Self: DeserializeOwned,
{
let revision = revision
.into()
.unwrap_or(<Self as VersionedSerialise>::CURRENT_SERIALISATION_REVISION);
match revision {
1 => Err(Error::UnsupportedSerializationRevision { revision }),
2 => Self::try_unpack_current(b),
_ => Err(Error::UnknownSerializationRevision { revision }),
}
}
}
@@ -5,17 +5,33 @@ use crate::ecash::bandwidth::issued::CURRENT_SERIALIZATION_REVISION;
use crate::Error;
use bincode::Options;
use serde::de::DeserializeOwned;
use serde::Serialize;
use serde::{Deserialize, Serialize};
use std::marker::PhantomData;
use zeroize::Zeroize;
pub mod keys;
pub mod signatures;
#[derive(Zeroize, Serialize, Deserialize)]
pub struct VersionSerialised<T: ?Sized> {
pub data: Vec<u8>,
pub revision: u8,
// still wondering if there's any point in having the phantom in here
#[zeroize(skip)]
#[serde(skip)]
_phantom: PhantomData<T>,
}
impl<T> VersionSerialised<T> {
pub fn try_unpack(&self) -> Result<T, Error>
where
T: VersionedSerialise + DeserializeOwned,
{
T::try_unpack(&self.data, self.revision)
}
}
pub trait VersionedSerialise {
const CURRENT_SERIALISATION_REVISION: u8;
@@ -0,0 +1,66 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::ecash::bandwidth::serialiser::VersionedSerialise;
use crate::Error;
use nym_credentials_interface::{AnnotatedCoinIndexSignature, AnnotatedExpirationDateSignature};
use serde::de::DeserializeOwned;
use serde::{Deserialize, Serialize};
use time::Date;
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct AggregatedExpirationDateSignatures {
pub epoch_id: u64,
#[serde(with = "nym_serde_helpers::date")]
pub expiration_date: Date,
pub signatures: Vec<AnnotatedExpirationDateSignature>,
}
impl VersionedSerialise for AggregatedExpirationDateSignatures {
// we start with revision 2 as the initial, 1, only contained the inner `signatures` field data
const CURRENT_SERIALISATION_REVISION: u8 = 2;
fn try_unpack(b: &[u8], revision: impl Into<Option<u8>>) -> Result<Self, Error>
where
Self: DeserializeOwned,
{
let revision = revision
.into()
.unwrap_or(<Self as VersionedSerialise>::CURRENT_SERIALISATION_REVISION);
match revision {
1 => Err(Error::UnsupportedSerializationRevision { revision }),
2 => Self::try_unpack_current(b),
_ => Err(Error::UnknownSerializationRevision { revision }),
}
}
}
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct AggregatedCoinIndicesSignatures {
pub epoch_id: u64,
pub signatures: Vec<AnnotatedCoinIndexSignature>,
}
impl VersionedSerialise for AggregatedCoinIndicesSignatures {
// we start with revision 2 as the initial, 1, only contained the inner `signatures` field data
const CURRENT_SERIALISATION_REVISION: u8 = 2;
fn try_unpack(b: &[u8], revision: impl Into<Option<u8>>) -> Result<Self, Error>
where
Self: DeserializeOwned,
{
let revision = revision
.into()
.unwrap_or(<Self as VersionedSerialise>::CURRENT_SERIALISATION_REVISION);
match revision {
1 => Err(Error::UnsupportedSerializationRevision { revision }),
2 => Self::try_unpack_current(b),
_ => Err(Error::UnknownSerializationRevision { revision }),
}
}
}
+1 -1
View File
@@ -151,7 +151,7 @@ pub async fn obtain_aggregate_wallet(
);
match voucher
.obtain_partial_bandwidth_voucher_credential(
.obtain_partial_ticketbook_credential(
&ecash_api_client.api_client,
ecash_api_client.node_id,
&ecash_api_client.verification_key,
+4 -1
View File
@@ -22,7 +22,10 @@ pub enum Error {
revision: u8,
},
#[error("unknown credential serializatio revision {revision}. the current (and max supported) version is {CURRENT_SERIALIZATION_REVISION}")]
#[error("unsupported data serialization revision {revision}. the current (and max supported) version is {CURRENT_SERIALIZATION_REVISION}")]
UnsupportedSerializationRevision { revision: u8 },
#[error("unknown data serialization revision {revision}. the current (and max supported) version is {CURRENT_SERIALIZATION_REVISION}")]
UnknownSerializationRevision { revision: u8 },
#[error("Could not contact any validator")]
+5
View File
@@ -5,6 +5,11 @@ pub mod ecash;
pub mod error;
pub use ecash::bandwidth::{
importable::{DecodedImportableTicketBook, ImportableTicketBook},
serialiser::{
keys::EpochVerificationKey,
signatures::{AggregatedCoinIndicesSignatures, AggregatedExpirationDateSignatures},
},
CredentialSigningData, CredentialSpendingData, IssuanceTicketBook, IssuedTicketBook,
};
pub use ecash::utils::{aggregate_verification_keys, obtain_aggregate_wallet};
+23 -2
View File
@@ -7,12 +7,33 @@ use time::Date;
#[derive(Debug, Error)]
pub enum NymIdError {
#[error("failed to deserialize provided credential: {source}")]
CredentialDeserializationFailure { source: nym_credentials::Error },
#[error("failed to deserialize provided full ticketbook: {source}")]
FullTicketbookDeserializationFailure { source: nym_credentials::Error },
#[error("failed to deserialize provided ticketbook: {source}")]
TicketbookDeserializationFailure { source: nym_credentials::Error },
#[error("failed to deserialize provided expiration date signatures: {source}")]
ExpirationDateSignaturesDeserializationFailure { source: nym_credentials::Error },
#[error("failed to deserialize provided coin index signatures: {source}")]
CoinIndexSignaturesDeserializationFailure { source: nym_credentials::Error },
#[error("failed to deserialize provided verification key: {source}")]
VerificationKeyDeserializationFailure { source: nym_credentials::Error },
#[error("attempted to import an expired credential (it expired on {expiration})")]
ExpiredCredentialImport { expiration: Date },
#[error("could not import ticketbook expiring at {date} since we do not have corresponding expiration date signatures")]
MissingExpirationDateSignatures { date: Date },
#[error("could not import ticketbook for epoch {epoch_id} since we do not have corresponding coin index signatures")]
MissingCoinIndexSignatures { epoch_id: u64 },
#[error("could not import ticketbook for epoch {epoch_id} since we do not have corresponding master verification key")]
MissingMasterVerificationKey { epoch_id: u64 },
#[error("failed to store credential in the provided store: {source}")]
StorageError {
source: Box<dyn Error + Send + Sync>,
-49
View File
@@ -1,49 +0,0 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::NymIdError;
use nym_credential_storage::storage::Storage;
use nym_credentials::ecash::bandwidth::serialiser::VersionedSerialise;
use nym_credentials::ecash::utils::EcashTime;
use nym_credentials::IssuedTicketBook;
use time::OffsetDateTime;
use tracing::{debug, warn};
use zeroize::Zeroizing;
pub async fn import_credential<S>(
credentials_store: S,
raw_credential: Vec<u8>,
credential_version: impl Into<Option<u8>>,
) -> Result<OffsetDateTime, NymIdError>
where
S: Storage,
<S as Storage>::StorageError: Send + Sync + 'static,
{
let raw_credential = Zeroizing::new(raw_credential);
// note: the type itself implements ZeroizeOnDrop
let ticketbook = IssuedTicketBook::try_unpack(&raw_credential, credential_version)
.map_err(|source| NymIdError::CredentialDeserializationFailure { source })?;
debug!(
"attempting to import credential with expiration date at {}",
ticketbook.expiration_date()
);
if ticketbook.expired() {
warn!("the credential has already expired!");
// technically we can import it, but the gateway will just reject it so what's the point
return Err(NymIdError::ExpiredCredentialImport {
expiration: ticketbook.expiration_date(),
});
}
credentials_store
.insert_issued_ticketbook(&ticketbook)
.await
.map_err(|source| NymIdError::StorageError {
source: Box::new(source),
})?;
Ok(ticketbook.expiration_date().ecash_datetime())
}
@@ -0,0 +1,147 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::NymIdError;
use nym_credential_storage::storage::Storage;
use nym_credentials::{
AggregatedCoinIndicesSignatures, AggregatedExpirationDateSignatures, EpochVerificationKey,
IssuedTicketBook,
};
use tracing::{debug, warn};
pub(crate) async fn import_master_verification_key<S>(
credentials_store: &S,
key: &EpochVerificationKey,
) -> Result<(), NymIdError>
where
S: Storage,
<S as Storage>::StorageError: Send + Sync + 'static,
{
debug!(
"attempting to import master verification key for epoch {}",
key.epoch_id
);
credentials_store
.insert_master_verification_key(key)
.await
.map_err(|source| NymIdError::StorageError {
source: Box::new(source),
})?;
Ok(())
}
pub(crate) async fn import_expiration_date_signatures<S>(
credentials_store: &S,
signatures: &AggregatedExpirationDateSignatures,
) -> Result<(), NymIdError>
where
S: Storage,
<S as Storage>::StorageError: Send + Sync + 'static,
{
debug!(
"attempting to import expiration date signatures with expiration date at {} (epoch: {})",
signatures.expiration_date, signatures.epoch_id
);
credentials_store
.insert_expiration_date_signatures(signatures)
.await
.map_err(|source| NymIdError::StorageError {
source: Box::new(source),
})?;
Ok(())
}
pub(crate) async fn import_coin_index_signatures<S>(
credentials_store: &S,
signatures: &AggregatedCoinIndicesSignatures,
) -> Result<(), NymIdError>
where
S: Storage,
<S as Storage>::StorageError: Send + Sync + 'static,
{
debug!(
"attempting to import coin index signatures for epoch {}",
signatures.epoch_id
);
credentials_store
.insert_coin_index_signatures(signatures)
.await
.map_err(|source| NymIdError::StorageError {
source: Box::new(source),
})?;
Ok(())
}
pub(crate) async fn import_ticketbook<S>(
credentials_store: &S,
ticketbook: &IssuedTicketBook,
) -> Result<(), NymIdError>
where
S: Storage,
<S as Storage>::StorageError: Send + Sync + 'static,
{
debug!(
"attempting to import ticketbook with expiration date at {}",
ticketbook.expiration_date()
);
if ticketbook.expired() {
warn!("the credential has already expired!");
// technically we can import it, but the gateway will just reject it so what's the point
return Err(NymIdError::ExpiredCredentialImport {
expiration: ticketbook.expiration_date(),
});
}
// in order to import the ticketbook we MUST have the appropriate signatures in the storage already
if credentials_store
.get_expiration_date_signatures(ticketbook.expiration_date())
.await
.map_err(|source| NymIdError::StorageError {
source: Box::new(source),
})?
.is_none()
{
return Err(NymIdError::MissingExpirationDateSignatures {
date: ticketbook.expiration_date(),
});
}
if credentials_store
.get_coin_index_signatures(ticketbook.epoch_id())
.await
.map_err(|source| NymIdError::StorageError {
source: Box::new(source),
})?
.is_none()
{
return Err(NymIdError::MissingCoinIndexSignatures {
epoch_id: ticketbook.epoch_id(),
});
}
if credentials_store
.get_master_verification_key(ticketbook.epoch_id())
.await
.map_err(|source| NymIdError::StorageError {
source: Box::new(source),
})?
.is_none()
{
return Err(NymIdError::MissingMasterVerificationKey {
epoch_id: ticketbook.epoch_id(),
});
}
credentials_store
.insert_issued_ticketbook(ticketbook)
.await
.map_err(|source| NymIdError::StorageError {
source: Box::new(source),
})?;
Ok(())
}
+119
View File
@@ -0,0 +1,119 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::NymIdError;
use nym_credential_storage::storage::Storage;
use nym_credentials::ecash::bandwidth::serialiser::keys::EpochVerificationKey;
use nym_credentials::ecash::bandwidth::serialiser::signatures::{
AggregatedCoinIndicesSignatures, AggregatedExpirationDateSignatures,
};
use nym_credentials::ecash::bandwidth::serialiser::VersionedSerialise;
use nym_credentials::ecash::utils::EcashTime;
use nym_credentials::{ImportableTicketBook, IssuedTicketBook};
use time::OffsetDateTime;
use zeroize::Zeroizing;
mod helpers;
pub async fn import_master_verification_key<S>(
credentials_store: S,
raw_key: Vec<u8>,
key_version: impl Into<Option<u8>>,
) -> Result<(), NymIdError>
where
S: Storage,
<S as Storage>::StorageError: Send + Sync + 'static,
{
let key = EpochVerificationKey::try_unpack(&raw_key, key_version)
.map_err(|source| NymIdError::VerificationKeyDeserializationFailure { source })?;
helpers::import_master_verification_key(&credentials_store, &key).await
}
pub async fn import_expiration_date_signatures<S>(
credentials_store: S,
raw_signatures: Vec<u8>,
signatures_version: impl Into<Option<u8>>,
) -> Result<(), NymIdError>
where
S: Storage,
<S as Storage>::StorageError: Send + Sync + 'static,
{
let signatures =
AggregatedExpirationDateSignatures::try_unpack(&raw_signatures, signatures_version)
.map_err(
|source| NymIdError::ExpirationDateSignaturesDeserializationFailure { source },
)?;
helpers::import_expiration_date_signatures(&credentials_store, &signatures).await
}
pub async fn import_coin_index_signatures<S>(
credentials_store: S,
raw_signatures: Vec<u8>,
signatures_version: impl Into<Option<u8>>,
) -> Result<(), NymIdError>
where
S: Storage,
<S as Storage>::StorageError: Send + Sync + 'static,
{
let signatures =
AggregatedCoinIndicesSignatures::try_unpack(&raw_signatures, signatures_version)
.map_err(|source| NymIdError::CoinIndexSignaturesDeserializationFailure { source })?;
helpers::import_coin_index_signatures(&credentials_store, &signatures).await
}
pub async fn import_standalone_ticketbook<S>(
credentials_store: S,
raw_credential: Vec<u8>,
credential_version: impl Into<Option<u8>>,
) -> Result<OffsetDateTime, NymIdError>
where
S: Storage,
<S as Storage>::StorageError: Send + Sync + 'static,
{
let raw_credential = Zeroizing::new(raw_credential);
// note: the type itself implements ZeroizeOnDrop
let ticketbook = IssuedTicketBook::try_unpack(&raw_credential, credential_version)
.map_err(|source| NymIdError::TicketbookDeserializationFailure { source })?;
helpers::import_ticketbook(&credentials_store, &ticketbook).await?;
Ok(ticketbook.expiration_date().ecash_datetime())
}
pub async fn import_full_ticketbook<S>(
credentials_store: S,
raw_credential: Vec<u8>,
credential_version: impl Into<Option<u8>>,
) -> Result<OffsetDateTime, NymIdError>
where
S: Storage,
<S as Storage>::StorageError: Send + Sync + 'static,
{
let raw_credential = Zeroizing::new(raw_credential);
let importable = ImportableTicketBook::try_unpack(&raw_credential, credential_version)
.map_err(|source| NymIdError::FullTicketbookDeserializationFailure { source })?;
let decoded = importable
.try_unpack_full()
.map_err(|source| NymIdError::TicketbookDeserializationFailure { source })?;
if let Some(key) = &decoded.master_verification_key {
helpers::import_master_verification_key(&credentials_store, key).await?
}
if let Some(sigs) = &decoded.expiration_date_signatures {
helpers::import_expiration_date_signatures(&credentials_store, sigs).await?
}
if let Some(sigs) = &decoded.coin_index_signatures {
helpers::import_coin_index_signatures(&credentials_store, sigs).await?
}
helpers::import_ticketbook(&credentials_store, &decoded.ticketbook).await?;
Ok(decoded.ticketbook.expiration_date().ecash_datetime())
}
+4 -1
View File
@@ -8,4 +8,7 @@ pub mod error;
pub mod import_credential;
pub use error::NymIdError;
pub use import_credential::import_credential;
pub use import_credential::{
import_coin_index_signatures, import_expiration_date_signatures, import_full_ticketbook,
import_master_verification_key, import_standalone_ticketbook,
};
@@ -14,6 +14,7 @@ use core::iter::Sum;
use core::ops::Mul;
use group::Curve;
use itertools::Itertools;
use zeroize::Zeroizing;
pub(crate) trait Aggregatable: Sized {
fn aggregate(aggregatable: &[Self], indices: Option<&[SignerIndex]>) -> Result<Self>;
@@ -138,12 +139,12 @@ pub fn aggregate_wallets(
.map(|wallet| SignatureShare::new(*wallet.signature(), wallet.index()))
.collect();
let attributes = vec![
let attributes = Zeroizing::new(vec![
sk_user.sk,
*req_info.get_v(),
*req_info.get_expiration_date(),
*req_info.get_t_type(),
];
]);
let aggregated_signature =
aggregate_signature_shares(verification_key, &attributes, &signature_shares)?;
@@ -524,7 +524,22 @@ pub struct KeyPairUser {
public_key: PublicKeyUser,
}
impl From<KeyPairUser> for SecretKeyUser {
fn from(value: KeyPairUser) -> Self {
value.secret_key
}
}
impl KeyPairUser {
#[allow(clippy::new_without_default)]
pub fn new() -> Self {
generate_keypair_user()
}
pub fn new_seeded<M: AsRef<[u8]>>(seed: M) -> Self {
generate_keypair_user_from_seed(seed)
}
pub fn secret_key(&self) -> &SecretKeyUser {
&self.secret_key
}
@@ -16,6 +16,7 @@ use bls12_381::{multi_miller_loop, G1Projective, G2Prepared, G2Projective, Scala
use group::{Curve, Group, GroupEncoding};
use serde::{Deserialize, Serialize};
use std::ops::Neg;
use zeroize::{Zeroize, ZeroizeOnDrop};
/// Represents a withdrawal request generate by the client who wants to obtain a zk-nym credential.
///
@@ -51,7 +52,7 @@ impl WithdrawalRequest {
///
/// This structure holds the commitment hash, commitment opening, private attributes openings,
/// the wallet secret (scalar), and the expiration date related to a withdrawal request.
#[derive(Debug, Clone, Serialize, Deserialize)]
#[derive(Debug, Clone, Serialize, Deserialize, Zeroize, ZeroizeOnDrop)]
pub struct RequestInfo {
joined_commitment_hash: G1Projective,
joined_commitment_opening: Scalar,
+2 -1
View File
@@ -15,8 +15,9 @@ license.workspace = true
serde = { workspace = true }
bs58 = { workspace = true, optional = true }
base64 = { workspace = true, optional = true }
time = { workspace = true, features = ["formatting", "parsing"], optional = true }
[features]
bs58 = ["dep:bs58"]
base64 = ["dep:base64"]
date = ["time"]
+38
View File
@@ -31,3 +31,41 @@ pub mod bs58 {
.map_err(serde::de::Error::custom)
}
}
#[cfg(feature = "date")]
pub mod date {
use serde::ser::Error;
use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
use time::format_description::{modifier, BorrowedFormatItem, Component};
use time::Date;
// simple YYYY-MM-DD
pub const DATE_FORMAT: &[BorrowedFormatItem<'_>] = &[
BorrowedFormatItem::Component(Component::Year(modifier::Year::default())),
BorrowedFormatItem::Literal(b"-"),
BorrowedFormatItem::Component(Component::Month(modifier::Month::default())),
BorrowedFormatItem::Literal(b"-"),
BorrowedFormatItem::Component(Component::Day(modifier::Day::default())),
];
pub fn deserialize<'de, D>(deserializer: D) -> Result<Date, D::Error>
where
D: Deserializer<'de>,
{
let s = String::deserialize(deserializer)?;
Date::parse(&s, DATE_FORMAT).map_err(de::Error::custom)
}
pub fn serialize<S>(datetime: &Date, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
// serialize it with human-readable format for compatibility with eclipse and nutella clients
// in the future change it back to rfc3339
datetime
.format(&DATE_FORMAT)
.map_err(S::Error::custom)?
.serialize(serializer)
}
}
+9 -9
View File
@@ -1292,7 +1292,7 @@ dependencies = [
name = "nym-mixnet-contract-common"
version = "0.6.0"
dependencies = [
"bs58 0.4.0",
"bs58 0.5.1",
"cosmwasm-schema",
"cosmwasm-std",
"cw2",
@@ -1697,9 +1697,9 @@ dependencies = [
[[package]]
name = "serde"
version = "1.0.198"
version = "1.0.209"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9846a40c979031340571da2545a4e5b7c4163bdae79b301d5f86d03979451fcc"
checksum = "99fce0ffe7310761ca6bf9faf5115afbc19688edd00171d81b1bb1b116c63e09"
dependencies = [
"serde_derive",
]
@@ -1724,9 +1724,9 @@ dependencies = [
[[package]]
name = "serde_derive"
version = "1.0.198"
version = "1.0.209"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e88edab869b01783ba905e7d0153f9fc1a6505a96e4ad3018011eedb838566d9"
checksum = "a5831b979fd7b5439637af1752d535ff49f4860c0f341d1baeb6faf0f4242170"
dependencies = [
"proc-macro2",
"quote",
@@ -1933,18 +1933,18 @@ dependencies = [
[[package]]
name = "thiserror"
version = "1.0.58"
version = "1.0.63"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "03468839009160513471e86a034bb2c5c0e4baae3b43f79ffc55c4a5427b3297"
checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "1.0.58"
version = "1.0.63"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7"
checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261"
dependencies = [
"proc-macro2",
"quote",
+4 -5
View File
@@ -13,11 +13,10 @@ DENOMS_EXPONENT=6
REWARDING_VALIDATOR_ADDRESS=n1pefc2utwpy5w78p2kqdsfmpjxfwmn9d39k5mqa
MIXNET_CONTRACT_ADDRESS=n1xr3rq8yvd7qplsw5yx90ftsr2zdhg4e9z60h5duusgxpv72hud3sjkxkav
VESTING_CONTRACT_ADDRESS=n1unyuj8qnmygvzuex3dwmg9yzt9alhvyeat0uu0jedg2wj33efl5qackslz
ECASH_CONTRACT_ADDRESS=n1ljlwey4xdj0zs7zueepc48nkr033fca6fjgvurfvttqegm8dvsrswsul70
GROUP_CONTRACT_ADDRESS=n10v3rjnq4cjyccfykyams68ztce337gksuu6f0lvtl4meuwvkewaqru4uav
MULTISIG_CONTRACT_ADDRESS=n1cemnu8as0ls45v3caunpesl8jlsfw2ff9rlwnltlecp7zrxct4dsqc2y42
COCONUT_DKG_CONTRACT_ADDRESS=n1zx96qgd88vqlzcxkpwzks7kqs5ctrx36xtzfc58p7q6c4ng9anlqzc4nh8
GROUP_CONTRACT_ADDRESS=n1ewmwz97xm0h8rdk8sw7h9mwn866qkx9hl9zlmagqfkhuzvwk5hhq844ue9
MULTISIG_CONTRACT_ADDRESS=n1tz0setr8vkh9udp8xyxgpqc89ns27k4d0jx2h942hr0ax63yjhmqz6xct8
COCONUT_DKG_CONTRACT_ADDRESS=n1v3n2ly2dp3a9ng3ff6rh26yfkn0pc5hed7w2shc5u9ca5c865utqj5elvh
ECASH_CONTRACT_ADDRESS=n1v3vydvs2ued84yv3khqwtgldmgwn0elljsdh08dr5s2j9x4rc5fs9jlwz9
STATISTICS_SERVICE_DOMAIN_ADDRESS="http://0.0.0.0"
EXPLORER_API=https://sandbox-explorer.nymtech.net/api
+1 -1
View File
@@ -25,7 +25,7 @@ sha2 = "0.10.8"
# for serde on secp256k1 signatures
ecdsa = { workspace = true, features = ["serde"] }
nym-serde-helpers = { path = "../../common/serde-helpers", features = ["bs58", "base64"] }
nym-serde-helpers = { path = "../../common/serde-helpers", features = ["bs58", "base64", "date"] }
nym-credentials-interface = { path = "../../common/credentials-interface" }
nym-crypto = { path = "../../common/crypto", features = ["serde", "asymmetric"] }
+4 -37
View File
@@ -2,27 +2,19 @@
// SPDX-License-Identifier: Apache-2.0
use schemars::JsonSchema;
use time::format_description::{modifier, BorrowedFormatItem, Component};
use time::OffsetDateTime;
// just to have something, even if not accurate to generate the swagger docs
#[derive(JsonSchema)]
pub struct PlaceholderJsonSchemaImpl {}
const DATE_FORMAT: &[BorrowedFormatItem<'_>] = &[
BorrowedFormatItem::Component(Component::Year(modifier::Year::default())),
BorrowedFormatItem::Literal(b"-"),
BorrowedFormatItem::Component(Component::Month(modifier::Month::default())),
BorrowedFormatItem::Literal(b"-"),
BorrowedFormatItem::Component(Component::Day(modifier::Day::default())),
];
pub(crate) const fn unix_epoch() -> OffsetDateTime {
OffsetDateTime::UNIX_EPOCH
}
pub(crate) mod overengineered_offset_date_time_serde {
use crate::helpers::{unix_epoch, DATE_FORMAT};
use crate::helpers::unix_epoch;
use nym_serde_helpers::date::DATE_FORMAT;
use serde::de::Visitor;
use serde::ser::Error;
use serde::{Deserializer, Serialize, Serializer};
@@ -112,30 +104,5 @@ pub(crate) mod overengineered_offset_date_time_serde {
}
}
pub(crate) mod date_serde {
use crate::helpers::DATE_FORMAT;
use serde::ser::Error;
use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
use time::Date;
pub(crate) fn deserialize<'de, D>(deserializer: D) -> Result<Date, D::Error>
where
D: Deserializer<'de>,
{
let s = String::deserialize(deserializer)?;
Date::parse(&s, DATE_FORMAT).map_err(de::Error::custom)
}
pub(crate) fn serialize<S>(datetime: &Date, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
// serialize it with human-readable format for compatibility with eclipse and nutella clients
// in the future change it back to rfc3339
datetime
.format(&DATE_FORMAT)
.map_err(S::Error::custom)?
.serialize(serializer)
}
}
// reimport the module to not break existing imports
pub(crate) use nym_serde_helpers::date as date_serde;
+2 -2
View File
@@ -42,7 +42,7 @@ impl CachedEpoch {
self.valid_until > OffsetDateTime::now_utc()
}
async fn update(&mut self, epoch: Epoch) -> Result<()> {
fn update(&mut self, epoch: Epoch) -> Result<()> {
let now = OffsetDateTime::now_utc();
let validity_duration = if let Some(epoch_finish) = epoch.deadline {
@@ -85,7 +85,7 @@ impl QueryCommunicationChannel {
let epoch = ecash::client::Client::get_current_epoch(&self.nyxd_client).await?;
guard.update(epoch).await?;
guard.update(epoch)?;
Ok(guard)
}
}
+1
View File
@@ -3355,6 +3355,7 @@ dependencies = [
"base64 0.22.1",
"bs58",
"serde",
"time",
]
[[package]]
@@ -0,0 +1,16 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::cli::CliAuthenticatorClient;
use nym_authenticator::error::AuthenticatorError;
use nym_client_core::cli_helpers::client_import_coin_index_signatures::{
import_coin_index_signatures, CommonClientImportCoinIndexSignaturesArgs,
};
pub(crate) async fn execute(
args: CommonClientImportCoinIndexSignaturesArgs,
) -> Result<(), AuthenticatorError> {
import_coin_index_signatures::<CliAuthenticatorClient, _>(args).await?;
println!("successfully imported coin index signatures!");
Ok(())
}
@@ -4,12 +4,10 @@
use crate::cli::CliAuthenticatorClient;
use nym_authenticator::error::AuthenticatorError;
use nym_client_core::cli_helpers::client_import_credential::{
import_credential, CommonClientImportCredentialArgs,
import_credential, CommonClientImportTicketBookArgs,
};
pub(crate) async fn execute(
args: CommonClientImportCredentialArgs,
) -> Result<(), AuthenticatorError> {
pub async fn execute(args: CommonClientImportTicketBookArgs) -> Result<(), AuthenticatorError> {
import_credential::<CliAuthenticatorClient, _>(args).await?;
println!("successfully imported credential!");
Ok(())
@@ -0,0 +1,16 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::cli::CliAuthenticatorClient;
use nym_authenticator::error::AuthenticatorError;
use nym_client_core::cli_helpers::client_import_expiration_date_signatures::{
import_expiration_date_signatures, CommonClientImportExpirationDateSignaturesArgs,
};
pub(crate) async fn execute(
args: CommonClientImportExpirationDateSignaturesArgs,
) -> Result<(), AuthenticatorError> {
import_expiration_date_signatures::<CliAuthenticatorClient, _>(args).await?;
println!("successfully imported expiration date signatures!");
Ok(())
}
@@ -0,0 +1,16 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::cli::CliAuthenticatorClient;
use nym_authenticator::error::AuthenticatorError;
use nym_client_core::cli_helpers::client_import_master_verification_key::{
import_master_verification_key, CommonClientImportMasterVerificationKeyArgs,
};
pub(crate) async fn execute(
args: CommonClientImportMasterVerificationKeyArgs,
) -> Result<(), AuthenticatorError> {
import_master_verification_key::<CliAuthenticatorClient, _>(args).await?;
println!("successfully imported master verification key!");
Ok(())
}
@@ -0,0 +1,59 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use clap::{Args, Subcommand};
use nym_authenticator::error::AuthenticatorError;
use nym_client_core::cli_helpers::client_import_coin_index_signatures::CommonClientImportCoinIndexSignaturesArgs;
use nym_client_core::cli_helpers::client_import_credential::CommonClientImportTicketBookArgs;
use nym_client_core::cli_helpers::client_import_expiration_date_signatures::CommonClientImportExpirationDateSignaturesArgs;
use nym_client_core::cli_helpers::client_import_master_verification_key::CommonClientImportMasterVerificationKeyArgs;
pub(crate) mod import_coin_index_signatures;
pub(crate) mod import_credential;
pub(crate) mod import_expiration_date_signatures;
pub(crate) mod import_master_verification_key;
pub(crate) mod show_ticketbooks;
#[derive(Args)]
#[clap(args_conflicts_with_subcommands = true, subcommand_required = true)]
pub struct Ecash {
#[clap(subcommand)]
pub command: EcashCommands,
}
impl Ecash {
pub async fn execute(self) -> Result<(), AuthenticatorError> {
match self.command {
EcashCommands::ShowTicketBooks(args) => show_ticketbooks::execute(args).await?,
EcashCommands::ImportTicketBook(args) => import_credential::execute(args).await?,
EcashCommands::ImportCoinIndexSignatures(args) => {
import_coin_index_signatures::execute(args).await?
}
EcashCommands::ImportExpirationDateSignatures(args) => {
import_expiration_date_signatures::execute(args).await?
}
EcashCommands::ImportMasterVerificationKey(args) => {
import_master_verification_key::execute(args).await?
}
}
Ok(())
}
}
#[derive(Subcommand)]
pub enum EcashCommands {
/// Display information associated with the imported ticketbooks,
ShowTicketBooks(show_ticketbooks::Args),
/// Import a pre-generated ticketbook
ImportTicketBook(CommonClientImportTicketBookArgs),
/// Import coin index signatures needed for ticketbooks
ImportCoinIndexSignatures(CommonClientImportCoinIndexSignaturesArgs),
/// Import expiration date signatures needed for ticketbooks
ImportExpirationDateSignatures(CommonClientImportExpirationDateSignaturesArgs),
/// Import master verification key needed for ticketbooks
ImportMasterVerificationKey(CommonClientImportMasterVerificationKeyArgs),
}
@@ -0,0 +1,32 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::cli::CliAuthenticatorClient;
use nym_authenticator::error::AuthenticatorError;
use nym_bin_common::output_format::OutputFormat;
use nym_client_core::cli_helpers::client_show_ticketbooks::{
show_ticketbooks, CommonShowTicketbooksArgs,
};
#[derive(clap::Args)]
pub(crate) struct Args {
#[command(flatten)]
common_args: CommonShowTicketbooksArgs,
#[arg(short, long, default_value_t = OutputFormat::default())]
output: OutputFormat,
}
impl AsRef<CommonShowTicketbooksArgs> for Args {
fn as_ref(&self) -> &CommonShowTicketbooksArgs {
&self.common_args
}
}
pub(crate) async fn execute(args: Args) -> Result<(), AuthenticatorError> {
let output = args.output;
let res = show_ticketbooks::<CliAuthenticatorClient, _>(args).await?;
println!("{}", output.format(&res));
Ok(())
}
@@ -1,6 +1,7 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::cli::ecash::Ecash;
use clap::{CommandFactory, Parser, Subcommand};
use log::error;
use nym_authenticator::{
@@ -9,13 +10,12 @@ use nym_authenticator::{
};
use nym_bin_common::completions::{fig_generate, ArgShell};
use nym_bin_common::{bin_info, version_checker};
use nym_client_core::cli_helpers::client_import_credential::CommonClientImportCredentialArgs;
use nym_client_core::cli_helpers::CliClient;
use std::sync::OnceLock;
mod add_gateway;
mod build_info;
mod import_credential;
pub mod ecash;
mod init;
mod list_gateways;
mod peer_handler;
@@ -69,8 +69,8 @@ pub(crate) enum Commands {
/// parameters.
Run(run::Run),
/// Import a pre-generated credential
ImportCredential(CommonClientImportCredentialArgs),
/// Ecash-related functionalities
Ecash(Ecash),
/// List all registered with gateways
ListGateways(list_gateways::Args),
@@ -127,7 +127,7 @@ pub(crate) async fn execute(args: Cli) -> Result<(), AuthenticatorError> {
match args.command {
Commands::Init(m) => init::execute(m).await?,
Commands::Run(m) => run::execute(&m).await?,
Commands::ImportCredential(m) => import_credential::execute(m).await?,
Commands::Ecash(ecash) => ecash.execute().await?,
Commands::ListGateways(args) => list_gateways::execute(args).await?,
Commands::AddGateway(args) => add_gateway::execute(args).await?,
Commands::SwitchGateway(args) => switch_gateway::execute(args).await?,
@@ -0,0 +1,17 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::cli::CliIpPacketRouterClient;
use crate::error::ClientError;
use nym_client_core::cli_helpers::client_import_coin_index_signatures::{
import_coin_index_signatures, CommonClientImportCoinIndexSignaturesArgs,
};
use nym_ip_packet_router::error::IpPacketRouterError;
pub(crate) async fn execute(
args: CommonClientImportCoinIndexSignaturesArgs,
) -> Result<(), IpPacketRouterError> {
import_coin_index_signatures::<CliIpPacketRouterClient, _>(args).await?;
println!("successfully imported coin index signatures!");
Ok(())
}
@@ -3,13 +3,11 @@
use crate::cli::CliIpPacketRouterClient;
use nym_client_core::cli_helpers::client_import_credential::{
import_credential, CommonClientImportCredentialArgs,
import_credential, CommonClientImportTicketBookArgs,
};
use nym_ip_packet_router::error::IpPacketRouterError;
pub(crate) async fn execute(
args: CommonClientImportCredentialArgs,
) -> Result<(), IpPacketRouterError> {
pub async fn execute(args: CommonClientImportTicketBookArgs) -> Result<(), IpPacketRouterError> {
import_credential::<CliIpPacketRouterClient, _>(args).await?;
println!("successfully imported credential!");
Ok(())
@@ -0,0 +1,16 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::cli::CliIpPacketRouterClient;
use nym_client_core::cli_helpers::client_import_expiration_date_signatures::{
import_expiration_date_signatures, CommonClientImportExpirationDateSignaturesArgs,
};
use nym_ip_packet_router::error::IpPacketRouterError;
pub(crate) async fn execute(
args: CommonClientImportExpirationDateSignaturesArgs,
) -> Result<(), IpPacketRouterError> {
import_expiration_date_signatures::<CliIpPacketRouterClient, _>(args).await?;
println!("successfully imported expiration date signatures!");
Ok(())
}
@@ -0,0 +1,16 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::cli::CliIpPacketRouterClient;
use nym_client_core::cli_helpers::client_import_master_verification_key::{
import_master_verification_key, CommonClientImportMasterVerificationKeyArgs,
};
use nym_ip_packet_router::error::IpPacketRouterError;
pub(crate) async fn execute(
args: CommonClientImportMasterVerificationKeyArgs,
) -> Result<(), IpPacketRouterError> {
import_master_verification_key::<CliIpPacketRouterClient, _>(args).await?;
println!("successfully imported master verification key!");
Ok(())
}
@@ -0,0 +1,61 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use clap::{Args, Subcommand};
use nym_client_core::cli_helpers::client_import_coin_index_signatures::CommonClientImportCoinIndexSignaturesArgs;
use nym_client_core::cli_helpers::client_import_credential::CommonClientImportTicketBookArgs;
use nym_client_core::cli_helpers::client_import_expiration_date_signatures::CommonClientImportExpirationDateSignaturesArgs;
use nym_client_core::cli_helpers::client_import_master_verification_key::CommonClientImportMasterVerificationKeyArgs;
use std::error::Error;
pub(crate) mod import_coin_index_signatures;
pub(crate) mod import_credential;
pub mod import_credential;
pub(crate) mod import_expiration_date_signatures;
pub(crate) mod import_master_verification_key;
pub(crate) mod show_ticketbooks;
pub mod show_ticketbooks;
#[derive(Args)]
#[clap(args_conflicts_with_subcommands = true, subcommand_required = true)]
pub struct Ecash {
#[clap(subcommand)]
pub command: EcashCommands,
}
impl Ecash {
pub async fn execute(self) -> Result<(), Box<dyn Error + Send + Sync>> {
match self.command {
EcashCommands::ShowTicketBooks(args) => show_ticketbooks::execute(args).await?,
EcashCommands::ImportTicketBook(args) => import_credential::execute(args).await?,
EcashCommands::ImportCoinIndexSignatures(args) => {
import_coin_index_signatures::execute(args).await?
}
EcashCommands::ImportExpirationDateSignatures(args) => {
import_expiration_date_signatures::execute(args).await?
}
EcashCommands::ImportMasterVerificationKey(args) => {
import_master_verification_key::execute(args).await?
}
}
Ok(())
}
}
#[derive(Subcommand)]
pub enum EcashCommands {
/// Display information associated with the imported ticketbooks,
ShowTicketBooks(show_ticketbooks::Args),
/// Import a pre-generated ticketbook
ImportTicketBook(CommonClientImportTicketBookArgs),
/// Import coin index signatures needed for ticketbooks
ImportCoinIndexSignatures(CommonClientImportCoinIndexSignaturesArgs),
/// Import expiration date signatures needed for ticketbooks
ImportExpirationDateSignatures(CommonClientImportExpirationDateSignaturesArgs),
/// Import master verification key needed for ticketbooks
ImportMasterVerificationKey(CommonClientImportMasterVerificationKeyArgs),
}
@@ -9,7 +9,7 @@ use nym_client_core::cli_helpers::client_show_ticketbooks::{
use nym_ip_packet_router::error::IpPacketRouterError;
#[derive(clap::Args)]
pub(crate) struct Args {
pub struct Args {
#[command(flatten)]
common_args: CommonShowTicketbooksArgs,
@@ -23,7 +23,7 @@ impl AsRef<CommonShowTicketbooksArgs> for Args {
}
}
pub(crate) async fn execute(args: Args) -> Result<(), IpPacketRouterError> {
pub async fn execute(args: Args) -> Result<(), IpPacketRouterError> {
let output = args.output;
let res = show_ticketbooks::<CliIpPacketRouterClient, _>(args).await?;
@@ -1,8 +1,9 @@
use crate::commands::ecash::Ecash;
use clap::{CommandFactory, Parser, Subcommand};
use log::error;
use nym_bin_common::completions::{fig_generate, ArgShell};
use nym_bin_common::{bin_info, version_checker};
use nym_client_core::cli_helpers::client_import_credential::CommonClientImportCredentialArgs;
use nym_client_core::cli_helpers::client_import_credential::CommonClientImportTicketBookArgs;
use nym_client_core::cli_helpers::CliClient;
use nym_ip_packet_router::config::helpers::try_upgrade_config;
use nym_ip_packet_router::config::{BaseClientConfig, Config};
@@ -11,11 +12,10 @@ use std::sync::OnceLock;
mod add_gateway;
mod build_info;
mod import_credential;
pub mod ecash;
mod init;
mod list_gateways;
mod run;
mod show_ticketbooks;
mod sign;
mod switch_gateway;
@@ -65,8 +65,8 @@ pub(crate) enum Commands {
/// parameters.
Run(run::Run),
/// Import a pre-generated credential
ImportCredential(CommonClientImportCredentialArgs),
/// Ecash-related functionalities
Ecash(Ecash),
/// List all registered with gateways
ListGateways(list_gateways::Args),
@@ -132,11 +132,10 @@ pub(crate) async fn execute(args: Cli) -> Result<(), IpPacketRouterError> {
match args.command {
Commands::Init(m) => init::execute(m).await?,
Commands::Run(m) => run::execute(&m).await?,
Commands::ImportCredential(m) => import_credential::execute(m).await?,
Commands::Ecash(ecash) => ecash.execute().await?,
Commands::ListGateways(args) => list_gateways::execute(args).await?,
Commands::AddGateway(args) => add_gateway::execute(args).await?,
Commands::SwitchGateway(args) => switch_gateway::execute(args).await?,
Commands::ShowTicketbooks(args) => show_ticketbooks::execute(args).await?,
Commands::Sign(m) => sign::execute(&m).await?,
Commands::BuildInfo(m) => build_info::execute(m),
Commands::Completions(s) => s.generate(&mut Cli::command(), bin_name),
@@ -0,0 +1,16 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::cli::CliNetworkRequesterClient;
use crate::error::NetworkRequesterError;
use nym_client_core::cli_helpers::client_import_coin_index_signatures::{
import_coin_index_signatures, CommonClientImportCoinIndexSignaturesArgs,
};
pub(crate) async fn execute(
args: CommonClientImportCoinIndexSignaturesArgs,
) -> Result<(), NetworkRequesterError> {
import_coin_index_signatures::<CliNetworkRequesterClient, _>(args).await?;
println!("successfully imported coin index signatures!");
Ok(())
}
@@ -4,12 +4,10 @@
use crate::cli::CliNetworkRequesterClient;
use crate::error::NetworkRequesterError;
use nym_client_core::cli_helpers::client_import_credential::{
import_credential, CommonClientImportCredentialArgs,
import_credential, CommonClientImportTicketBookArgs,
};
pub(crate) async fn execute(
args: CommonClientImportCredentialArgs,
) -> Result<(), NetworkRequesterError> {
pub async fn execute(args: CommonClientImportTicketBookArgs) -> Result<(), NetworkRequesterError> {
import_credential::<CliNetworkRequesterClient, _>(args).await?;
println!("successfully imported credential!");
Ok(())
@@ -0,0 +1,16 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::cli::CliNetworkRequesterClient;
use crate::error::NetworkRequesterError;
use nym_client_core::cli_helpers::client_import_expiration_date_signatures::{
import_expiration_date_signatures, CommonClientImportExpirationDateSignaturesArgs,
};
pub(crate) async fn execute(
args: CommonClientImportExpirationDateSignaturesArgs,
) -> Result<(), NetworkRequesterError> {
import_expiration_date_signatures::<CliNetworkRequesterClient, _>(args).await?;
println!("successfully imported expiration date signatures!");
Ok(())
}
@@ -0,0 +1,16 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::cli::CliNetworkRequesterClient;
use crate::error::NetworkRequesterError;
use nym_client_core::cli_helpers::client_import_master_verification_key::{
import_master_verification_key, CommonClientImportMasterVerificationKeyArgs,
};
pub(crate) async fn execute(
args: CommonClientImportMasterVerificationKeyArgs,
) -> Result<(), NetworkRequesterError> {
import_master_verification_key::<CliNetworkRequesterClient, _>(args).await?;
println!("successfully imported master verification key!");
Ok(())
}
@@ -0,0 +1,59 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::error::NetworkRequesterError;
use clap::{Args, Subcommand};
use nym_client_core::cli_helpers::client_import_coin_index_signatures::CommonClientImportCoinIndexSignaturesArgs;
use nym_client_core::cli_helpers::client_import_credential::CommonClientImportTicketBookArgs;
use nym_client_core::cli_helpers::client_import_expiration_date_signatures::CommonClientImportExpirationDateSignaturesArgs;
use nym_client_core::cli_helpers::client_import_master_verification_key::CommonClientImportMasterVerificationKeyArgs;
pub(crate) mod import_coin_index_signatures;
pub(crate) mod import_credential;
pub(crate) mod import_expiration_date_signatures;
pub(crate) mod import_master_verification_key;
pub(crate) mod show_ticketbooks;
#[derive(Args)]
#[clap(args_conflicts_with_subcommands = true, subcommand_required = true)]
pub struct Ecash {
#[clap(subcommand)]
pub command: EcashCommands,
}
impl Ecash {
pub async fn execute(self) -> Result<(), NetworkRequesterError> {
match self.command {
EcashCommands::ShowTicketBooks(args) => show_ticketbooks::execute(args).await?,
EcashCommands::ImportTicketBook(args) => import_credential::execute(args).await?,
EcashCommands::ImportCoinIndexSignatures(args) => {
import_coin_index_signatures::execute(args).await?
}
EcashCommands::ImportExpirationDateSignatures(args) => {
import_expiration_date_signatures::execute(args).await?
}
EcashCommands::ImportMasterVerificationKey(args) => {
import_master_verification_key::execute(args).await?
}
}
Ok(())
}
}
#[derive(Subcommand)]
pub enum EcashCommands {
/// Display information associated with the imported ticketbooks,
ShowTicketBooks(show_ticketbooks::Args),
/// Import a pre-generated ticketbook
ImportTicketBook(CommonClientImportTicketBookArgs),
/// Import coin index signatures needed for ticketbooks
ImportCoinIndexSignatures(CommonClientImportCoinIndexSignaturesArgs),
/// Import expiration date signatures needed for ticketbooks
ImportExpirationDateSignatures(CommonClientImportExpirationDateSignaturesArgs),
/// Import master verification key needed for ticketbooks
ImportMasterVerificationKey(CommonClientImportMasterVerificationKeyArgs),
}
@@ -1,6 +1,7 @@
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: GPL-3.0-only
use crate::cli::ecash::Ecash;
use crate::config::helpers::try_upgrade_config_by_id;
use crate::{
config::{BaseClientConfig, Config},
@@ -11,18 +12,16 @@ use log::error;
use nym_bin_common::bin_info;
use nym_bin_common::completions::{fig_generate, ArgShell};
use nym_bin_common::version_checker;
use nym_client_core::cli_helpers::client_import_credential::CommonClientImportCredentialArgs;
use nym_client_core::cli_helpers::CliClient;
use nym_config::OptionalSet;
use std::sync::OnceLock;
mod add_gateway;
mod build_info;
mod import_credential;
pub mod ecash;
mod init;
mod list_gateways;
mod run;
mod show_ticketbooks;
mod sign;
mod switch_gateway;
@@ -72,12 +71,12 @@ pub(crate) enum Commands {
/// parameters.
Run(run::Run),
/// Ecash-related functionalities
Ecash(Ecash),
/// Sign to prove ownership of this network requester
Sign(sign::Sign),
/// Import a pre-generated credential
ImportCredential(CommonClientImportCredentialArgs),
/// List all registered with gateways
ListGateways(list_gateways::Args),
@@ -87,9 +86,6 @@ pub(crate) enum Commands {
/// Change the currently active gateway. Note that you must have already registered with the new gateway!
SwitchGateway(switch_gateway::Args),
/// Display information associated with the imported ticketbooks,
ShowTicketbooks(show_ticketbooks::Args),
/// Show build information of this binary
BuildInfo(build_info::BuildInfo),
@@ -151,12 +147,11 @@ pub(crate) async fn execute(args: Cli) -> Result<(), NetworkRequesterError> {
match args.command {
Commands::Init(m) => init::execute(m).await?,
Commands::Run(m) => run::execute(&m).await?,
Commands::Ecash(ecash) => ecash.execute().await?,
Commands::Sign(m) => sign::execute(&m).await?,
Commands::ImportCredential(m) => import_credential::execute(m).await?,
Commands::ListGateways(args) => list_gateways::execute(args).await?,
Commands::AddGateway(args) => add_gateway::execute(args).await?,
Commands::SwitchGateway(args) => switch_gateway::execute(args).await?,
Commands::ShowTicketbooks(args) => show_ticketbooks::execute(args).await?,
Commands::BuildInfo(m) => build_info::execute(m),
Commands::Completions(s) => s.generate(&mut Cli::command(), bin_name),
Commands::GenerateFigSpec => fig_generate(&mut Cli::command(), bin_name),
+17 -7
View File
@@ -1,28 +1,38 @@
use nym_cli_commands::context::{create_query_client, create_signing_client, ClientArgs};
use nym_cli_commands::ecash::EcashCommands;
use nym_network_defaults::NymNetworkDetails;
pub(crate) async fn execute(
global_args: ClientArgs,
coconut: nym_cli_commands::coconut::Ecash,
coconut: nym_cli_commands::ecash::Ecash,
network_details: &NymNetworkDetails,
) -> anyhow::Result<()> {
match coconut.command {
nym_cli_commands::coconut::EcashCommands::IssueTicketBook(args) => {
nym_cli_commands::coconut::issue_ticket_book::execute(
EcashCommands::IssueTicketBook(args) => {
nym_cli_commands::ecash::issue_ticket_book::execute(
args,
create_signing_client(global_args, network_details)?,
)
.await?
}
nym_cli_commands::coconut::EcashCommands::RecoverTicketBook(args) => {
nym_cli_commands::coconut::recover_ticket_book::execute(
EcashCommands::RecoverTicketBook(args) => {
nym_cli_commands::ecash::recover_ticket_book::execute(
args,
create_query_client(network_details)?,
)
.await?
}
nym_cli_commands::coconut::EcashCommands::ImportTicketBook(args) => {
nym_cli_commands::coconut::import_ticket_book::execute(args).await?
EcashCommands::ImportTicketBook(args) => {
nym_cli_commands::ecash::import_ticket_book::execute(args).await?
}
EcashCommands::ImportCoinIndexSignatures(args) => {
nym_cli_commands::ecash::import_coin_index_signatures::execute(args).await?
}
EcashCommands::ImportExpirationDateSignatures(args) => {
nym_cli_commands::ecash::import_expiration_date_signatures::execute(args).await?
}
EcashCommands::ImportMasterVerificationKey(args) => {
nym_cli_commands::ecash::import_master_verification_key::execute(args).await?
}
}
Ok(())
+1 -1
View File
@@ -63,7 +63,7 @@ pub(crate) enum Commands {
/// Sign and verify messages
Signature(nym_cli_commands::validator::signature::Signature),
/// Ecash related stuff
Ecash(nym_cli_commands::coconut::Ecash),
Ecash(nym_cli_commands::ecash::Ecash),
/// Query chain blocks
Block(nym_cli_commands::validator::block::Block),
/// Manage and execute WASM smart contracts
@@ -2,7 +2,7 @@
// SPDX-License-Identifier: Apache-2.0
use clap::ArgGroup;
use nym_id::import_credential;
use nym_id::import_standalone_ticketbook;
use std::fs;
use std::path::PathBuf;
@@ -43,6 +43,6 @@ pub(crate) async fn execute(args: Args) -> anyhow::Result<()> {
}
};
import_credential(credentials_store, raw_credential, args.version).await?;
import_standalone_ticketbook(credentials_store, raw_credential, args.version).await?;
Ok(())
}