diff --git a/apps/src/lib/cli.rs b/apps/src/lib/cli.rs index 84967a9b81..8380aa84e8 100644 --- a/apps/src/lib/cli.rs +++ b/apps/src/lib/cli.rs @@ -1935,7 +1935,8 @@ pub mod args { pub const VALIDATOR_CODE_PATH: ArgOpt = arg_opt("validator-code-path"); pub const VALUE: ArgOpt = arg_opt("value"); - pub const VERIFICATION_KEY: ArgOpt = arg_opt("verification-key"); + pub const VERIFICATION_KEY: ArgOpt = + arg_opt("verification-key"); pub const VIEWING_KEY: Arg = arg("key"); pub const WALLET_ALIAS_FORCE: ArgFlag = flag("wallet-alias-force"); pub const WASM_CHECKSUMS_PATH: Arg = arg("wasm-checksums-path"); @@ -3341,12 +3342,15 @@ pub mod args { fee_token: ctx.get(&self.fee_token), gas_limit: self.gas_limit, signing_key: self.signing_key.map(|x| ctx.get_cached(&x)), - verification_key: self.verification_key.map(|x| ctx.get_cached(&x)), + verification_key: self + .verification_key + .map(|x| ctx.get_cached(&x)), signer: self.signer.map(|x| ctx.get(&x)), tx_reveal_code_path: self.tx_reveal_code_path, password: self.password, expiration: self.expiration, - chain_id: self.chain_id + chain_id: self + .chain_id .or_else(|| Some(ctx.config.ledger.chain_id.clone())), } } @@ -3419,16 +3423,16 @@ pub mod args { .conflicts_with(SIGNING_KEY_OPT.name) .conflicts_with(VERIFICATION_KEY.name), ) - .arg( - VERIFICATION_KEY - .def() - .about( - "Sign the transaction with the key for the given \ - public key, public key hash or alias from your \ - wallet.", - ) - .conflicts_with(SIGNER.name) - .conflicts_with(SIGNING_KEY_OPT.name), + .arg( + VERIFICATION_KEY + .def() + .help( + "Sign the transaction with the key for the given \ + public key, public key hash or alias from your \ + wallet.", + ) + .conflicts_with(SIGNER.name) + .conflicts_with(SIGNING_KEY_OPT.name), ) .arg(CHAIN_ID_OPT.def().help("The chain ID.")) } diff --git a/apps/src/lib/client/signing.rs b/apps/src/lib/client/signing.rs index 402a8432c5..4ae12c6b17 100644 --- a/apps/src/lib/client/signing.rs +++ b/apps/src/lib/client/signing.rs @@ -22,8 +22,7 @@ pub async fn find_pk< wallet: &mut Wallet, addr: &Address, ) -> Result { - namada::ledger::signing::find_pk(client, wallet, addr, None) - .await + namada::ledger::signing::find_pk(client, wallet, addr, None).await } /// Given CLI arguments and some defaults, determine the rightful transaction @@ -60,13 +59,7 @@ pub async fn sign_tx< args: &args::Tx, default: &common::PublicKey, ) -> Result<(), tx::Error> { - namada::ledger::signing::sign_tx( - wallet, - tx, - args, - default, - ) - .await + namada::ledger::signing::sign_tx(wallet, tx, args, default).await } /// Create a wrapper tx from a normal tx. Get the hash of the diff --git a/apps/src/lib/client/tx.rs b/apps/src/lib/client/tx.rs index 2b69d1b154..a206345af2 100644 --- a/apps/src/lib/client/tx.rs +++ b/apps/src/lib/client/tx.rs @@ -5,8 +5,6 @@ use std::fs::{File, OpenOptions}; use std::io::{Read, Write}; use std::path::PathBuf; -use async_std::io; -use async_std::io::prelude::WriteExt; use async_trait::async_trait; use borsh::{BorshDeserialize, BorshSerialize}; use data_encoding::HEXLOWER_PERMISSIVE; @@ -15,7 +13,7 @@ use namada::ledger::governance::storage as gov_storage; use namada::ledger::rpc::{TxBroadcastData, TxResponse}; use namada::ledger::signing::TxSigningKey; use namada::ledger::wallet::{Wallet, WalletUtils}; -use namada::ledger::{masp, pos, tx, signing}; +use namada::ledger::{masp, pos, signing, tx}; use namada::proof_of_stake::parameters::PosParams; use namada::proto::{Code, Data, Section, Tx}; use namada::types::address::Address; @@ -43,9 +41,7 @@ use crate::config::TendermintMode; use crate::facade::tendermint_rpc::endpoint::broadcast::tx_sync::Response; use crate::facade::tendermint_rpc::HttpClient; use crate::node::ledger::tendermint_node; -use crate::wallet::{ - gen_validator_keys, read_and_confirm_encryption_password, CliWalletUtils, -}; +use crate::wallet::{gen_validator_keys, read_and_confirm_encryption_password}; pub async fn submit_custom( client: &C, @@ -59,18 +55,23 @@ pub async fn submit_custom( let reveal_pk = tx::build_reveal_pk( client, &mut ctx.wallet, - args::RevealPk { tx: args.tx.clone(), public_key: pk.clone() }, - ).await?; + args::RevealPk { + tx: args.tx.clone(), + public_key: pk.clone(), + }, + ) + .await?; if let Some((mut rtx, _, pk)) = reveal_pk { // Sign the reveal public key transaction with the fee payer - signing::sign_tx(&mut ctx.wallet, &mut rtx, &args.tx, &pk) - .await?; + signing::sign_tx(&mut ctx.wallet, &mut rtx, &args.tx, &pk).await?; // Submit the reveal public key transaction first tx::process_tx(client, &mut ctx.wallet, &args.tx, rtx).await?; // Update the stateful PoW challenge of the outer transaction #[cfg(not(feature = "mainnet"))] - signing::update_pow_challenge(client, &args.tx, &mut tx, &pk, false) - .await; + signing::update_pow_challenge( + client, &args.tx, &mut tx, &pk, false, + ) + .await; } } signing::sign_tx(&mut ctx.wallet, &mut tx, &args.tx, &pk).await?; @@ -90,18 +91,23 @@ pub async fn submit_update_vp( let reveal_pk = tx::build_reveal_pk( client, &mut ctx.wallet, - args::RevealPk { tx: args.tx.clone(), public_key: pk.clone() }, - ).await?; + args::RevealPk { + tx: args.tx.clone(), + public_key: pk.clone(), + }, + ) + .await?; if let Some((mut rtx, _, pk)) = reveal_pk { // Sign the reveal public key transaction with the fee payer - signing::sign_tx(&mut ctx.wallet, &mut rtx, &args.tx, &pk) - .await?; + signing::sign_tx(&mut ctx.wallet, &mut rtx, &args.tx, &pk).await?; // Submit the reveal public key transaction first tx::process_tx(client, &mut ctx.wallet, &args.tx, rtx).await?; // Update the stateful PoW challenge of the outer transaction #[cfg(not(feature = "mainnet"))] - signing::update_pow_challenge(client, &args.tx, &mut tx, &pk, false) - .await; + signing::update_pow_challenge( + client, &args.tx, &mut tx, &pk, false, + ) + .await; } } signing::sign_tx(&mut ctx.wallet, &mut tx, &args.tx, &pk).await?; @@ -121,18 +127,23 @@ pub async fn submit_init_account( let reveal_pk = tx::build_reveal_pk( client, &mut ctx.wallet, - args::RevealPk { tx: args.tx.clone(), public_key: pk.clone() }, - ).await?; + args::RevealPk { + tx: args.tx.clone(), + public_key: pk.clone(), + }, + ) + .await?; if let Some((mut rtx, _, pk)) = reveal_pk { // Sign the reveal public key transaction with the fee payer - signing::sign_tx(&mut ctx.wallet, &mut rtx, &args.tx, &pk) - .await?; + signing::sign_tx(&mut ctx.wallet, &mut rtx, &args.tx, &pk).await?; // Submit the reveal public key transaction first tx::process_tx(client, &mut ctx.wallet, &args.tx, rtx).await?; // Update the stateful PoW challenge of the outer transaction #[cfg(not(feature = "mainnet"))] - signing::update_pow_challenge(client, &args.tx, &mut tx, &pk, false) - .await; + signing::update_pow_challenge( + client, &args.tx, &mut tx, &pk, false, + ) + .await; } } signing::sign_tx(&mut ctx.wallet, &mut tx, &args.tx, &pk).await?; @@ -289,35 +300,41 @@ pub async fn submit_init_validator< #[cfg(not(feature = "mainnet"))] false, ) - .await?; + .await?; // Build a transaction to reveal the signer of this transaction if let Some(Address::Implicit(_)) = addr { let reveal_pk = tx::build_reveal_pk( client, &mut ctx.wallet, - args::RevealPk { tx: tx_args.clone(), public_key: pk.clone() }, - ).await?; + args::RevealPk { + tx: tx_args.clone(), + public_key: pk.clone(), + }, + ) + .await?; if let Some((mut rtx, _, pk)) = reveal_pk { // Sign the reveal public key transaction with the fee payer - signing::sign_tx(&mut ctx.wallet, &mut rtx, &tx_args, &pk) - .await?; + signing::sign_tx(&mut ctx.wallet, &mut rtx, &tx_args, &pk).await?; // Submit the reveal public key transaction first tx::process_tx(client, &mut ctx.wallet, &tx_args, rtx).await?; // Update the stateful PoW challenge of the outer transaction #[cfg(not(feature = "mainnet"))] - signing::update_pow_challenge(client, &tx_args, &mut tx, &pk, false) - .await; + signing::update_pow_challenge( + client, &tx_args, &mut tx, &pk, false, + ) + .await; } } signing::sign_tx(&mut ctx.wallet, &mut tx, &tx_args, &pk).await?; - let result = tx::process_tx(client, &mut ctx.wallet, &tx_args, tx).await? + let result = tx::process_tx(client, &mut ctx.wallet, &tx_args, tx) + .await? .initialized_accounts(); if !tx_args.dry_run { let (validator_address_alias, validator_address) = match &result[..] { // There should be 1 account for the validator itself [validator_address] => { - if let Some(alias) = ctx.wallet.find_alias(validator_address) { + if let Some(alias) = ctx.wallet.find_alias(validator_address) { (alias.clone(), validator_address.clone()) } else { eprintln!("Expected one account to be created"); @@ -496,14 +513,18 @@ pub async fn submit_transfer( let arg = args.clone(); let (mut tx, addr, pk, tx_epoch, isf) = tx::build_transfer(client, &mut ctx.wallet, &mut ctx.shielded, arg) - .await?; + .await?; // Build a transaction to reveal the signer of this transaction if let Some(Address::Implicit(_)) = addr { let reveal_pk = tx::build_reveal_pk( client, &mut ctx.wallet, - args::RevealPk { tx: args.tx.clone(), public_key: pk.clone() }, - ).await?; + args::RevealPk { + tx: args.tx.clone(), + public_key: pk.clone(), + }, + ) + .await?; if let Some((mut rtx, _, pk)) = reveal_pk { // Sign the reveal public key transaction with the fee payer signing::sign_tx(&mut ctx.wallet, &mut rtx, &args.tx, &pk) @@ -512,14 +533,15 @@ pub async fn submit_transfer( tx::process_tx(client, &mut ctx.wallet, &args.tx, rtx).await?; // Update the stateful PoW challenge of the outer transaction #[cfg(not(feature = "mainnet"))] - signing::update_pow_challenge(client, &args.tx, &mut tx, &pk, isf) - .await; + signing::update_pow_challenge( + client, &args.tx, &mut tx, &pk, isf, + ) + .await; } } - signing::sign_tx(&mut ctx.wallet, &mut tx, &args.tx, &pk) - .await?; - let result = tx::process_tx(client, &mut ctx.wallet, &args.tx, tx) - .await?; + signing::sign_tx(&mut ctx.wallet, &mut tx, &args.tx, &pk).await?; + let result = + tx::process_tx(client, &mut ctx.wallet, &args.tx, tx).await?; // Query the epoch in which the transaction was probably submitted let submission_epoch = rpc::query_and_print_epoch(client).await; @@ -559,18 +581,23 @@ pub async fn submit_ibc_transfer( let reveal_pk = tx::build_reveal_pk( client, &mut ctx.wallet, - args::RevealPk { tx: args.tx.clone(), public_key: pk.clone() }, - ).await?; + args::RevealPk { + tx: args.tx.clone(), + public_key: pk.clone(), + }, + ) + .await?; if let Some((mut rtx, _, pk)) = reveal_pk { // Sign the reveal public key transaction with the fee payer - signing::sign_tx(&mut ctx.wallet, &mut rtx, &args.tx, &pk) - .await?; + signing::sign_tx(&mut ctx.wallet, &mut rtx, &args.tx, &pk).await?; // Submit the reveal public key transaction first tx::process_tx(client, &mut ctx.wallet, &args.tx, rtx).await?; // Update the stateful PoW challenge of the outer transaction #[cfg(not(feature = "mainnet"))] - signing::update_pow_challenge(client, &args.tx, &mut tx, &pk, false) - .await; + signing::update_pow_challenge( + client, &args.tx, &mut tx, &pk, false, + ) + .await; } } signing::sign_tx(&mut ctx.wallet, &mut tx, &args.tx, &pk).await?; @@ -727,14 +754,18 @@ pub async fn submit_init_proposal( #[cfg(not(feature = "mainnet"))] false, ) - .await?; + .await?; // Build a transaction to reveal the signer of this transaction if let Some(Address::Implicit(_)) = addr { let reveal_pk = tx::build_reveal_pk( client, &mut ctx.wallet, - args::RevealPk { tx: args.tx.clone(), public_key: pk.clone() }, - ).await?; + args::RevealPk { + tx: args.tx.clone(), + public_key: pk.clone(), + }, + ) + .await?; if let Some((mut rtx, _, pk)) = reveal_pk { // Sign the reveal public key transaction with the fee payer signing::sign_tx(&mut ctx.wallet, &mut rtx, &args.tx, &pk) @@ -743,12 +774,13 @@ pub async fn submit_init_proposal( tx::process_tx(client, &mut ctx.wallet, &args.tx, rtx).await?; // Update the stateful PoW challenge of the outer transaction #[cfg(not(feature = "mainnet"))] - signing::update_pow_challenge(client, &args.tx, &mut tx, &pk, false) - .await; + signing::update_pow_challenge( + client, &args.tx, &mut tx, &pk, false, + ) + .await; } } - signing::sign_tx(&mut ctx.wallet, &mut tx, &args.tx, &pk) - .await?; + signing::sign_tx(&mut ctx.wallet, &mut tx, &args.tx, &pk).await?; tx::process_tx(client, &mut ctx.wallet, &args.tx, tx).await?; Ok(()) } @@ -1003,24 +1035,38 @@ pub async fn submit_vote_proposal( #[cfg(not(feature = "mainnet"))] false, ) - .await?; + .await?; // Build a transaction to reveal the signer of this transaction if let Some(Address::Implicit(_)) = addr { let reveal_pk = tx::build_reveal_pk( client, &mut ctx.wallet, - args::RevealPk { tx: args.tx.clone(), public_key: pk.clone() }, - ).await?; + args::RevealPk { + tx: args.tx.clone(), + public_key: pk.clone(), + }, + ) + .await?; if let Some((mut rtx, _, pk)) = reveal_pk { - // Sign the reveal public key transaction with the fee payer - signing::sign_tx(&mut ctx.wallet, &mut rtx, &args.tx, &pk) - .await?; + // Sign the reveal public key transaction with the fee + // payer + signing::sign_tx( + &mut ctx.wallet, + &mut rtx, + &args.tx, + &pk, + ) + .await?; // Submit the reveal public key transaction first - tx::process_tx(client, &mut ctx.wallet, &args.tx, rtx).await?; - // Update the stateful PoW challenge of the outer transaction + tx::process_tx(client, &mut ctx.wallet, &args.tx, rtx) + .await?; + // Update the stateful PoW challenge of the outer + // transaction #[cfg(not(feature = "mainnet"))] - signing::update_pow_challenge(client, &args.tx, &mut tx, &pk, false) - .await; + signing::update_pow_challenge( + client, &args.tx, &mut tx, &pk, false, + ) + .await; } } signing::sign_tx(&mut ctx.wallet, &mut tx, &args.tx, &pk) @@ -1047,8 +1093,7 @@ pub async fn submit_reveal_pk( let reveal_tx = tx::build_reveal_pk(client, &mut ctx.wallet, args.clone()).await?; if let Some((mut tx, _, pk)) = reveal_tx { - signing::sign_tx(&mut ctx.wallet, &mut tx, &args.tx, &pk) - .await?; + signing::sign_tx(&mut ctx.wallet, &mut tx, &args.tx, &pk).await?; tx::process_tx(client, &mut ctx.wallet, &args.tx, tx).await?; } Ok(()) @@ -1109,24 +1154,30 @@ pub async fn submit_bond( ctx: &mut Context, args: args::Bond, ) -> Result<(), tx::Error> { - let (mut tx, addr, pk) = tx::build_bond::(client, &mut ctx.wallet, args.clone()).await?; + let (mut tx, addr, pk) = + tx::build_bond::(client, &mut ctx.wallet, args.clone()).await?; // Build a transaction to reveal the signer of this transaction if let Some(Address::Implicit(_)) = addr { let reveal_pk = tx::build_reveal_pk( client, &mut ctx.wallet, - args::RevealPk { tx: args.tx.clone(), public_key: pk.clone() }, - ).await?; + args::RevealPk { + tx: args.tx.clone(), + public_key: pk.clone(), + }, + ) + .await?; if let Some((mut rtx, _, pk)) = reveal_pk { // Sign the reveal public key transaction with the fee payer - signing::sign_tx(&mut ctx.wallet, &mut rtx, &args.tx, &pk) - .await?; + signing::sign_tx(&mut ctx.wallet, &mut rtx, &args.tx, &pk).await?; // Submit the reveal public key transaction first tx::process_tx(client, &mut ctx.wallet, &args.tx, rtx).await?; // Update the stateful PoW challenge of the outer transaction #[cfg(not(feature = "mainnet"))] - signing::update_pow_challenge(client, &args.tx, &mut tx, &pk, false) - .await; + signing::update_pow_challenge( + client, &args.tx, &mut tx, &pk, false, + ) + .await; } } signing::sign_tx(&mut ctx.wallet, &mut tx, &args.tx, &pk).await?; @@ -1146,18 +1197,23 @@ pub async fn submit_unbond( let reveal_pk = tx::build_reveal_pk( client, &mut ctx.wallet, - args::RevealPk { tx: args.tx.clone(), public_key: pk.clone() }, - ).await?; + args::RevealPk { + tx: args.tx.clone(), + public_key: pk.clone(), + }, + ) + .await?; if let Some((mut rtx, _, pk)) = reveal_pk { // Sign the reveal public key transaction with the fee payer - signing::sign_tx(&mut ctx.wallet, &mut rtx, &args.tx, &pk) - .await?; + signing::sign_tx(&mut ctx.wallet, &mut rtx, &args.tx, &pk).await?; // Submit the reveal public key transaction first tx::process_tx(client, &mut ctx.wallet, &args.tx, rtx).await?; #[cfg(not(feature = "mainnet"))] // Update the stateful PoW challenge of the outer transaction - signing::update_pow_challenge(client, &args.tx, &mut tx, &pk, false) - .await; + signing::update_pow_challenge( + client, &args.tx, &mut tx, &pk, false, + ) + .await; } } signing::sign_tx(&mut ctx.wallet, &mut tx, &args.tx, &pk).await?; @@ -1171,25 +1227,30 @@ pub async fn submit_withdraw( mut ctx: Context, args: args::Withdraw, ) -> Result<(), tx::Error> { - let (mut tx, addr, pk) = tx::build_withdraw(client, &mut ctx.wallet, args.clone()) - .await?; + let (mut tx, addr, pk) = + tx::build_withdraw(client, &mut ctx.wallet, args.clone()).await?; // Build a transaction to reveal the signer of this transaction if let Some(Address::Implicit(_)) = addr { let reveal_pk = tx::build_reveal_pk( client, &mut ctx.wallet, - args::RevealPk { tx: args.tx.clone(), public_key: pk.clone() }, - ).await?; + args::RevealPk { + tx: args.tx.clone(), + public_key: pk.clone(), + }, + ) + .await?; if let Some((mut rtx, _, pk)) = reveal_pk { // Sign the reveal public key transaction with the fee payer - signing::sign_tx(&mut ctx.wallet, &mut rtx, &args.tx, &pk) - .await?; + signing::sign_tx(&mut ctx.wallet, &mut rtx, &args.tx, &pk).await?; // Submit the reveal public key transaction first tx::process_tx(client, &mut ctx.wallet, &args.tx, rtx).await?; // Update the stateful PoW challenge of the outer transaction #[cfg(not(feature = "mainnet"))] - signing::update_pow_challenge(client, &args.tx, &mut tx, &pk, false) - .await; + signing::update_pow_challenge( + client, &args.tx, &mut tx, &pk, false, + ) + .await; } } signing::sign_tx(&mut ctx.wallet, &mut tx, &args.tx, &pk).await?; @@ -1207,24 +1268,29 @@ pub async fn submit_validator_commission_change< let arg = args.clone(); let (mut tx, addr, pk) = tx::build_validator_commission_change(client, &mut ctx.wallet, arg) - .await?; + .await?; // Build a transaction to reveal the signer of this transaction if let Some(Address::Implicit(_)) = addr { let reveal_pk = tx::build_reveal_pk( client, &mut ctx.wallet, - args::RevealPk { tx: args.tx.clone(), public_key: pk.clone() }, - ).await?; + args::RevealPk { + tx: args.tx.clone(), + public_key: pk.clone(), + }, + ) + .await?; if let Some((mut rtx, _, pk)) = reveal_pk { // Sign the reveal public key transaction with the fee payer - signing::sign_tx(&mut ctx.wallet, &mut rtx, &args.tx, &pk) - .await?; + signing::sign_tx(&mut ctx.wallet, &mut rtx, &args.tx, &pk).await?; // Submit the reveal public key transaction first tx::process_tx(client, &mut ctx.wallet, &args.tx, rtx).await?; // Update the stateful PoW challenge of the outer transaction #[cfg(not(feature = "mainnet"))] - signing::update_pow_challenge(client, &args.tx, &mut tx, &pk, false) - .await; + signing::update_pow_challenge( + client, &args.tx, &mut tx, &pk, false, + ) + .await; } } signing::sign_tx(&mut ctx.wallet, &mut tx, &args.tx, &pk).await?; @@ -1241,24 +1307,29 @@ pub async fn submit_unjail_validator< ) -> Result<(), tx::Error> { let (mut tx, addr, pk) = tx::build_unjail_validator(client, &mut ctx.wallet, args.clone()) - .await?; + .await?; // Build a transaction to reveal the signer of this transaction if let Some(Address::Implicit(_)) = addr { let reveal_pk = tx::build_reveal_pk( client, &mut ctx.wallet, - args::RevealPk { tx: args.tx.clone(), public_key: pk.clone() }, - ).await?; + args::RevealPk { + tx: args.tx.clone(), + public_key: pk.clone(), + }, + ) + .await?; if let Some((mut rtx, _, pk)) = reveal_pk { // Sign the reveal public key transaction with the fee payer - signing::sign_tx(&mut ctx.wallet, &mut rtx, &args.tx, &pk) - .await?; + signing::sign_tx(&mut ctx.wallet, &mut rtx, &args.tx, &pk).await?; // Submit the reveal public key transaction first tx::process_tx(client, &mut ctx.wallet, &args.tx, rtx).await?; // Update the stateful PoW challenge of the outer transaction #[cfg(not(feature = "mainnet"))] - signing::update_pow_challenge(client, &args.tx, &mut tx, &pk, false) - .await; + signing::update_pow_challenge( + client, &args.tx, &mut tx, &pk, false, + ) + .await; } } signing::sign_tx(&mut ctx.wallet, &mut tx, &args.tx, &pk).await?; diff --git a/proof_of_stake/src/lib.rs b/proof_of_stake/src/lib.rs index 4e8cbb560f..9815520f72 100644 --- a/proof_of_stake/src/lib.rs +++ b/proof_of_stake/src/lib.rs @@ -53,9 +53,11 @@ use storage::{ get_validator_address_from_bond, into_tm_voting_power, is_bond_key, is_unbond_key, is_validator_slashes_key, last_block_proposer_key, params_key, slashes_prefix, unbonds_for_source_prefix, unbonds_prefix, - validator_address_raw_hash_key, validator_max_commission_rate_change_key, - BondDetails, BondsAndUnbondsDetail, BondsAndUnbondsDetails, - ReverseOrdTokenAmount, RewardsAccumulator, UnbondDetails, + validator_address_raw_hash_key, validator_last_slash_key, + validator_max_commission_rate_change_key, BondDetails, + BondsAndUnbondsDetail, BondsAndUnbondsDetails, EpochedSlashes, + ReverseOrdTokenAmount, RewardsAccumulator, SlashedAmount, UnbondDetails, + ValidatorAddresses, ValidatorUnbondRecords, }; use thiserror::Error; use types::{ diff --git a/shared/src/ledger/signing.rs b/shared/src/ledger/signing.rs index 99c218b2ed..cbd05d9959 100644 --- a/shared/src/ledger/signing.rs +++ b/shared/src/ledger/signing.rs @@ -15,7 +15,9 @@ use masp_primitives::asset_type::AssetType; use masp_primitives::transaction::components::sapling::fees::{ InputView, OutputView, }; -use namada_core::types::address::{masp, masp_tx_key, Address, ImplicitAddress}; +use namada_core::types::address::{ + masp, masp_tx_key, Address, ImplicitAddress, +}; use namada_core::types::storage::Key; use namada_core::types::token::{ self, Amount, DenominatedAmount, MaspDenom, TokenAddress, @@ -81,23 +83,24 @@ pub async fn find_pk< "Looking-up public key of {} from the ledger...", addr.encode() ); - rpc::get_public_key(client, addr).await.ok_or( - Error::Other(format!( + rpc::get_public_key(client, addr).await.ok_or(Error::Other( + format!( "No public key found for the address {}", addr.encode() - )), - ) + ), + )) } - Address::Implicit(ImplicitAddress(pkh)) => { - Ok(wallet.find_key_by_pkh(pkh, password).map_err(|err| { + Address::Implicit(ImplicitAddress(pkh)) => Ok(wallet + .find_key_by_pkh(pkh, password) + .map_err(|err| { Error::Other(format!( "Unable to load the keypair from the wallet for the \ implicit address {}. Failed with: {}", addr.encode(), err )) - })?.ref_to()) - } + })? + .ref_to()), Address::Internal(_) => other_err(format!( "Internal address {} doesn't have any signing keys.", addr @@ -116,18 +119,25 @@ pub fn find_key_by_pk( if *keypair == masp_tx_key().ref_to() { // We already know the secret key corresponding to the MASP sentinal key Ok(masp_tx_key()) - } else if args.signing_key.as_ref().map(|x| x.ref_to() == *keypair).unwrap_or(false) { + } else if args + .signing_key + .as_ref() + .map(|x| x.ref_to() == *keypair) + .unwrap_or(false) + { // We can lookup the secret key from the CLI arguments in this case Ok(args.signing_key.clone().unwrap()) } else { // Otherwise we need to search the wallet for the secret key - wallet.find_key_by_pk(&keypair, args.password.clone()).map_err(|err| { - Error::Other(format!( - "Unable to load the keypair from the wallet for public \ - key {}. Failed with: {}", - keypair, err - )) - }) + wallet + .find_key_by_pk(keypair, args.password.clone()) + .map_err(|err| { + Error::Other(format!( + "Unable to load the keypair from the wallet for public \ + key {}. Failed with: {}", + keypair, err + )) + }) } } @@ -173,16 +183,12 @@ pub async fn tx_signer< match signer { TxSigningKey::WalletAddress(signer) if signer == masp() => { Ok((None, masp_tx_key().ref_to())) - }, - TxSigningKey::WalletAddress(signer) => { - Ok((Some(signer.clone()), find_pk::( - client, - wallet, - &signer, - args.password.clone(), - ) - .await?)) } + TxSigningKey::WalletAddress(signer) => Ok(( + Some(signer.clone()), + find_pk::(client, wallet, &signer, args.password.clone()) + .await?, + )), TxSigningKey::None => other_err( "All transactions must be signed; please either specify the key \ or the address from which to look up the signing key." @@ -199,9 +205,7 @@ pub async fn tx_signer< /// hashes needed for monitoring the tx on chain. /// /// If it is a dry run, it is not put in a wrapper, but returned as is. -pub async fn sign_tx< - U: WalletUtils, ->( +pub async fn sign_tx( wallet: &mut Wallet, tx: &mut Tx, args: &args::Tx, @@ -229,9 +233,7 @@ pub async fn sign_tx< #[cfg(not(feature = "mainnet"))] /// Solve the PoW challenge if balance is insufficient to pay transaction fees /// or if solution is explicitly requested. -pub async fn solve_pow_challenge< - C: crate::ledger::queries::Client + Sync, - >( +pub async fn solve_pow_challenge( client: &C, args: &args::Tx, keypair: &common::PublicKey, @@ -242,8 +244,8 @@ pub async fn solve_pow_challenge< client, &wrapper_tx_fees_key, ) - .await - .unwrap_or_default(); + .await + .unwrap_or_default(); let fee_token = &args.fee_token; let source = Address::from(keypair); let balance_key = token::balance_key(fee_token, &source); @@ -253,28 +255,31 @@ pub async fn solve_pow_challenge< .unwrap_or_default(); let is_bal_sufficient = fee_amount <= balance; if !is_bal_sufficient { - eprintln!( + let token_addr = TokenAddress { + address: args.fee_token.clone(), + sub_prefix: None, + }; + let err_msg = format!( "The wrapper transaction source doesn't have enough balance to \ - pay fee {fee_amount}, got {balance}." + pay fee {}, got {}.", + format_denominated_amount(client, &token_addr, fee_amount).await, + format_denominated_amount(client, &token_addr, balance).await, ); if !args.force && cfg!(feature = "mainnet") { - panic!( - "The wrapper transaction source doesn't have enough balance \ - to pay fee {fee_amount}, got {balance}." - ); + panic!("{}", err_msg); } } - let fee = Fee { amount: fee_amount, token: fee_token.clone() }; + let fee = Fee { + amount: fee_amount, + token: fee_token.clone(), + }; // A PoW solution can be used to allow zero-fee testnet transactions // If the address derived from the keypair doesn't have enough balance // to pay for the fee, allow to find a PoW solution instead. if requires_pow || !is_bal_sufficient { - println!( - "The transaction requires the completion of a PoW challenge." - ); + println!("The transaction requires the completion of a PoW challenge."); // Obtain a PoW challenge for faucet withdrawal - let challenge = - rpc::get_testnet_pow_challenge(client, source).await; + let challenge = rpc::get_testnet_pow_challenge(client, source).await; // Solve the solution, this blocks until a solution is found let solution = challenge.solve(); @@ -286,23 +291,18 @@ pub async fn solve_pow_challenge< #[cfg(not(feature = "mainnet"))] /// Update the PoW challenge inside the given transaction -pub async fn update_pow_challenge< - C: crate::ledger::queries::Client + Sync, - >( +pub async fn update_pow_challenge( client: &C, args: &args::Tx, tx: &mut Tx, keypair: &common::PublicKey, requires_pow: bool, ) { - match &mut tx.header.tx_type { - TxType::Wrapper(wrapper) => { - let (pow_solution, fee) = - solve_pow_challenge(client, args, keypair, requires_pow).await; - wrapper.fee = fee; - wrapper.pow_solution = pow_solution; - }, - _ => {}, + if let TxType::Wrapper(wrapper) = &mut tx.header.tx_type { + let (pow_solution, fee) = + solve_pow_challenge(client, args, keypair, requires_pow).await; + wrapper.fee = fee; + wrapper.pow_solution = pow_solution; } } diff --git a/shared/src/ledger/tx.rs b/shared/src/ledger/tx.rs index d744312c19..c63da9f62c 100644 --- a/shared/src/ledger/tx.rs +++ b/shared/src/ledger/tx.rs @@ -4,7 +4,6 @@ use std::collections::{BTreeMap, HashMap, HashSet}; use std::str::FromStr; use borsh::BorshSerialize; -use itertools::Either::*; use masp_primitives::asset_type::AssetType; use masp_primitives::transaction::builder; use masp_primitives::transaction::builder::Builder; @@ -38,9 +37,9 @@ use crate::ledger::args::{self, InputAmount}; use crate::ledger::governance::storage as gov_storage; use crate::ledger::masp::{ShieldedContext, ShieldedUtils}; use crate::ledger::rpc::{self, validate_amount, TxBroadcastData, TxResponse}; -use crate::ledger::signing::{find_keypair, sign_tx, tx_signer, TxSigningKey, wrap_tx, find_pk}; +use crate::ledger::signing::{tx_signer, wrap_tx, TxSigningKey}; use crate::ledger::wallet::{Wallet, WalletUtils}; -use crate::proto::{Code, Data, MaspBuilder, Section, Signature, Tx}; +use crate::proto::{Code, Data, MaspBuilder, Section, Tx}; use crate::tendermint_rpc::endpoint::broadcast::tx_sync::Response; use crate::tendermint_rpc::error::Error as RpcError; use crate::types::hash::Hash; @@ -160,7 +159,13 @@ pub enum Error { transferred and fees. Amount to transfer is {1} {2} and fees are {3} \ {4}." )] - NegativeBalanceAfterTransfer(Address, String, Address, String, Address), + NegativeBalanceAfterTransfer( + Box
, + String, + Box
, + String, + Box
, + ), /// No Balance found for token #[error("{0}")] MaspError(builder::Error), @@ -224,9 +229,9 @@ impl ProcessTxResponse { /// Prepare a transaction for signing and submission by adding a wrapper header /// to it. pub async fn prepare_tx< - C: crate::ledger::queries::Client + Sync, + C: crate::ledger::queries::Client + Sync, U: WalletUtils, - >( +>( client: &C, wallet: &mut Wallet, args: &args::Tx, @@ -234,34 +239,34 @@ pub async fn prepare_tx< default_signer: TxSigningKey, #[cfg(not(feature = "mainnet"))] requires_pow: bool, ) -> Result<(Tx, Option
, common::PublicKey), Error> { - let (signer_addr, signer_pk) = tx_signer::( - client, - wallet, - args, - default_signer.clone(), - ).await?; + let (signer_addr, signer_pk) = + tx_signer::(client, wallet, args, default_signer.clone()).await?; if args.dry_run { Ok((tx, signer_addr, signer_pk)) } else { let epoch = rpc::query_epoch(client).await; - Ok((wrap_tx( - client, - wallet, - args, - epoch, - tx.clone(), - &signer_pk, - #[cfg(not(feature = "mainnet"))] - requires_pow, - ) - .await, signer_addr, signer_pk)) + Ok(( + wrap_tx( + client, + wallet, + args, + epoch, + tx.clone(), + &signer_pk, + #[cfg(not(feature = "mainnet"))] + requires_pow, + ) + .await, + signer_addr, + signer_pk, + )) } } /// Submit transaction and wait for result. Returns a list of addresses /// initialized in the transaction if any. In dry run, this is always empty. pub async fn process_tx< - C: crate::ledger::queries::Client + Sync, + C: crate::ledger::queries::Client + Sync, U: WalletUtils, >( client: &C, @@ -303,14 +308,20 @@ pub async fn process_tx< // Either broadcast or submit transaction and collect result into // sum type if args.broadcast_only { - broadcast_tx(client, &to_broadcast).await.map(ProcessTxResponse::Broadcast) + broadcast_tx(client, &to_broadcast) + .await + .map(ProcessTxResponse::Broadcast) } else { match submit_tx(client, to_broadcast).await { Ok(x) => { - save_initialized_accounts::(wallet, &args, x.initialized_accounts.clone()) - .await; + save_initialized_accounts::( + wallet, + args, + x.initialized_accounts.clone(), + ) + .await; Ok(ProcessTxResponse::Applied(x)) - }, + } Err(x) => Err(x), } } @@ -337,7 +348,10 @@ pub async fn build_reveal_pk< Ok(None) } else { // If not, submit it - Ok(Some(build_reveal_pk_aux::(client, wallet, &public_key, &args).await?)) + Ok(Some( + build_reveal_pk_aux::(client, wallet, &public_key, &args) + .await?, + )) } } @@ -393,7 +407,7 @@ pub async fn build_reveal_pk_aux< prepare_tx::( client, wallet, - &args, + args, tx, TxSigningKey::WalletAddress(addr), #[cfg(not(feature = "mainnet"))] @@ -725,6 +739,52 @@ pub async fn build_unjail_validator< .await } +/// Submit transaction to unjail a jailed validator +pub async fn submit_unjail_validator< + C: crate::ledger::queries::Client + Sync, + U: WalletUtils, +>( + client: &C, + wallet: &mut Wallet, + args: args::TxUnjailValidator, +) -> Result<(), Error> { + if !rpc::is_validator(client, &args.validator).await { + eprintln!("The given address {} is not a validator.", &args.validator); + if !args.tx.force { + return Err(Error::InvalidValidatorAddress(args.validator.clone())); + } + } + + let tx_code_path = String::from_utf8(args.tx_code_path).unwrap(); + let tx_code_hash = + query_wasm_code_hash(client, tx_code_path).await.unwrap(); + + let data = args + .validator + .clone() + .try_to_vec() + .map_err(Error::EncodeTxFailure)?; + + let mut tx = Tx::new(TxType::Raw); + tx.header.chain_id = args.tx.chain_id.clone().unwrap(); + tx.header.expiration = args.tx.expiration; + tx.set_data(Data::new(data)); + tx.set_code(Code::from_hash(tx_code_hash)); + + let default_signer = args.validator; + prepare_tx( + client, + wallet, + &args.tx, + tx, + TxSigningKey::WalletAddress(default_signer), + #[cfg(not(feature = "mainnet"))] + false, + ) + .await?; + Ok(()) +} + /// Submit transaction to withdraw an unbond pub async fn build_withdraw< C: crate::ledger::queries::Client + Sync, @@ -804,7 +864,15 @@ pub async fn build_unbond< client: &C, wallet: &mut Wallet, args: args::Unbond, -) -> Result<(Tx, Option
, common::PublicKey, Option<(Epoch, token::Amount)>), Error> { +) -> Result< + ( + Tx, + Option
, + common::PublicKey, + Option<(Epoch, token::Amount)>, + ), + Error, +> { let source = args.source.clone(); // Check the source's current bond amount let bond_source = source.clone().unwrap_or_else(|| args.validator.clone()); @@ -892,7 +960,7 @@ pub async fn query_unbonds( let source = args.source.clone(); // Check the source's current bond amount let bond_source = source.clone().unwrap_or_else(|| args.validator.clone()); - + // Query the unbonds post-tx let unbonds = rpc::query_unbond_with_slashing(client, &bond_source, &args.validator) @@ -1236,8 +1304,9 @@ pub async fn build_transfer< client: &C, wallet: &mut Wallet, shielded: &mut ShieldedContext, - args: args::TxTransfer, -) -> Result<(Tx, Option
, common::PublicKey, Option, bool), Error> { + mut args: args::TxTransfer, +) -> Result<(Tx, Option
, common::PublicKey, Option, bool), Error> +{ let source = args.source.effective_address(); let target = args.target.effective_address(); let token = args.token.clone(); @@ -1293,33 +1362,27 @@ pub async fn build_transfer< args.tx.force, client, ) - .await?; + .await?; let masp_addr = masp(); // For MASP sources, use a special sentinel key recognized by VPs as default // signer. Also, if the transaction is shielded, redact the amount and token // types by setting the transparent value to 0 and token type to a constant. // This has no side-effect because transaction is to self. - let (amount, token) = - if source == masp_addr && target == masp_addr { - // TODO Refactor me, we shouldn't rely on any specific token here. - ( - token::Amount::default(), - args.native_token.clone(), - ) - } else { - ( - validated_amount.amount, - token, - ) - }; - let default_signer = TxSigningKey::WalletAddress(args.source.effective_address()); + let (_amount, token) = if source == masp_addr && target == masp_addr { + // TODO Refactor me, we shouldn't rely on any specific token here. + (token::Amount::default(), args.native_token.clone()) + } else { + (validated_amount.amount, token) + }; + let default_signer = + TxSigningKey::WalletAddress(args.source.effective_address()); // If our chosen signer is the MASP sentinel key, then our shielded inputs // will need to cover the gas fees. let chosen_signer = tx_signer::(client, wallet, &args.tx, default_signer.clone()) - .await? - .1; + .await? + .1; let shielded_gas = masp_tx_key().ref_to() == chosen_signer; // Determine whether to pin this transaction to a storage key let key = match &args.target { @@ -1332,8 +1395,8 @@ pub async fn build_transfer< let tx_code_hash = query_wasm_code_hash(client, args.tx_code_path.to_str().unwrap()) - .await - .unwrap(); + .await + .unwrap(); // Construct the shielded part of the transaction, if any let stx_result = shielded @@ -1344,11 +1407,11 @@ pub async fn build_transfer< Ok(stx) => Ok(stx), Err(builder::Error::InsufficientFunds(_)) => { Err(Error::NegativeBalanceAfterTransfer( - source.clone(), - args.amount, - token.clone(), - args.tx.fee_amount, - args.tx.fee_token.clone(), + Box::new(source.clone()), + validated_amount.amount.to_string_native(), + Box::new(token.clone()), + validate_fee.amount.to_string_native(), + Box::new(args.tx.fee_token.clone()), )) } Err(err) => Err(Error::MaspError(err)), @@ -1368,8 +1431,7 @@ pub async fn build_transfer< Hash(masp_tx.hash(&mut Sha256::new()).finalize_reset().into()); // Get the decoded asset types used in the transaction to give // offline wallet users more information - let asset_types = - used_asset_types(shielded, client, &shielded_parts.0) + let asset_types = used_asset_types(shielded, client, &shielded_parts.0) .await .unwrap_or_default(); // Add the MASP Transaction's Builder to the Tx @@ -1393,7 +1455,7 @@ pub async fn build_transfer< target: target.clone(), token: token.clone(), sub_prefix: sub_prefix.clone(), - amount, + amount: validated_amount, key: key.clone(), // Link the Transfer to the MASP Transaction by hash code shielded: masp_hash, @@ -1417,8 +1479,14 @@ pub async fn build_transfer< #[cfg(not(feature = "mainnet"))] is_source_faucet, ) - .await?; - Ok((tx, signer_addr, def_key, shielded_tx_epoch, is_source_faucet)) + .await?; + Ok(( + tx, + signer_addr, + def_key, + shielded_tx_epoch, + is_source_faucet, + )) } /// Submit a transaction to initialize an account