introduced initial internal commands for nym-cli: ecash key and request generation (#5174)

* introduced initial internal commands for nym-cli: ecash key and request generation

* reduced args logging level
This commit is contained in:
Jędrzej Stuczyński
2024-11-25 15:41:49 +00:00
committed by GitHub
parent 27637ae6b4
commit 5668e123d9
11 changed files with 230 additions and 0 deletions
Generated
+2
View File
@@ -4752,12 +4752,14 @@ dependencies = [
"nym-coconut-dkg-common",
"nym-config",
"nym-contracts-common",
"nym-credential-proxy-requests",
"nym-credential-storage",
"nym-credential-utils",
"nym-credentials",
"nym-credentials-interface",
"nym-crypto",
"nym-ecash-contract-common",
"nym-ecash-time",
"nym-id",
"nym-mixnet-contract-common",
"nym-multisig-contract-common",
+2
View File
@@ -48,6 +48,7 @@ nym-vesting-contract-common = { path = "../cosmwasm-smart-contracts/vesting-cont
nym-coconut-dkg-common = { path = "../cosmwasm-smart-contracts/coconut-dkg" }
nym-multisig-contract-common = { path = "../cosmwasm-smart-contracts/multisig-contract" }
nym-ecash-contract-common = { path = "../cosmwasm-smart-contracts/ecash-contract" }
nym-ecash-time = { path = "../../common/ecash-time" }
nym-sphinx = { path = "../../common/nymsphinx" }
nym-client-core = { path = "../../common/client-core" }
nym-config = { path = "../../common/config" }
@@ -56,6 +57,7 @@ nym-credentials-interface = { path = "../../common/credentials-interface" }
nym-credential-storage = { path = "../../common/credential-storage" }
nym-credential-utils = { path = "../../common/credential-utils" }
nym-id = { path = "../nym-id" }
nym-credential-proxy-requests = { path = "../../nym-credential-proxy/nym-credential-proxy-requests" }
nym-pemstore = { path = "../../common/pemstore", version = "0.3.0" }
nym-types = { path = "../../common/types" }
@@ -0,0 +1,41 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use clap::Parser;
use log::trace;
use nym_credentials_interface::{generate_keypair_user, generate_keypair_user_from_seed, Base58};
use serde::{Deserialize, Serialize};
use std::io::stdout;
#[derive(Serialize, Deserialize)]
pub struct Bs58EncodedKeys {
pub secret_key: String,
pub public_key: String,
}
#[derive(Debug, Parser)]
pub struct Args {
/// Secret value that's used for deriving underlying ecash keypair
#[clap(long)]
pub(crate) bs58_encoded_client_secret: Option<String>,
}
pub fn generate_ecash_keypair(args: Args) -> anyhow::Result<()> {
trace!("args: {args:?}");
let keypair = if let Some(secret) = args.bs58_encoded_client_secret {
let seed = bs58::decode(&secret).into_vec()?;
generate_keypair_user_from_seed(&seed)
} else {
generate_keypair_user()
};
let encoded = Bs58EncodedKeys {
secret_key: keypair.secret_key().to_bs58(),
public_key: keypair.public_key().to_bs58(),
};
serde_json::to_writer_pretty(stdout(), &encoded)?;
Ok(())
}
+23
View File
@@ -0,0 +1,23 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use clap::{Args, Subcommand};
pub mod generate_keypair;
pub mod withdrawal_request;
#[derive(Debug, Args)]
#[clap(args_conflicts_with_subcommands = true, subcommand_required = true)]
pub struct InternalEcash {
#[clap(subcommand)]
pub command: InternalEcashCommands,
}
#[derive(Debug, Subcommand)]
pub enum InternalEcashCommands {
/// Generate a dummy withdrawal request
GenerateWithdrawalRequest(withdrawal_request::Args),
/// Generate dummy ecash keypair
GenerateKeypair(generate_keypair::Args),
}
@@ -0,0 +1,78 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use clap::Parser;
use log::trace;
use nym_credential_proxy_requests::api::v1::ticketbook::models::TicketbookRequest;
use nym_credentials_interface::{
generate_keypair_user, withdrawal_request, Base58, SecretKeyUser, TicketType,
};
use nym_ecash_time::{ecash_default_expiration_date, EcashTime};
use serde::{Deserialize, Serialize};
use std::io::stdout;
use time::macros::format_description;
use time::Date;
use zeroize::Zeroizing;
fn parse_date(raw: &str) -> Result<Date, time::error::Parse> {
let format = format_description!("[year]-[month]-[day]");
Date::parse(raw, &format)
}
#[derive(Serialize, Deserialize)]
pub struct Bs58EncodedOutput {
pub ecash_proxy_request: TicketbookRequest,
pub ecash_secret: String,
/// Needed to later unblind shares
pub ecash_request_info_bs58: String,
}
#[derive(Debug, Parser)]
pub struct Args {
/// Specify which type of ticketbook
#[clap(long, default_value_t = TicketType::V1MixnetEntry)]
pub(crate) ticketbook_type: TicketType,
/// Set expiration date for the ticketbook
#[clap(long, value_parser = parse_date, default_value_t = ecash_default_expiration_date())]
pub(crate) expiration_date: Date,
/// Provide ecash secret key (or generate a fresh one)
#[clap(long)]
pub(crate) ecash_secret_key_bs58: Option<String>,
}
pub async fn generate_withdrawal_request(args: Args) -> anyhow::Result<()> {
trace!("args: {args:?}");
let ecash_keypair = if let Some(secret_key) = args.ecash_secret_key_bs58 {
let secret_key = Zeroizing::new(bs58::decode(Zeroizing::new(secret_key)).into_vec()?);
let sk = SecretKeyUser::from_bytes(&secret_key)?;
sk.into()
} else {
generate_keypair_user()
};
let (withdrawal_request, request_info) = withdrawal_request(
ecash_keypair.secret_key(),
args.expiration_date.ecash_unix_timestamp(),
args.ticketbook_type.encode(),
)?;
let encoded = Bs58EncodedOutput {
ecash_proxy_request: TicketbookRequest {
withdrawal_request: withdrawal_request.into(),
ecash_pubkey: ecash_keypair.public_key(),
expiration_date: args.expiration_date,
ticketbook_type: args.ticketbook_type,
is_freepass_request: false,
},
ecash_secret: ecash_keypair.secret_key().to_bs58(),
ecash_request_info_bs58: request_info.to_bs58(),
};
serde_json::to_writer_pretty(stdout(), &encoded)?;
Ok(())
}
+19
View File
@@ -0,0 +1,19 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use clap::{Args, Subcommand};
pub mod ecash;
#[derive(Debug, Args)]
#[clap(args_conflicts_with_subcommands = true, subcommand_required = true)]
pub struct Internal {
#[clap(subcommand)]
pub command: InternalCommands,
}
#[derive(Debug, Subcommand)]
pub enum InternalCommands {
/// Ecash related internal commands
Ecash(ecash::InternalEcash),
}
+1
View File
@@ -3,5 +3,6 @@
pub mod context;
pub mod ecash;
pub mod internal;
pub mod utils;
pub mod validator;
@@ -530,6 +530,15 @@ impl From<KeyPairUser> for SecretKeyUser {
}
}
impl From<SecretKeyUser> for KeyPairUser {
fn from(value: SecretKeyUser) -> Self {
KeyPairUser {
public_key: value.public_key(),
secret_key: value,
}
}
}
impl KeyPairUser {
#[allow(clippy::new_without_default)]
pub fn new() -> Self {
+26
View File
@@ -0,0 +1,26 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use nym_cli_commands::context::ClientArgs;
use nym_cli_commands::internal::ecash::InternalEcashCommands;
use nym_network_defaults::NymNetworkDetails;
pub(super) async fn execute(
global_args: ClientArgs,
ecash: nym_cli_commands::internal::ecash::InternalEcash,
nym_network_details: &NymNetworkDetails,
) -> anyhow::Result<()> {
// I reckon those will be needed later
let _ = global_args;
let _ = nym_network_details;
match ecash.command {
InternalEcashCommands::GenerateWithdrawalRequest(args) => {
nym_cli_commands::internal::ecash::withdrawal_request::generate_withdrawal_request(args)
.await
}
InternalEcashCommands::GenerateKeypair(args) => {
nym_cli_commands::internal::ecash::generate_keypair::generate_ecash_keypair(args)
}
}
}
+20
View File
@@ -0,0 +1,20 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use nym_cli_commands::context::ClientArgs;
use nym_cli_commands::internal::InternalCommands;
use nym_network_defaults::NymNetworkDetails;
mod ecash;
pub(super) async fn execute(
global_args: ClientArgs,
internal: nym_cli_commands::internal::Internal,
nym_network_details: &NymNetworkDetails,
) -> anyhow::Result<()> {
match internal.command {
InternalCommands::Ecash(ecash_commands) => {
ecash::execute(global_args, ecash_commands, nym_network_details).await
}
}
}
+9
View File
@@ -9,6 +9,7 @@ use nym_validator_client::nyxd::AccountId;
mod completion;
mod ecash;
mod internal;
mod validator;
#[derive(Debug, Parser)]
@@ -74,6 +75,11 @@ pub(crate) enum Commands {
VestingSchedule(nym_cli_commands::validator::vesting::VestingSchedule),
/// Manage your mixnet infrastructure, delegate stake or query the directory
Mixnet(nym_cli_commands::validator::mixnet::Mixnet),
#[clap(hide = true)]
/// Internal commands used for testing and debugging
Internal(nym_cli_commands::internal::Internal),
/// Generates shell completion
GenerateFig,
}
@@ -118,6 +124,9 @@ async fn execute(cli: Cli) -> anyhow::Result<()> {
Commands::Mixnet(mixnet) => {
validator::mixnet::execute(args, mixnet, &network_details).await?
}
Commands::Internal(internal_commands) => {
internal::execute(args, internal_commands, &network_details).await?
}
Commands::GenerateFig => {
let mut cmd = Cli::command();
completion::print_fig(&mut cmd);