From 44c5f039a3254491d796d66838a355459bd4e9c2 Mon Sep 17 00:00:00 2001 From: Murisi Tarusenga Date: Mon, 23 Sep 2024 11:49:55 +0200 Subject: [PATCH 01/12] Implemented MASP signing using the hardware wallet. --- Cargo.lock | 9 +- Cargo.toml | 6 +- crates/apps_lib/Cargo.toml | 1 + crates/apps_lib/src/cli/context.rs | 63 +++- crates/apps_lib/src/cli/wallet.rs | 70 ++++- crates/apps_lib/src/client/tx.rs | 291 +++++++++++++++++- .../src/config/genesis/transactions.rs | 1 + crates/benches/native_vps.rs | 13 +- crates/core/src/masp.rs | 38 +-- crates/node/src/bench_utils.rs | 2 + crates/sdk/src/args.rs | 7 +- crates/sdk/src/lib.rs | 7 +- crates/sdk/src/signing.rs | 5 + crates/sdk/src/tx.rs | 26 +- crates/shielded_token/src/masp.rs | 21 +- .../src/masp/shielded_wallet.rs | 30 +- crates/shielded_token/src/validation.rs | 4 +- crates/tests/src/integration/masp.rs | 37 ++- crates/token/src/lib.rs | 3 +- crates/tx/src/types.rs | 24 ++ crates/wallet/src/lib.rs | 29 +- crates/wallet/src/store.rs | 17 +- wasm/Cargo.lock | 6 +- wasm_for_tests/Cargo.lock | 6 +- 24 files changed, 615 insertions(+), 101 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7861b507ae..1365fc2c46 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4264,7 +4264,7 @@ dependencies = [ [[package]] name = "ledger-namada-rs" version = "0.0.1" -source = "git+https://github.com/Zondax/ledger-namada?tag=v0.0.24#ca9da5e0129f676934809f58acffbd855d280664" +source = "git+https://github.com/Zondax/ledger-namada?rev=f54b76adcc1430db0496e894ad72cd74cfb6eb88#f54b76adcc1430db0496e894ad72cd74cfb6eb88" dependencies = [ "bincode", "byteorder", @@ -4494,7 +4494,7 @@ dependencies = [ [[package]] name = "masp_note_encryption" version = "1.0.0" -source = "git+https://github.com/anoma/masp?rev=12ed8b060b295c06502a2ff8468e4a941cb7cca4#12ed8b060b295c06502a2ff8468e4a941cb7cca4" +source = "git+https://github.com/anoma/masp?rev=a35f73be69b21ee62cd4940f37855161cbed2a56#a35f73be69b21ee62cd4940f37855161cbed2a56" dependencies = [ "arbitrary", "borsh", @@ -4508,7 +4508,7 @@ dependencies = [ [[package]] name = "masp_primitives" version = "1.0.0" -source = "git+https://github.com/anoma/masp?rev=12ed8b060b295c06502a2ff8468e4a941cb7cca4#12ed8b060b295c06502a2ff8468e4a941cb7cca4" +source = "git+https://github.com/anoma/masp?rev=a35f73be69b21ee62cd4940f37855161cbed2a56#a35f73be69b21ee62cd4940f37855161cbed2a56" dependencies = [ "aes", "arbitrary", @@ -4541,7 +4541,7 @@ dependencies = [ [[package]] name = "masp_proofs" version = "1.0.0" -source = "git+https://github.com/anoma/masp?rev=12ed8b060b295c06502a2ff8468e4a941cb7cca4#12ed8b060b295c06502a2ff8468e4a941cb7cca4" +source = "git+https://github.com/anoma/masp?rev=a35f73be69b21ee62cd4940f37855161cbed2a56#a35f73be69b21ee62cd4940f37855161cbed2a56" dependencies = [ "bellman", "blake2b_simd", @@ -4769,6 +4769,7 @@ dependencies = [ "futures", "git2", "itertools 0.12.1", + "jubjub 0.10.0 (git+https://github.com/heliaxdev/jubjub.git?rev=a373686962f4e9d0edb3b4716f86ff6bbd9aa86c)", "kdam", "lazy_static", "ledger-lib", diff --git a/Cargo.toml b/Cargo.toml index c6699f1ce5..ed4916fdbb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -134,15 +134,15 @@ konst = { version = "0.3.8", default-features = false } lazy_static = "1.4.0" # TODO: upstreamed in https://github.com/ledger-community/rust-ledger/pull/9 ledger-lib = { git = "https://github.com/heliaxdev/rust-ledger", rev = "f96f4559b3237d09218f7583df01acf36034ea79", default-features = false, features = ["transport_tcp"] } -ledger-namada-rs = { git = "https://github.com/Zondax/ledger-namada", tag = "v0.0.24" } +ledger-namada-rs = { git = "https://github.com/Zondax/ledger-namada", rev = "f54b76adcc1430db0496e894ad72cd74cfb6eb88" } ledger-transport = "0.10.0" ledger-transport-hid = "0.10.0" libc = "0.2.97" libloading = "0.7.2" linkme = "0.3.24" # branch = "tomas/arbitrary" -masp_primitives = { git = "https://github.com/anoma/masp", rev = "12ed8b060b295c06502a2ff8468e4a941cb7cca4" } -masp_proofs = { git = "https://github.com/anoma/masp", rev = "12ed8b060b295c06502a2ff8468e4a941cb7cca4", default-features = false, features = ["local-prover"] } +masp_primitives = { git = "https://github.com/anoma/masp", rev = "a35f73be69b21ee62cd4940f37855161cbed2a56" } +masp_proofs = { git = "https://github.com/anoma/masp", rev = "a35f73be69b21ee62cd4940f37855161cbed2a56", default-features = false, features = ["local-prover"] } num256 = "0.3.5" num_cpus = "1.13.0" num-derive = "0.4" diff --git a/crates/apps_lib/Cargo.toml b/crates/apps_lib/Cargo.toml index c0fd42e600..9faaf7f38c 100644 --- a/crates/apps_lib/Cargo.toml +++ b/crates/apps_lib/Cargo.toml @@ -53,6 +53,7 @@ fd-lock.workspace = true flate2.workspace = true futures.workspace = true itertools.workspace = true +jubjub.workspace = true kdam.workspace = true lazy_static = { workspace = true, optional = true } linkme = { workspace = true, optional = true } diff --git a/crates/apps_lib/src/cli/context.rs b/crates/apps_lib/src/cli/context.rs index 63cf70fea2..588342ff08 100644 --- a/crates/apps_lib/src/cli/context.rs +++ b/crates/apps_lib/src/cli/context.rs @@ -6,6 +6,11 @@ use std::path::{Path, PathBuf}; use std::str::FromStr; use color_eyre::eyre::Result; +use masp_primitives::zip32::sapling::PseudoExtendedKey; +use masp_primitives::zip32::{ + ExtendedFullViewingKey as MaspExtendedViewingKey, + ExtendedSpendingKey as MaspExtendedSpendingKey, +}; use namada_core::masp::{ BalanceOwner, ExtendedSpendingKey, ExtendedViewingKey, PaymentAddress, TransferSource, TransferTarget, @@ -47,7 +52,7 @@ pub type WalletAddrOrNativeToken = FromContext; /// A raw extended spending key (bech32m encoding) or an alias of an extended /// spending key in the wallet -pub type WalletSpendingKey = FromContext; +pub type WalletSpendingKey = FromContext; /// A raw dated extended spending key (bech32m encoding) or an alias of an /// extended spending key in the wallet @@ -589,6 +594,48 @@ impl ArgFromMutContext for ExtendedSpendingKey { } } +impl ArgFromMutContext for PseudoExtendedKey { + fn arg_from_mut_ctx( + ctx: &mut ChainContext, + raw: impl AsRef, + ) -> Result { + let raw = raw.as_ref(); + // Either the string is a raw extended spending key + ExtendedSpendingKey::from_str(raw) + .map(|x| PseudoExtendedKey::from(MaspExtendedSpendingKey::from(x))) + .or_else(|_parse_err| { + ExtendedViewingKey::from_str(raw).map(|x| { + PseudoExtendedKey::from(MaspExtendedViewingKey::from(x)) + }) + }) + .or_else(|_parse_err| { + // Or it is a stored alias of one + ctx.wallet + .find_spending_key(raw, None) + .map(|k| { + PseudoExtendedKey::from(MaspExtendedSpendingKey::from( + k.key, + )) + }) + .map_err(|_find_err| { + format!("Unknown spending key {}", raw) + }) + }) + .or_else(|_parse_err| { + // Or it is a stored alias of one + ctx.wallet + .find_viewing_key(raw) + .copied() + .map(|k| { + PseudoExtendedKey::from(MaspExtendedViewingKey::from( + k.key, + )) + }) + .map_err(|_find_err| format!("Unknown viewing key {}", raw)) + }) + } +} + impl ArgFromMutContext for DatedSpendingKey { fn arg_from_mut_ctx( ctx: &mut ChainContext, @@ -667,8 +714,18 @@ impl ArgFromMutContext for TransferSource { Address::arg_from_ctx(ctx, raw) .map(Self::Address) .or_else(|_| { - ExtendedSpendingKey::arg_from_mut_ctx(ctx, raw) - .map(Self::ExtendedSpendingKey) + ExtendedSpendingKey::arg_from_mut_ctx(ctx, raw).map(|x| { + Self::ExtendedSpendingKey(PseudoExtendedKey::from( + MaspExtendedSpendingKey::from(x), + )) + }) + }) + .or_else(|_| { + ExtendedViewingKey::arg_from_mut_ctx(ctx, raw).map(|x| { + Self::ExtendedSpendingKey(PseudoExtendedKey::from( + MaspExtendedViewingKey::from(x), + )) + }) }) } } diff --git a/crates/apps_lib/src/cli/wallet.rs b/crates/apps_lib/src/cli/wallet.rs index e6a763f234..42f24a6b8d 100644 --- a/crates/apps_lib/src/cli/wallet.rs +++ b/crates/apps_lib/src/cli/wallet.rs @@ -8,7 +8,10 @@ use borsh::BorshDeserialize; use borsh_ext::BorshSerializeExt; use color_eyre::eyre::Result; use itertools::sorted; -use ledger_namada_rs::{BIP44Path, NamadaApp}; +use ledger_namada_rs::{BIP44Path, KeyResponse, NamadaApp, NamadaKeys}; +use ledger_transport_hid::hidapi::HidApi; +use ledger_transport_hid::TransportNativeHID; +use masp_primitives::zip32::ExtendedFullViewingKey; use namada_core::chain::BlockHeight; use namada_core::masp::{ExtendedSpendingKey, MaspValue, PaymentAddress}; use namada_sdk::address::{Address, DecodeError}; @@ -184,7 +187,7 @@ fn payment_addresses_list( } /// Derives a masp spending key from the mnemonic code in the wallet. -fn shielded_key_derive( +async fn shielded_key_derive( ctx: Context, io: &impl Io, args::KeyDerive { @@ -232,9 +235,56 @@ fn shielded_key_derive( }) .0 } else { - display_line!(io, "Not implemented."); - display_line!(io, "No changes are persisted. Exiting."); - cli::safe_exit(1) + let hidapi = HidApi::new().unwrap_or_else(|err| { + edisplay_line!(io, "Failed to create HidApi: {}", err); + cli::safe_exit(1) + }); + let app = NamadaApp::new( + TransportNativeHID::new(&hidapi).unwrap_or_else(|err| { + edisplay_line!(io, "Unable to connect to Ledger: {}", err); + cli::safe_exit(1) + }), + ); + let response = app + .retrieve_keys( + &BIP44Path { + path: derivation_path.to_string(), + }, + NamadaKeys::ViewKey, + true, + ) + .await + .unwrap_or_else(|err| { + edisplay_line!( + io, + "Unable to connect to query address and public key from \ + Ledger: {}", + err + ); + cli::safe_exit(1) + }); + let KeyResponse::ViewKey(response_key) = response else { + edisplay_line!(io, "Unexpected response from Ledger"); + cli::safe_exit(1) + }; + let xfvk = ExtendedFullViewingKey::try_from_slice(&response_key.xfvk) + .expect( + "unable to decode extended full viewing key from the hardware \ + wallet", + ); + + wallet + .insert_viewing_key( + alias, + xfvk.into(), + birthday, + alias_force, + Some(derivation_path), + ) + .unwrap_or_else(|| { + display_line!(io, "No changes are persisted. Exiting."); + cli::safe_exit(1) + }) }; wallet .save() @@ -367,7 +417,13 @@ fn shielded_key_address_add( let (alias, typ) = match masp_value { MaspValue::FullViewingKey(viewing_key) => { let alias = wallet - .insert_viewing_key(alias, viewing_key, birthday, alias_force) + .insert_viewing_key( + alias, + viewing_key, + birthday, + alias_force, + None, + ) .unwrap_or_else(|| { edisplay_line!(io, "Viewing key not added"); cli::safe_exit(1); @@ -638,7 +694,7 @@ async fn key_derive( if !args_key_derive.shielded { transparent_key_and_address_derive(ctx, io, args_key_derive).await } else { - shielded_key_derive(ctx, io, args_key_derive) + shielded_key_derive(ctx, io, args_key_derive).await } } diff --git a/crates/apps_lib/src/client/tx.rs b/crates/apps_lib/src/client/tx.rs index 26b2dd0df5..38bc19fc98 100644 --- a/crates/apps_lib/src/client/tx.rs +++ b/crates/apps_lib/src/client/tx.rs @@ -4,11 +4,20 @@ use std::io::Write; use borsh::BorshDeserialize; use borsh_ext::BorshSerializeExt; use color_eyre::owo_colors::OwoColorize; -use ledger_namada_rs::{BIP44Path, NamadaApp}; use namada_core::masp::MaspTransaction; +use ledger_namada_rs::{BIP44Path, KeyResponse, NamadaApp, NamadaKeys}; +use masp_primitives::sapling::redjubjub::PrivateKey; +use masp_primitives::sapling::{redjubjub, ProofGenerationKey}; +use masp_primitives::transaction::components::sapling; +use masp_primitives::transaction::components::sapling::builder::{ + BuildParams, ConvertBuildParams, OutputBuildParams, RngBuildParams, + SpendBuildParams, StoredBuildParams, +}; +use masp_primitives::transaction::components::sapling::fees::InputView; +use masp_primitives::zip32::{ExtendedFullViewingKey, ExtendedKey}; use namada_sdk::address::{Address, ImplicitAddress}; use namada_sdk::args::TxBecomeValidator; -use namada_sdk::collections::HashSet; +use namada_sdk::collections::{HashMap, HashSet}; use namada_sdk::governance::cli::onchain::{ DefaultProposal, PgfFundingProposal, PgfStewardProposal, }; @@ -21,7 +30,7 @@ use namada_sdk::tx::data::compute_inner_tx_hash; use namada_sdk::tx::{CompressedAuthorization, Section, Signer, Tx}; use namada_sdk::wallet::alias::{validator_address, validator_consensus_key}; use namada_sdk::wallet::{Wallet, WalletIo}; -use namada_sdk::{error, signing, tx, Namada}; +use namada_sdk::{error, signing, tx, ExtendedViewingKey, Namada}; use rand::rngs::OsRng; use tokio::sync::RwLock; @@ -826,9 +835,38 @@ pub async fn submit_transparent_transfer( Ok(()) } +// A mapper that replaces authorization signatures with those in a built-in map +struct MapSaplingSigAuth( + HashMap::AuthSig>, +); + +impl sapling::MapAuth + for MapSaplingSigAuth +{ + fn map_proof( + &self, + p: ::Proof, + _pos: usize, + ) -> ::Proof { + p + } + + fn map_auth_sig( + &self, + s: ::AuthSig, + pos: usize, + ) -> ::AuthSig { + self.0.get(&pos).cloned().unwrap_or(s) + } + + fn map_authorization(&self, a: sapling::Authorized) -> sapling::Authorized { + a + } +} + pub async fn submit_shielded_transfer( namada: &impl Namada, - args: args::TxShieldedTransfer, + mut args: args::TxShieldedTransfer, ) -> Result<(), error::Error> { display_line!( namada.io(), @@ -838,8 +876,167 @@ pub async fn submit_shielded_transfer( to date, make sure to run `namadac shielded-sync` before running \ this command.", ); - - let (mut tx, signing_data) = args.clone().build(namada).await?; + + // Records the shielded keys that are on the hardware wallet + let mut shielded_hw_keys = HashMap::new(); + // Construct the build parameters that parameterized the Transaction + // authorizations + let mut bparams: Box = if args.tx.use_device { + let transport = WalletTransport::from_arg(args.tx.device_transport); + let app = NamadaApp::new(transport); + // Clear hardware wallet randomness buffers + app.clean_randomness_buffers().await.map_err(|err| { + error::Error::Other(format!( + "Unable to clear randomness buffer. Error: {}", + err, + )) + })?; + let wallet = namada.wallet().await; + // Augment the pseudo spending key with a proof authorization key + for data in &mut args.data { + // Only attempt an augmentation if proof authorization is not there + if data.source.to_spending_key().is_none() { + // First find the derivation path corresponding to this viewing + // key + let viewing_key = + ExtendedViewingKey::from(data.source.to_viewing_key()); + let path = wallet + .find_path_by_viewing_key(&viewing_key) + .map_err(|err| { + error::Error::Other(format!( + "Unable to find derivation path from the wallet \ + for viewing key {}. Error: {}", + viewing_key, err, + )) + })?; + let path = BIP44Path { + path: path.to_string(), + }; + // Then confirm that the viewing key at this path in the + // hardware wallet matches the viewing key in this pseudo + // spending key + let response = app + .retrieve_keys(&path, NamadaKeys::ViewKey, true) + .await + .map_err(|err| { + error::Error::Other(format!( + "Unable to obtain viewing key from the hardware \ + wallet at path {}. Error: {}", + path.path, err, + )) + })?; + let KeyResponse::ViewKey(response_key) = response else { + return Err(error::Error::Other( + "Unexpected response from Ledger".to_string(), + )); + }; + let xfvk = + ExtendedFullViewingKey::try_from_slice(&response_key.xfvk) + .expect( + "unable to decode extended full viewing key from \ + the hardware wallet", + ); + if ExtendedFullViewingKey::from(viewing_key) != xfvk { + return Err(error::Error::Other(format!( + "Unexpected viewing key response from Ledger: {}", + ExtendedViewingKey::from(xfvk), + ))); + } + // Then obtain the proof authorization key at this path in the + // hardware wallet + let response = app + .retrieve_keys(&path, NamadaKeys::ProofGenerationKey, false) + .await + .map_err(|err| { + error::Error::Other(format!( + "Unable to obtain proof generation key from the \ + hardware wallet for viewing key {}. Error: {}", + viewing_key, err, + )) + })?; + let KeyResponse::ProofGenKey(response_key) = response else { + return Err(error::Error::Other( + "Unexpected response from Ledger".to_string(), + )); + }; + let pgk = ProofGenerationKey::try_from_slice( + &[response_key.ak, response_key.nsk].concat(), + ) + .map_err(|err| { + error::Error::Other(format!( + "Unexpected proof generation key in response from the \ + hardware wallet: {}.", + err, + )) + })?; + // Augment the pseudo spending key + data.source.augment_proof_generation_key(pgk).map_err( + |_| { + error::Error::Other( + "Proof generation key in response from the \ + hardware wallet does not correspond to stored \ + viewing key." + .to_string(), + ) + }, + )?; + // Finally, augment an incorrect spend authorization key just to + // make sure that the Transaction is built. + data.source.augment_spend_authorizing_key_unchecked( + PrivateKey(jubjub::Fr::default()), + ); + shielded_hw_keys.insert(path.path, viewing_key); + } + } + // Get randomness to aid in construction of various descriptors + let mut bparams = StoredBuildParams::default(); + // Number of spend descriptions is the number of transfers + let spend_len = args.data.len(); + // Number of convert description is assumed to be double the number of + // transfers. This is because each spend description might first be + // converted to epoch 0 before going to the intended epoch. + let convert_len = args.data.len() * 2; + // Number of output descriptions is assumed to be double the number of + // transfers. This is because there may be change from each output + // that's destined for the sender. + let output_len = args.data.len() * 2; + for _ in 0..spend_len { + let spend_randomness = app + .get_spend_randomness() + .await + .map_err(|err| error::Error::Other(err.to_string()))?; + bparams.spend_params.push(SpendBuildParams { + rcv: jubjub::Fr::from_bytes(&spend_randomness.rcv).unwrap(), + alpha: jubjub::Fr::from_bytes(&spend_randomness.alpha).unwrap(), + ..SpendBuildParams::default() + }); + } + for _ in 0..convert_len { + let convert_randomness = app + .get_convert_randomness() + .await + .map_err(|err| error::Error::Other(err.to_string()))?; + bparams.convert_params.push(ConvertBuildParams { + rcv: jubjub::Fr::from_bytes(&convert_randomness.rcv).unwrap(), + }); + } + for _ in 0..output_len { + let output_randomness = app + .get_output_randomness() + .await + .map_err(|err| error::Error::Other(err.to_string()))?; + bparams.output_params.push(OutputBuildParams { + rcv: jubjub::Fr::from_bytes(&output_randomness.rcv).unwrap(), + rseed: output_randomness.rcm, + ..OutputBuildParams::default() + }); + } + Box::new(bparams) + } else { + Box::new(RngBuildParams::new(OsRng)) + }; + let (mut tx, signing_data) = + args.clone().build(namada, &mut bparams).await?; let masp_section = tx .sections @@ -854,6 +1051,88 @@ pub async fn submit_shielded_transfer( tx::dump_tx(namada.io(), &args.tx, tx)?; pre_cache_masp_data(namada, &masp_section).await; } else { + // Get the MASP section that is the target of our signing + if let Some(shielded_hash) = signing_data.shielded_hash { + let mut masp_tx = tx + .get_masp_section(&shielded_hash) + .expect("Expected to find the indicated MASP Transaction") + .clone(); + + let masp_builder = tx + .get_masp_builder(&shielded_hash) + .expect("Expected to find the indicated MASP Builder"); + + // Reverse the spend metadata to enable looking up construction + // material + let sapling_inputs = masp_builder.builder.sapling_inputs(); + let mut descriptor_map = vec![0; sapling_inputs.len()]; + for i in 0.. { + if let Some(pos) = masp_builder.metadata.spend_index(i) { + descriptor_map[pos] = i; + } else { + break; + }; + } + // Sign the MASP Transaction using each relevant key in the + // hardware wallet + let mut app = None; + for (path, vk) in shielded_hw_keys { + // Initialize the Ledger app interface if it is uninitialized + let app = app.get_or_insert_with(|| { + NamadaApp::new(WalletTransport::from_arg( + args.tx.device_transport, + )) + }); + // Sign the MASP Transaction using the current viewing key + let path = BIP44Path { + path: path.to_string(), + }; + app.sign_masp_spends(&path, &tx.serialize_to_vec()) + .await + .map_err(|err| error::Error::Other(err.to_string()))?; + // Now prepare a new list of authorizations based on hardware + // wallet responses + let mut authorizations = HashMap::new(); + for (tx_pos, builder_pos) in descriptor_map.iter().enumerate() { + // Read the next spend authorization signature from the + // hardware wallet + let response = app + .get_spend_signature() + .await + .map_err(|err| error::Error::Other(err.to_string()))?; + let signature = redjubjub::Signature::try_from_slice( + &[response.rbar, response.sbar].concat(), + ) + .map_err(|err| { + error::Error::Other(format!( + "Unexpected spend authorization key in response \ + from the hardware wallet: {}.", + err, + )) + })?; + if *sapling_inputs[*builder_pos].key() + == ExtendedFullViewingKey::from(vk) + { + // If this descriptor was produced by the current + // viewing key (which comes from the hardware wallet), + // then use the authorization from the hardware wallet + authorizations.insert(tx_pos, signature); + } + } + // Finally, patch the MASP Transaction with the fetched spend + // authorization signature + masp_tx = (*masp_tx).clone().map_authorization::( + (), + MapSaplingSigAuth(authorizations), + ).freeze().map_err(|err| error::Error::Other(format!( + "Unable to apply hardware walleet sourced authorization \ + signatures to the transaction being constructed: {}.", + err, + )))?; + } + tx.remove_masp_section(&shielded_hash); + tx.add_section(Section::MaspTx(masp_tx)); + } sign(namada, &mut tx, &args.tx, signing_data).await?; let res = namada.submit(tx, &args.tx).await?; pre_cache_masp_data_on_tx_result(namada, &res, &masp_section).await; diff --git a/crates/apps_lib/src/config/genesis/transactions.rs b/crates/apps_lib/src/config/genesis/transactions.rs index 2873488b1d..8649884f9c 100644 --- a/crates/apps_lib/src/config/genesis/transactions.rs +++ b/crates/apps_lib/src/config/genesis/transactions.rs @@ -773,6 +773,7 @@ impl Signed { public_keys: pks.clone(), threshold, fee_payer: genesis_fee_payer_pk(), + shielded_hash: None, }; let mut tx = self.data.tx_to_sign(); diff --git a/crates/benches/native_vps.rs b/crates/benches/native_vps.rs index f2350ca722..6e12b24523 100644 --- a/crates/benches/native_vps.rs +++ b/crates/benches/native_vps.rs @@ -10,6 +10,7 @@ use masp_primitives::sapling::Node; use masp_primitives::transaction::sighash::{signature_hash, SignableInput}; use masp_primitives::transaction::txid::TxIdDigester; use masp_primitives::transaction::TransactionData; +use masp_primitives::zip32::ExtendedSpendingKey; use masp_proofs::group::GroupEncoding; use masp_proofs::sapling::BatchValidator; use namada_apps_lib::address::{self, Address, InternalAddress}; @@ -410,7 +411,9 @@ fn prepare_ibc_tx_and_ctx(bench_name: &str) -> (BenchShieldedCtx, BatchedTx) { shielded_ctx.shell.write().commit_block(); shielded_ctx.generate_shielded_action( Amount::native_whole(10), - TransferSource::ExtendedSpendingKey(albert_spending_key.key), + TransferSource::ExtendedSpendingKey( + ExtendedSpendingKey::from(albert_spending_key.key).into(), + ), defaults::bertha_address().to_string(), ) } @@ -602,12 +605,16 @@ fn setup_storage_for_masp_verification( ), "unshielding" => shielded_ctx.generate_masp_tx( amount, - TransferSource::ExtendedSpendingKey(albert_spending_key.key), + TransferSource::ExtendedSpendingKey( + ExtendedSpendingKey::from(albert_spending_key.key).into(), + ), TransferTarget::Address(defaults::albert_address()), ), "shielded" => shielded_ctx.generate_masp_tx( amount, - TransferSource::ExtendedSpendingKey(albert_spending_key.key), + TransferSource::ExtendedSpendingKey( + ExtendedSpendingKey::from(albert_spending_key.key).into(), + ), TransferTarget::PaymentAddress(bertha_payment_addr), ), _ => panic!("Unexpected bench test"), diff --git a/crates/core/src/masp.rs b/crates/core/src/masp.rs index ea6d915e4d..962f487dfa 100644 --- a/crates/core/src/masp.rs +++ b/crates/core/src/masp.rs @@ -13,6 +13,7 @@ use masp_primitives::transaction::TransparentAddress; pub use masp_primitives::transaction::{ Transaction as MaspTransaction, TxId as TxIdInner, }; +use masp_primitives::zip32::{ExtendedKey, PseudoExtendedKey}; use namada_macros::BorshDeserializer; #[cfg(feature = "migrations")] use namada_migrations::*; @@ -69,7 +70,7 @@ pub struct MaspTxId( serialize_with = "serialize_txid", deserialize_with = "deserialize_txid" )] - TxIdInner, + pub TxIdInner, ); impl From for MaspTxId { @@ -532,12 +533,13 @@ impl<'de> serde::Deserialize<'de> for ExtendedSpendingKey { } /// Represents a source of funds for a transfer +#[allow(clippy::large_enum_variant)] #[derive(Debug, Clone, Hash, Eq, PartialEq)] pub enum TransferSource { /// A transfer coming from a transparent address Address(Address), /// A transfer coming from a shielded address - ExtendedSpendingKey(ExtendedSpendingKey), + ExtendedSpendingKey(PseudoExtendedKey), } impl TransferSource { @@ -552,7 +554,7 @@ impl TransferSource { } /// Get the contained ExtendedSpendingKey contained, if any - pub fn spending_key(&self) -> Option { + pub fn spending_key(&self) -> Option { match self { Self::ExtendedSpendingKey(x) => Some(*x), _ => None, @@ -580,7 +582,9 @@ impl Display for TransferSource { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { Self::Address(x) => x.fmt(f), - Self::ExtendedSpendingKey(x) => x.fmt(f), + Self::ExtendedSpendingKey(x) => { + ExtendedViewingKey::from(x.to_viewing_key()).fmt(f) + } } } } @@ -815,12 +819,10 @@ mod test { let addr = address::testing::established_address_1(); assert_eq!(addr.to_string(), TransferSource::Address(addr).to_string()); - let sk = ExtendedSpendingKey::from( - masp_primitives::zip32::ExtendedSpendingKey::master(&[0_u8]), - ); + let sk = masp_primitives::zip32::ExtendedSpendingKey::master(&[0_u8]); assert_eq!( - sk.to_string(), - TransferSource::ExtendedSpendingKey(sk).to_string() + ExtendedSpendingKey::from(sk).to_string(), + TransferSource::ExtendedSpendingKey(sk.into()).to_string() ); } @@ -832,9 +834,9 @@ mod test { assert_eq!(addr.unwrap(), address::testing::established_address_1()); let addr = - TransferSource::ExtendedSpendingKey(ExtendedSpendingKey::from( - masp_primitives::zip32::ExtendedSpendingKey::master(&[0_u8]), - )) + TransferSource::ExtendedSpendingKey( + masp_primitives::zip32::ExtendedSpendingKey::master(&[0_u8]).into(), + ) .address(); assert!(addr.is_none()); } @@ -850,9 +852,9 @@ mod test { ); let addr = - TransferSource::ExtendedSpendingKey(ExtendedSpendingKey::from( - masp_primitives::zip32::ExtendedSpendingKey::master(&[0_u8]), - )) + TransferSource::ExtendedSpendingKey( + masp_primitives::zip32::ExtendedSpendingKey::master(&[0_u8]).into(), + ) .address(); assert!(addr.is_none()); } @@ -866,10 +868,8 @@ mod test { address::testing::established_address_1() ); - let sk = ExtendedSpendingKey::from( - masp_primitives::zip32::ExtendedSpendingKey::master(&[0_u8]), - ); - let source = TransferSource::ExtendedSpendingKey(sk); + let sk = masp_primitives::zip32::ExtendedSpendingKey::master(&[0_u8]); + let source = TransferSource::ExtendedSpendingKey(sk.into()); assert_eq!(source.effective_address(), MASP); } diff --git a/crates/node/src/bench_utils.rs b/crates/node/src/bench_utils.rs index b59c03e353..ea253938d5 100644 --- a/crates/node/src/bench_utils.rs +++ b/crates/node/src/bench_utils.rs @@ -14,6 +14,7 @@ use std::sync::{Arc, Once, RwLock, RwLockReadGuard, RwLockWriteGuard}; use borsh::{BorshDeserialize, BorshSerialize}; use borsh_ext::BorshSerializeExt; +use masp_primitives::transaction::components::sapling::builder::RngBuildParams; use masp_primitives::transaction::Transaction; use masp_primitives::zip32::ExtendedFullViewingKey; use masp_proofs::prover::LocalTxProver; @@ -1223,6 +1224,7 @@ impl BenchShieldedCtx { vec![masp_transfer_data], None, expiration, + &mut RngBuildParams::new(OsRng), ) .await }) diff --git a/crates/sdk/src/args.rs b/crates/sdk/src/args.rs index c4934750ac..f4cecf68e1 100644 --- a/crates/sdk/src/args.rs +++ b/crates/sdk/src/args.rs @@ -6,6 +6,8 @@ use std::str::FromStr; use std::time::Duration as StdDuration; use either::Either; +use masp_primitives::transaction::components::sapling::builder::BuildParams; +use masp_primitives::zip32::PseudoExtendedKey; use namada_core::address::Address; use namada_core::chain::{BlockHeight, ChainId, Epoch}; use namada_core::collections::HashMap; @@ -122,7 +124,7 @@ impl NamadaTypes for SdkTypes { type MaspIndexerAddress = String; type PaymentAddress = namada_core::masp::PaymentAddress; type PublicKey = namada_core::key::common::PublicKey; - type SpendingKey = namada_core::masp::ExtendedSpendingKey; + type SpendingKey = PseudoExtendedKey; type TendermintAddress = tendermint_rpc::Url; type TransferSource = namada_core::masp::TransferSource; type TransferTarget = namada_core::masp::TransferTarget; @@ -370,8 +372,9 @@ impl TxShieldedTransfer { pub async fn build( &mut self, context: &impl Namada, + bparams: &mut impl BuildParams, ) -> crate::error::Result<(namada_tx::Tx, SigningTxData)> { - tx::build_shielded_transfer(context, self).await + tx::build_shielded_transfer(context, self, bparams).await } } diff --git a/crates/sdk/src/lib.rs b/crates/sdk/src/lib.rs index 65c3e457e6..60d96cc7e1 100644 --- a/crates/sdk/src/lib.rs +++ b/crates/sdk/src/lib.rs @@ -45,6 +45,7 @@ use std::path::PathBuf; use std::str::FromStr; use args::{DeviceTransport, InputAmount, SdkTypes}; +use masp_primitives::zip32::PseudoExtendedKey; use namada_core::address::Address; use namada_core::collections::HashSet; use namada_core::dec::Dec; @@ -173,7 +174,7 @@ pub trait Namada: NamadaIo { fn new_shielded_transfer( &self, data: Vec, - gas_spending_key: Option, + gas_spending_key: Option, disposable_signing_key: bool, ) -> args::TxShieldedTransfer { args::TxShieldedTransfer { @@ -204,9 +205,9 @@ pub trait Namada: NamadaIo { /// arguments fn new_unshielding_transfer( &self, - source: ExtendedSpendingKey, + source: PseudoExtendedKey, data: Vec, - gas_spending_key: Option, + gas_spending_key: Option, disposable_signing_key: bool, ) -> args::TxUnshieldingTransfer { args::TxUnshieldingTransfer { diff --git a/crates/sdk/src/signing.rs b/crates/sdk/src/signing.rs index b0ff3ff119..5768629110 100644 --- a/crates/sdk/src/signing.rs +++ b/crates/sdk/src/signing.rs @@ -73,6 +73,8 @@ pub struct SigningTxData { pub account_public_keys_map: Option, /// The public key of the fee payer pub fee_payer: common::PublicKey, + /// ID of the Transaction needing signing + pub shielded_hash: Option, } impl PartialEq for SigningTxData { @@ -429,6 +431,7 @@ pub async fn aux_signing_data( threshold, account_public_keys_map, fee_payer, + shielded_hash: None, }) } @@ -2419,6 +2422,7 @@ mod test_signing { threshold: 1, account_public_keys_map: Some(Default::default()), fee_payer: public_key_fee.clone(), + shielded_hash: None, }; let Error::Tx(TxSubmitError::MissingSigningKeys(1, 0)) = sign_tx( @@ -2454,6 +2458,7 @@ mod test_signing { threshold: 1, account_public_keys_map: Some(Default::default()), fee_payer: public_key.clone(), + shielded_hash: None, }; sign_tx( &RwLock::new(wallet), diff --git a/crates/sdk/src/tx.rs b/crates/sdk/src/tx.rs index ebb021f066..467b04e7c7 100644 --- a/crates/sdk/src/tx.rs +++ b/crates/sdk/src/tx.rs @@ -10,6 +10,9 @@ use borsh::BorshSerialize; use borsh_ext::BorshSerializeExt; use masp_primitives::asset_type::AssetType; use masp_primitives::transaction::builder::Builder; +use masp_primitives::transaction::components::sapling::builder::{ + BuildParams, RngBuildParams, +}; use masp_primitives::transaction::components::sapling::fees::{ ConvertView, InputView as SaplingInputView, OutputView as SaplingOutputView, }; @@ -17,7 +20,8 @@ use masp_primitives::transaction::components::transparent::fees::{ InputView as TransparentInputView, OutputView as TransparentOutputView, }; use masp_primitives::transaction::components::I128Sum; -use masp_primitives::transaction::Transaction as MaspTransaction; +use masp_primitives::transaction::{builder, Transaction as MaspTransaction}; +use masp_primitives::zip32::PseudoExtendedKey; use namada_account::{InitAccount, UpdateAccount}; use namada_core::address::{Address, IBC, MASP}; use namada_core::arith::checked; @@ -38,9 +42,7 @@ use namada_core::ibc::core::client::types::Height as IbcHeight; use namada_core::ibc::core::host::types::identifiers::{ChannelId, PortId}; use namada_core::ibc::primitives::Timestamp as IbcTimestamp; use namada_core::key::{self, *}; -use namada_core::masp::{ - AssetData, ExtendedSpendingKey, MaspEpoch, TransferSource, TransferTarget, -}; +use namada_core::masp::{AssetData, MaspEpoch, TransferSource, TransferTarget}; use namada_core::storage; use namada_core::time::DateTimeUtc; use namada_governance::cli::onchain::{ @@ -2649,6 +2651,7 @@ pub async fn build_ibc_transfer( masp_transfer_data, masp_fee_data, args.tx.expiration.to_datetime(), + &mut RngBuildParams::new(OsRng), ) .await?; let shielded_tx_epoch = shielded_parts.as_ref().map(|trans| trans.0.epoch); @@ -3050,8 +3053,9 @@ pub async fn build_transparent_transfer( pub async fn build_shielded_transfer( context: &N, args: &mut args::TxShieldedTransfer, + bparams: &mut impl BuildParams, ) -> Result<(Tx, SigningTxData)> { - let signing_data = signing::aux_signing_data( + let mut signing_data = signing::aux_signing_data( context, &args.tx, Some(MASP), @@ -3113,6 +3117,7 @@ pub async fn build_shielded_transfer( transfer_data, masp_fee_data, args.tx.expiration.to_datetime(), + bparams, ) .await? .expect("Shielded transfer must have shielded parts"); @@ -3142,6 +3147,7 @@ pub async fn build_shielded_transfer( }); data.shielded_section_hash = Some(section_hash); + signing_data.shielded_hash = Some(section_hash); tracing::debug!("Transfer data {data:?}"); Ok(()) }; @@ -3166,7 +3172,7 @@ async fn get_masp_fee_payment_amount( args: &args::Tx, fee_amount: DenominatedAmount, fee_payer: &common::PublicKey, - gas_spending_key: Option, + gas_spending_key: Option, ) -> Result> { let fee_payer_address = Address::from(fee_payer); let balance_key = balance_key(&args.fee_token, &fee_payer_address); @@ -3279,6 +3285,7 @@ pub async fn build_shielding_transfer( transfer_data, None, args.tx.expiration.to_datetime(), + &mut RngBuildParams::new(OsRng), ) .await? .expect("Shielding transfer must have shielded parts"); @@ -3400,6 +3407,7 @@ pub async fn build_unshielding_transfer( transfer_data, masp_fee_data, args.tx.expiration.to_datetime(), + &mut RngBuildParams::new(OsRng), ) .await? .expect("Shielding transfer must have shielded parts"); @@ -3452,6 +3460,7 @@ async fn construct_shielded_parts( data: Vec, fee_data: Option, expiration: Option, + bparams: &mut impl BuildParams, ) -> Result)>> { // Precompute asset types to increase chances of success in decoding let token_map = context.wallet().await.get_addresses(); @@ -3464,7 +3473,9 @@ async fn construct_shielded_parts( .await; shielded - .gen_shielded_transfer(context, data, fee_data, expiration) + .gen_shielded_transfer( + context, data, fee_data, expiration, bparams, + ) .await }; @@ -3845,6 +3856,7 @@ pub async fn gen_ibc_shielding_transfer( // Fees are paid from the transparent balance of the relayer None, args.expiration.to_datetime(), + &mut RngBuildParams::new(OsRng), ) .await .map_err(|err| TxSubmitError::MaspError(err.to_string()))? diff --git a/crates/shielded_token/src/masp.rs b/crates/shielded_token/src/masp.rs index 4daacb3337..d1203fe02d 100644 --- a/crates/shielded_token/src/masp.rs +++ b/crates/shielded_token/src/masp.rs @@ -25,7 +25,8 @@ use masp_primitives::transaction::components::sapling::builder::SaplingMetadata; use masp_primitives::transaction::components::{I128Sum, ValueSum}; use masp_primitives::transaction::Transaction; use masp_primitives::zip32::{ - ExtendedFullViewingKey, ExtendedSpendingKey as MaspExtendedSpendingKey, + ExtendedFullViewingKey, ExtendedKey, + ExtendedSpendingKey as MaspExtendedSpendingKey, PseudoExtendedKey, }; use masp_proofs::prover::LocalTxProver; use namada_core::address::Address; @@ -79,7 +80,7 @@ pub struct ShieldedTransfer { #[allow(missing_docs)] #[derive(Debug)] pub struct MaspFeeData { - pub source: Option, + pub source: Option, pub target: Address, pub token: Address, pub amount: token::DenominatedAmount, @@ -202,20 +203,20 @@ pub struct WalletMap; impl masp_primitives::transaction::components::sapling::builder::MapBuilder< P1, - MaspExtendedSpendingKey, + PseudoExtendedKey, (), ExtendedFullViewingKey, > for WalletMap { fn map_params(&self, _s: P1) {} - fn map_key(&self, s: MaspExtendedSpendingKey) -> ExtendedFullViewingKey { - (&s).into() + fn map_key(&self, s: PseudoExtendedKey) -> ExtendedFullViewingKey { + s.to_viewing_key() } } impl - MapBuilder + MapBuilder for WalletMap { fn map_notifier(&self, _s: N1) {} @@ -799,7 +800,7 @@ pub mod testing { mut rng in arb_rng().prop_map(TestCsprng), bparams_rng in arb_rng().prop_map(TestCsprng), prover_rng in arb_rng().prop_map(TestCsprng), - ) -> (MaspExtendedSpendingKey, Diversifier, Note, Node) { + ) -> (PseudoExtendedKey, Diversifier, Note, Node) { let mut spending_key_seed = [0; 32]; rng.fill_bytes(&mut spending_key_seed); let spending_key = MaspExtendedSpendingKey::master(spending_key_seed.as_ref()); @@ -810,7 +811,7 @@ pub mod testing { .to_payment_address(div) .expect("a PaymentAddress"); - let mut builder = Builder::::new( + let mut builder = Builder::::new( NETWORK, // NOTE: this is going to add 20 more blocks to the actual // expiration but there's no other exposed function that we could @@ -844,7 +845,7 @@ pub mod testing { assert_eq!(payment_addr, pa); // Make a path to out new note let node = Node::new(shielded_output.cmu.to_repr()); - (spending_key, div, note, node) + (PseudoExtendedKey::from(spending_key), div, note, node) } } @@ -889,7 +890,7 @@ pub mod testing { ).unwrap(), *value, )).collect::>() - ) -> Vec<(MaspExtendedSpendingKey, Diversifier, Note, Node)> { + ) -> Vec<(PseudoExtendedKey, Diversifier, Note, Node)> { spend_description } } diff --git a/crates/shielded_token/src/masp/shielded_wallet.rs b/crates/shielded_token/src/masp/shielded_wallet.rs index a8b38dec27..724f5e3165 100644 --- a/crates/shielded_token/src/masp/shielded_wallet.rs +++ b/crates/shielded_token/src/masp/shielded_wallet.rs @@ -17,13 +17,13 @@ use masp_primitives::sapling::{ Diversifier, Node, Note, Nullifier, ViewingKey, }; use masp_primitives::transaction::builder::Builder; -use masp_primitives::transaction::components::sapling::builder::RngBuildParams; +use masp_primitives::transaction::components::sapling::builder::BuildParams; use masp_primitives::transaction::components::{ I128Sum, TxOut, U64Sum, ValueSum, }; use masp_primitives::transaction::fees::fixed::FeeRule; use masp_primitives::transaction::{builder, Transaction}; -use masp_primitives::zip32::ExtendedSpendingKey as MaspExtendedSpendingKey; +use masp_primitives::zip32::{ExtendedKey, PseudoExtendedKey}; use namada_core::address::Address; use namada_core::arith::checked; use namada_core::borsh::{BorshDeserialize, BorshSerialize}; @@ -809,7 +809,7 @@ pub trait ShieldedApi: &mut self, context: &impl NamadaIo, spent_notes: &mut SpentNotesTracker, - sk: namada_core::masp::ExtendedSpendingKey, + sk: PseudoExtendedKey, target: ValueSum<(MaspDigitPos, Address), i128>, target_epoch: MaspEpoch, ) -> Result< @@ -820,7 +820,7 @@ pub trait ShieldedApi: ), eyre::Error, > { - let vk = &to_viewing_key(&sk.into()).vk; + let vk = &sk.to_viewing_key().fvk.vk; // TODO: we should try to use the smallest notes possible to fund the // transaction to allow people to fetch less often // Establish connection with which to do exchange rate queries @@ -1019,6 +1019,7 @@ pub trait ShieldedApi: data: Vec, fee_data: Option, expiration: Option, + bparams: &mut impl BuildParams, ) -> Result, TransferErr> { // Determine epoch in which to submit potential shielded transaction let epoch = Self::query_masp_epoch(context.client()) @@ -1088,7 +1089,7 @@ pub trait ShieldedApi: u32::MAX - 20 } }; - let mut builder = Builder::::new( + let mut builder = Builder::::new( NETWORK, // NOTE: this is going to add 20 more blocks to the actual // expiration but there's no other exposed function that we could @@ -1208,7 +1209,7 @@ pub trait ShieldedApi: &prover, &FeeRule::non_standard(U64Sum::zero()), &mut rng, - &mut RngBuildParams::new(OsRng), + bparams, ) .map_err(|error| TransferErr::Build { error })?; @@ -1413,7 +1414,7 @@ pub trait ShieldedApi: async fn add_inputs( &mut self, context: &impl NamadaIo, - builder: &mut Builder, + builder: &mut Builder, source: &TransferSource, token: &Address, amount: &Amount, @@ -1498,8 +1499,8 @@ pub trait ShieldedApi: for (asset_type, value) in change.components() { builder .add_sapling_output( - Some(MaspExtendedSpendingKey::from(sk).expsk.ovk), - MaspExtendedSpendingKey::from(sk).default_address().1, + Some(sk.to_viewing_key().fvk.ovk), + sk.to_viewing_key().default_address().1, *asset_type, *value as u64, MemoBytes::empty(), @@ -1512,12 +1513,7 @@ pub trait ShieldedApi: // Commit the notes found to our transaction for (diversifier, note, merkle_path) in unspent_notes { builder - .add_sapling_spend( - sk.into(), - diversifier, - note, - merkle_path, - ) + .add_sapling_spend(sk, diversifier, note, merkle_path) .map_err(|e| TransferErr::Build { error: builder::Error::SaplingBuild(e), })?; @@ -1579,7 +1575,7 @@ pub trait ShieldedApi: async fn add_outputs( &mut self, context: &impl NamadaIo, - builder: &mut Builder, + builder: &mut Builder, source: Option, target: &TransferTarget, token: Address, @@ -1629,7 +1625,7 @@ pub trait ShieldedApi: let ovk_opt = source.clone().and_then(|source| { source .spending_key() - .map(|x| MaspExtendedSpendingKey::from(x).expsk.ovk) + .map(|x| x.to_viewing_key().fvk.ovk) }); // Make transaction output tied to the current token, // denomination, and epoch. diff --git a/crates/shielded_token/src/validation.rs b/crates/shielded_token/src/validation.rs index 65a970cc85..39d46748f6 100644 --- a/crates/shielded_token/src/validation.rs +++ b/crates/shielded_token/src/validation.rs @@ -16,6 +16,7 @@ use masp_primitives::transaction::txid::TxIdDigester; use masp_primitives::transaction::{ Authorization, Authorized, Transaction, TransactionData, Unauthorized, }; +use masp_primitives::zip32::ExtendedSpendingKey; use masp_proofs::bellman::groth16::VerifyingKey; use masp_proofs::sapling::BatchValidator; use namada_gas::Gas; @@ -56,7 +57,8 @@ pub struct PartialAuthorized; impl Authorization for PartialAuthorized { type SaplingAuth = ::SaplingAuth; - type TransparentAuth = ::TransparentAuth; + type TransparentAuth = + as Authorization>::TransparentAuth; } /// MASP verifying keys diff --git a/crates/tests/src/integration/masp.rs b/crates/tests/src/integration/masp.rs index c447c0ba24..e75a3ea4a6 100644 --- a/crates/tests/src/integration/masp.rs +++ b/crates/tests/src/integration/masp.rs @@ -8,7 +8,7 @@ use namada_apps_lib::wallet::defaults::{ }; use namada_core::address::Address; use namada_core::dec::Dec; -use namada_core::masp::TokenMap; +use namada_core::masp::{MaspTxId, TokenMap}; use namada_node::shell::testing::client::run; use namada_node::shell::testing::node::NodeResults; use namada_node::shell::testing::utils::{Bin, CapturedOutput}; @@ -19,7 +19,7 @@ use namada_sdk::state::{StorageRead, StorageWrite}; use namada_sdk::time::DateTimeUtc; use namada_sdk::token::storage_key::masp_token_map_key; use namada_sdk::token::{self, Amount, DenominatedAmount}; -use namada_sdk::tx::Tx; +use namada_sdk::tx::{Section, Tx}; use namada_sdk::{tx, DEFAULT_GAS_LIMIT}; use test_log::test; @@ -5176,6 +5176,7 @@ fn identical_output_descriptions() -> Result<()> { threshold: 1, account_public_keys_map: None, fee_payer: albert_keypair().to_public(), + shielded_hash: None, }; let (mut batched_tx, _signing_data) = namada_sdk::tx::build_batch(vec![ @@ -5368,6 +5369,16 @@ fn identical_output_descriptions() -> Result<()> { Ok(()) } +// Extract the shielded section hash from the transaction +fn get_shielded_hash(tx: &namada_sdk::tx::Tx) -> Option { + for section in &tx.sections { + if let Section::MaspTx(masp) = section { + return Some(MaspTxId::from(masp.txid())); + } + } + None +} + // Test MASP batched txs where one is failing and one is successful and check // that both the protocol and the shielded sync command behave correctly. Since // the batches are not atomic check that the valid transactions get committed @@ -5461,6 +5472,7 @@ fn masp_batch() -> Result<()> { threshold: 1, account_public_keys_map: None, fee_payer: albert_keypair().to_public(), + shielded_hash: None, }; let mut txs = vec![]; @@ -5472,8 +5484,14 @@ fn masp_batch() -> Result<()> { for (tx0, tx1) in [(tx0.clone(), tx1.clone()), (tx1, tx0)] { let (mut batched_tx, _signing_data) = namada_sdk::tx::build_batch(vec![ - (tx0, signing_data.clone()), - (tx1, signing_data.clone()), + (tx0.clone(), SigningTxData { + shielded_hash: get_shielded_hash(&tx0), + ..signing_data.clone() + }), + (tx1.clone(), SigningTxData { + shielded_hash: get_shielded_hash(&tx1), + ..signing_data.clone() + }), ]) .unwrap(); batched_tx.header.atomic = false; @@ -5695,6 +5713,7 @@ fn masp_atomic_batch() -> Result<()> { threshold: 1, account_public_keys_map: None, fee_payer: albert_keypair().to_public(), + shielded_hash: None, }; let mut txs = vec![]; @@ -5706,8 +5725,14 @@ fn masp_atomic_batch() -> Result<()> { for (tx0, tx1) in [(tx0.clone(), tx1.clone()), (tx1, tx0)] { let (mut batched_tx, _signing_data) = namada_sdk::tx::build_batch(vec![ - (tx0, signing_data.clone()), - (tx1, signing_data.clone()), + (tx0.clone(), SigningTxData { + shielded_hash: get_shielded_hash(&tx0), + ..signing_data.clone() + }), + (tx1.clone(), SigningTxData { + shielded_hash: get_shielded_hash(&tx1), + ..signing_data.clone() + }), ]) .unwrap(); batched_tx.header.atomic = true; diff --git a/crates/token/src/lib.rs b/crates/token/src/lib.rs index 17b5fdc0a2..057e6895a0 100644 --- a/crates/token/src/lib.rs +++ b/crates/token/src/lib.rs @@ -336,6 +336,7 @@ pub mod testing { }; use masp_primitives::transaction::components::{TxOut, U64Sum}; use masp_primitives::transaction::fees::fixed::FeeRule; + use masp_primitives::zip32::PseudoExtendedKey; use namada_core::address::testing::{ arb_established_address, arb_non_internal_address, }; @@ -416,7 +417,7 @@ pub mod testing { assets in Just(assets), ) -> ( Transfer, - Builder::, + Builder::, HashMap, ) { // Enable assets to be more easily decoded diff --git a/crates/tx/src/types.rs b/crates/tx/src/types.rs index e800caa552..0d83576fec 100644 --- a/crates/tx/src/types.rs +++ b/crates/tx/src/types.rs @@ -259,6 +259,30 @@ impl Tx { None } + /// Remove the transaction section with the given hash + pub fn remove_masp_section(&mut self, hash: &MaspTxId) { + self.sections.retain(|section| { + if let Section::MaspTx(masp) = section { + if MaspTxId::from(masp.txid()) == *hash { + return false; + } + } + true + }); + } + + /// Get the MASP builder section with the given hash + pub fn get_masp_builder(&self, hash: &MaspTxId) -> Option<&MaspBuilder> { + for section in &self.sections { + if let Section::MaspBuilder(builder) = section { + if builder.target == *hash { + return Some(builder); + } + } + } + None + } + /// Set the last transaction memo hash stored in the header pub fn set_memo_sechash(&mut self, hash: namada_core::hash::Hash) { let item = match self.header.batch.pop() { diff --git a/crates/wallet/src/lib.rs b/crates/wallet/src/lib.rs index 5e5e61a7c2..f78dd75ca7 100644 --- a/crates/wallet/src/lib.rs +++ b/crates/wallet/src/lib.rs @@ -585,8 +585,21 @@ impl Wallet { (mnemonic, passphrase) }; let seed = Seed::new(&mnemonic, &passphrase); - let spend_key = - derive_hd_spending_key(seed.as_bytes(), derivation_path.clone()); + // Path to obtain the ZIP32 seed + let zip32_seed_path = + DerivationPath::default_for_transparent_scheme(SchemeType::Ed25519); + // Obtain the ZIP32 seed using SLIP10 + let seed = derive_hd_secret_key( + SchemeType::Ed25519, + seed.as_bytes(), + zip32_seed_path, + ) + .try_to_sk::() + .expect("Expected Ed25519 key") + .0 + .to_bytes(); + // Now ZIP32 derive the extended spending key from the new seed + let spend_key = derive_hd_spending_key(&seed, derivation_path.clone()); self.insert_spending_key( alias, @@ -599,6 +612,16 @@ impl Wallet { .map(|alias| (alias, spend_key)) } + /// Find a derivation path by viewing key + pub fn find_path_by_viewing_key( + &self, + vk: &ExtendedViewingKey, + ) -> Result { + self.store + .find_path_by_viewing_key(vk) + .ok_or_else(|| FindKeyError::KeyNotFound(vk.to_string())) + } + /// Restore a keypair from the user mnemonic code (read from stdin) using /// a given BIP44 derivation path and derive an implicit address from its /// public part and insert them into the store with the provided alias, @@ -1137,12 +1160,14 @@ impl Wallet { view_key: ExtendedViewingKey, birthday: Option, force_alias: bool, + path: Option, ) -> Option { self.store .insert_viewing_key::( alias.into(), view_key, birthday, + path, force_alias, ) .map(Into::into) diff --git a/crates/wallet/src/store.rs b/crates/wallet/src/store.rs index 287bd7822d..8237abbab5 100644 --- a/crates/wallet/src/store.rs +++ b/crates/wallet/src/store.rs @@ -194,6 +194,19 @@ impl Store { self.derivation_paths.get(self.pkhs.get(pkh)?).cloned() } + /// Find a derivation path by viewing key + pub fn find_path_by_viewing_key( + &self, + viewing_key: &ExtendedViewingKey, + ) -> Option { + for (alias, vk) in &self.view_keys { + if *viewing_key == vk.key { + return self.derivation_paths.get(alias).cloned(); + } + } + None + } + /// Find the public key by a public key hash. pub fn find_public_key_by_pkh( &self, @@ -418,6 +431,7 @@ impl Store { alias: Alias, viewkey: ExtendedViewingKey, birthday: Option, + path: Option, force: bool, ) -> Option { // abort if the alias is reserved @@ -435,7 +449,7 @@ impl Store { ConfirmationResponse::Replace => {} ConfirmationResponse::Reselect(new_alias) => { return self.insert_viewing_key::( - new_alias, viewkey, birthday, false, + new_alias, viewkey, birthday, path, false, ); } ConfirmationResponse::Skip => return None, @@ -444,6 +458,7 @@ impl Store { self.remove_alias(&alias); self.view_keys .insert(alias.clone(), DatedKeypair::new(viewkey, birthday)); + path.map(|p| self.derivation_paths.insert(alias.clone(), p)); Some(alias) } diff --git a/wasm/Cargo.lock b/wasm/Cargo.lock index a31ac28ac3..79caad5218 100644 --- a/wasm/Cargo.lock +++ b/wasm/Cargo.lock @@ -3449,7 +3449,7 @@ dependencies = [ [[package]] name = "masp_note_encryption" version = "1.0.0" -source = "git+https://github.com/anoma/masp?rev=12ed8b060b295c06502a2ff8468e4a941cb7cca4#12ed8b060b295c06502a2ff8468e4a941cb7cca4" +source = "git+https://github.com/anoma/masp?rev=a35f73be69b21ee62cd4940f37855161cbed2a56#a35f73be69b21ee62cd4940f37855161cbed2a56" dependencies = [ "borsh", "chacha20", @@ -3462,7 +3462,7 @@ dependencies = [ [[package]] name = "masp_primitives" version = "1.0.0" -source = "git+https://github.com/anoma/masp?rev=12ed8b060b295c06502a2ff8468e4a941cb7cca4#12ed8b060b295c06502a2ff8468e4a941cb7cca4" +source = "git+https://github.com/anoma/masp?rev=a35f73be69b21ee62cd4940f37855161cbed2a56#a35f73be69b21ee62cd4940f37855161cbed2a56" dependencies = [ "aes", "bip0039", @@ -3494,7 +3494,7 @@ dependencies = [ [[package]] name = "masp_proofs" version = "1.0.0" -source = "git+https://github.com/anoma/masp?rev=12ed8b060b295c06502a2ff8468e4a941cb7cca4#12ed8b060b295c06502a2ff8468e4a941cb7cca4" +source = "git+https://github.com/anoma/masp?rev=a35f73be69b21ee62cd4940f37855161cbed2a56#a35f73be69b21ee62cd4940f37855161cbed2a56" dependencies = [ "bellman", "blake2b_simd", diff --git a/wasm_for_tests/Cargo.lock b/wasm_for_tests/Cargo.lock index f9acde8215..ccea7985d4 100644 --- a/wasm_for_tests/Cargo.lock +++ b/wasm_for_tests/Cargo.lock @@ -1863,7 +1863,7 @@ checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" [[package]] name = "masp_note_encryption" version = "1.0.0" -source = "git+https://github.com/anoma/masp?rev=12ed8b060b295c06502a2ff8468e4a941cb7cca4#12ed8b060b295c06502a2ff8468e4a941cb7cca4" +source = "git+https://github.com/anoma/masp?rev=a35f73be69b21ee62cd4940f37855161cbed2a56#a35f73be69b21ee62cd4940f37855161cbed2a56" dependencies = [ "borsh", "chacha20", @@ -1876,7 +1876,7 @@ dependencies = [ [[package]] name = "masp_primitives" version = "1.0.0" -source = "git+https://github.com/anoma/masp?rev=12ed8b060b295c06502a2ff8468e4a941cb7cca4#12ed8b060b295c06502a2ff8468e4a941cb7cca4" +source = "git+https://github.com/anoma/masp?rev=a35f73be69b21ee62cd4940f37855161cbed2a56#a35f73be69b21ee62cd4940f37855161cbed2a56" dependencies = [ "aes", "bip0039", @@ -1907,7 +1907,7 @@ dependencies = [ [[package]] name = "masp_proofs" version = "1.0.0" -source = "git+https://github.com/anoma/masp?rev=12ed8b060b295c06502a2ff8468e4a941cb7cca4#12ed8b060b295c06502a2ff8468e4a941cb7cca4" +source = "git+https://github.com/anoma/masp?rev=a35f73be69b21ee62cd4940f37855161cbed2a56#a35f73be69b21ee62cd4940f37855161cbed2a56" dependencies = [ "bellman", "blake2b_simd", From 5fd0281d25582d208acf22f85ff39acf8345ea06 Mon Sep 17 00:00:00 2001 From: Murisi Tarusenga Date: Mon, 23 Sep 2024 15:00:46 +0200 Subject: [PATCH 02/12] Factored out the logic for MASP hardware wallet signing. --- crates/apps_lib/src/client/tx.rs | 259 ++++++++++++++++++------------- 1 file changed, 154 insertions(+), 105 deletions(-) diff --git a/crates/apps_lib/src/client/tx.rs b/crates/apps_lib/src/client/tx.rs index 38bc19fc98..206353cc21 100644 --- a/crates/apps_lib/src/client/tx.rs +++ b/crates/apps_lib/src/client/tx.rs @@ -864,33 +864,23 @@ impl sapling::MapAuth } } -pub async fn submit_shielded_transfer( +// Identify the viewing keys in the given transaction for which we do not +// possess spending keys in the software wallet, and augment them with a proof +// generation key from the hardware wallet. Returns a mapping from viewing keys +// to corresponding ZIP 32 paths in the hardware wallet. This function errors +// out if any ZIP 32 path that it handles maps to a different viewing key than +// it does on the software client. +async fn augment_masp_hardware_keys( namada: &impl Namada, - mut args: args::TxShieldedTransfer, -) -> Result<(), error::Error> { - display_line!( - namada.io(), - "{}: {}\n", - "WARNING".bold().underline().yellow(), - "Some information might be leaked if your shielded wallet is not up \ - to date, make sure to run `namadac shielded-sync` before running \ - this command.", - ); - + args: &mut args::TxShieldedTransfer, +) -> Result, error::Error> { // Records the shielded keys that are on the hardware wallet let mut shielded_hw_keys = HashMap::new(); // Construct the build parameters that parameterized the Transaction // authorizations - let mut bparams: Box = if args.tx.use_device { + if args.tx.use_device { let transport = WalletTransport::from_arg(args.tx.device_transport); let app = NamadaApp::new(transport); - // Clear hardware wallet randomness buffers - app.clean_randomness_buffers().await.map_err(|err| { - error::Error::Other(format!( - "Unable to clear randomness buffer. Error: {}", - err, - )) - })?; let wallet = namada.wallet().await; // Augment the pseudo spending key with a proof authorization key for data in &mut args.data { @@ -988,6 +978,29 @@ pub async fn submit_shielded_transfer( shielded_hw_keys.insert(path.path, viewing_key); } } + Ok(shielded_hw_keys) + } else { + Ok(HashMap::new()) + } +} + +// If the hardware wallet is beig used, use it to generate the random build +// parameters for the spend, convert, and output descriptions. +async fn generate_masp_build_params( + args: &args::TxShieldedTransfer, +) -> Result, error::Error> { + // Construct the build parameters that parameterized the Transaction + // authorizations + if args.tx.use_device { + let transport = WalletTransport::from_arg(args.tx.device_transport); + let app = NamadaApp::new(transport); + // Clear hardware wallet randomness buffers + app.clean_randomness_buffers().await.map_err(|err| { + error::Error::Other(format!( + "Unable to clear randomness buffer. Error: {}", + err, + )) + })?; // Get randomness to aid in construction of various descriptors let mut bparams = StoredBuildParams::default(); // Number of spend descriptions is the number of transfers @@ -1031,10 +1044,127 @@ pub async fn submit_shielded_transfer( ..OutputBuildParams::default() }); } - Box::new(bparams) + Ok(Box::new(bparams)) } else { - Box::new(RngBuildParams::new(OsRng)) - }; + Ok(Box::new(RngBuildParams::new(OsRng))) + } +} + +// Sign the given transaction's MASP component using signatures produced by the +// hardware wallet. This function takes the list of spending keys that are +// hosted on the hardware wallet. +async fn masp_sign( + tx: &mut Tx, + args: &args::Tx, + signing_data: &SigningTxData, + shielded_hw_keys: HashMap, +) -> Result<(), error::Error> { + // Get the MASP section that is the target of our signing + if let Some(shielded_hash) = signing_data.shielded_hash { + let mut masp_tx = tx + .get_masp_section(&shielded_hash) + .expect("Expected to find the indicated MASP Transaction") + .clone(); + + let masp_builder = tx + .get_masp_builder(&shielded_hash) + .expect("Expected to find the indicated MASP Builder"); + + // Reverse the spend metadata to enable looking up construction + // material + let sapling_inputs = masp_builder.builder.sapling_inputs(); + let mut descriptor_map = vec![0; sapling_inputs.len()]; + for i in 0.. { + if let Some(pos) = masp_builder.metadata.spend_index(i) { + descriptor_map[pos] = i; + } else { + break; + }; + } + // Sign the MASP Transaction using each relevant key in the + // hardware wallet + let mut app = None; + for (path, vk) in shielded_hw_keys { + // Initialize the Ledger app interface if it is uninitialized + let app = app.get_or_insert_with(|| { + NamadaApp::new(WalletTransport::from_arg(args.device_transport)) + }); + // Sign the MASP Transaction using the current viewing key + let path = BIP44Path { + path: path.to_string(), + }; + app.sign_masp_spends(&path, &tx.serialize_to_vec()) + .await + .map_err(|err| error::Error::Other(err.to_string()))?; + // Now prepare a new list of authorizations based on hardware + // wallet responses + let mut authorizations = HashMap::new(); + for (tx_pos, builder_pos) in descriptor_map.iter().enumerate() { + // Read the next spend authorization signature from the + // hardware wallet + let response = app + .get_spend_signature() + .await + .map_err(|err| error::Error::Other(err.to_string()))?; + let signature = redjubjub::Signature::try_from_slice( + &[response.rbar, response.sbar].concat(), + ) + .map_err(|err| { + error::Error::Other(format!( + "Unexpected spend authorization key in response from \ + the hardware wallet: {}.", + err, + )) + })?; + if *sapling_inputs[*builder_pos].key() + == ExtendedFullViewingKey::from(vk) + { + // If this descriptor was produced by the current + // viewing key (which comes from the hardware wallet), + // then use the authorization from the hardware wallet + authorizations.insert(tx_pos, signature); + } + } + // Finally, patch the MASP Transaction with the fetched spend + // authorization signature + masp_tx = (*masp_tx) + .clone() + .map_authorization::( + (), + MapSaplingSigAuth(authorizations), + ) + .freeze() + .map_err(|err| { + error::Error::Other(format!( + "Unable to apply hardware walleet sourced \ + authorization signatures to the transaction being \ + constructed: {}.", + err, + )) + })?; + } + tx.remove_masp_section(&shielded_hash); + tx.add_section(Section::MaspTx(masp_tx)); + } + Ok(()) +} + +pub async fn submit_shielded_transfer( + namada: &impl Namada, + mut args: args::TxShieldedTransfer, +) -> Result<(), error::Error> { + display_line!( + namada.io(), + "{}: {}\n", + "WARNING".bold().underline().yellow(), + "Some information might be leaked if your shielded wallet is not up \ + to date, make sure to run `namadac shielded-sync` before running \ + this command.", + ); + + let shielded_hw_keys = + augment_masp_hardware_keys(namada, &mut args).await?; + let mut bparams = generate_masp_build_params(&args).await?; let (mut tx, signing_data) = args.clone().build(namada, &mut bparams).await?; @@ -1051,88 +1181,7 @@ pub async fn submit_shielded_transfer( tx::dump_tx(namada.io(), &args.tx, tx)?; pre_cache_masp_data(namada, &masp_section).await; } else { - // Get the MASP section that is the target of our signing - if let Some(shielded_hash) = signing_data.shielded_hash { - let mut masp_tx = tx - .get_masp_section(&shielded_hash) - .expect("Expected to find the indicated MASP Transaction") - .clone(); - - let masp_builder = tx - .get_masp_builder(&shielded_hash) - .expect("Expected to find the indicated MASP Builder"); - - // Reverse the spend metadata to enable looking up construction - // material - let sapling_inputs = masp_builder.builder.sapling_inputs(); - let mut descriptor_map = vec![0; sapling_inputs.len()]; - for i in 0.. { - if let Some(pos) = masp_builder.metadata.spend_index(i) { - descriptor_map[pos] = i; - } else { - break; - }; - } - // Sign the MASP Transaction using each relevant key in the - // hardware wallet - let mut app = None; - for (path, vk) in shielded_hw_keys { - // Initialize the Ledger app interface if it is uninitialized - let app = app.get_or_insert_with(|| { - NamadaApp::new(WalletTransport::from_arg( - args.tx.device_transport, - )) - }); - // Sign the MASP Transaction using the current viewing key - let path = BIP44Path { - path: path.to_string(), - }; - app.sign_masp_spends(&path, &tx.serialize_to_vec()) - .await - .map_err(|err| error::Error::Other(err.to_string()))?; - // Now prepare a new list of authorizations based on hardware - // wallet responses - let mut authorizations = HashMap::new(); - for (tx_pos, builder_pos) in descriptor_map.iter().enumerate() { - // Read the next spend authorization signature from the - // hardware wallet - let response = app - .get_spend_signature() - .await - .map_err(|err| error::Error::Other(err.to_string()))?; - let signature = redjubjub::Signature::try_from_slice( - &[response.rbar, response.sbar].concat(), - ) - .map_err(|err| { - error::Error::Other(format!( - "Unexpected spend authorization key in response \ - from the hardware wallet: {}.", - err, - )) - })?; - if *sapling_inputs[*builder_pos].key() - == ExtendedFullViewingKey::from(vk) - { - // If this descriptor was produced by the current - // viewing key (which comes from the hardware wallet), - // then use the authorization from the hardware wallet - authorizations.insert(tx_pos, signature); - } - } - // Finally, patch the MASP Transaction with the fetched spend - // authorization signature - masp_tx = (*masp_tx).clone().map_authorization::( - (), - MapSaplingSigAuth(authorizations), - ).freeze().map_err(|err| error::Error::Other(format!( - "Unable to apply hardware walleet sourced authorization \ - signatures to the transaction being constructed: {}.", - err, - )))?; - } - tx.remove_masp_section(&shielded_hash); - tx.add_section(Section::MaspTx(masp_tx)); - } + masp_sign(&mut tx, &args.tx, &signing_data, shielded_hw_keys).await?; sign(namada, &mut tx, &args.tx, signing_data).await?; let res = namada.submit(tx, &args.tx).await?; pre_cache_masp_data_on_tx_result(namada, &res, &masp_section).await; From b78d8bff4cd49eae935bd586fbf3c07c7c2090fb Mon Sep 17 00:00:00 2001 From: Murisi Tarusenga Date: Tue, 24 Sep 2024 14:55:15 +0200 Subject: [PATCH 03/12] Expand MASP hardware wallet support to other transaction types. --- Cargo.lock | 6 +- Cargo.toml | 4 +- crates/apps_lib/src/client/tx.rs | 139 +++++++++++++++++++++---------- crates/core/src/masp.rs | 8 ++ crates/sdk/src/args.rs | 9 +- crates/sdk/src/tx.rs | 18 ++-- wasm/Cargo.lock | 6 +- wasm_for_tests/Cargo.lock | 6 +- 8 files changed, 134 insertions(+), 62 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1365fc2c46..7c23c99f23 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4494,7 +4494,7 @@ dependencies = [ [[package]] name = "masp_note_encryption" version = "1.0.0" -source = "git+https://github.com/anoma/masp?rev=a35f73be69b21ee62cd4940f37855161cbed2a56#a35f73be69b21ee62cd4940f37855161cbed2a56" +source = "git+https://github.com/anoma/masp?rev=2914e6ff9a922bae8f1cb63a79d796a69af3d8aa#2914e6ff9a922bae8f1cb63a79d796a69af3d8aa" dependencies = [ "arbitrary", "borsh", @@ -4508,7 +4508,7 @@ dependencies = [ [[package]] name = "masp_primitives" version = "1.0.0" -source = "git+https://github.com/anoma/masp?rev=a35f73be69b21ee62cd4940f37855161cbed2a56#a35f73be69b21ee62cd4940f37855161cbed2a56" +source = "git+https://github.com/anoma/masp?rev=2914e6ff9a922bae8f1cb63a79d796a69af3d8aa#2914e6ff9a922bae8f1cb63a79d796a69af3d8aa" dependencies = [ "aes", "arbitrary", @@ -4541,7 +4541,7 @@ dependencies = [ [[package]] name = "masp_proofs" version = "1.0.0" -source = "git+https://github.com/anoma/masp?rev=a35f73be69b21ee62cd4940f37855161cbed2a56#a35f73be69b21ee62cd4940f37855161cbed2a56" +source = "git+https://github.com/anoma/masp?rev=2914e6ff9a922bae8f1cb63a79d796a69af3d8aa#2914e6ff9a922bae8f1cb63a79d796a69af3d8aa" dependencies = [ "bellman", "blake2b_simd", diff --git a/Cargo.toml b/Cargo.toml index ed4916fdbb..e6d0b634ca 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -141,8 +141,8 @@ libc = "0.2.97" libloading = "0.7.2" linkme = "0.3.24" # branch = "tomas/arbitrary" -masp_primitives = { git = "https://github.com/anoma/masp", rev = "a35f73be69b21ee62cd4940f37855161cbed2a56" } -masp_proofs = { git = "https://github.com/anoma/masp", rev = "a35f73be69b21ee62cd4940f37855161cbed2a56", default-features = false, features = ["local-prover"] } +masp_primitives = { git = "https://github.com/anoma/masp", rev = "2914e6ff9a922bae8f1cb63a79d796a69af3d8aa" } +masp_proofs = { git = "https://github.com/anoma/masp", rev = "2914e6ff9a922bae8f1cb63a79d796a69af3d8aa", default-features = false, features = ["local-prover"] } num256 = "0.3.5" num_cpus = "1.13.0" num-derive = "0.4" diff --git a/crates/apps_lib/src/client/tx.rs b/crates/apps_lib/src/client/tx.rs index 206353cc21..97052a441a 100644 --- a/crates/apps_lib/src/client/tx.rs +++ b/crates/apps_lib/src/client/tx.rs @@ -14,7 +14,9 @@ use masp_primitives::transaction::components::sapling::builder::{ SpendBuildParams, StoredBuildParams, }; use masp_primitives::transaction::components::sapling::fees::InputView; -use masp_primitives::zip32::{ExtendedFullViewingKey, ExtendedKey}; +use masp_primitives::zip32::{ + ExtendedFullViewingKey, ExtendedKey, PseudoExtendedKey, +}; use namada_sdk::address::{Address, ImplicitAddress}; use namada_sdk::args::TxBecomeValidator; use namada_sdk::collections::{HashMap, HashSet}; @@ -45,6 +47,22 @@ use crate::wallet::{ gen_validator_keys, read_and_confirm_encryption_password, WalletTransport, }; +// Maximum number of spend description randomness parameters that can be +// generated on the hardware wallet. It is hard to compute the exact required +// number because a given MASP source could be distributed amongst several +// notes. +const MAX_HW_SPEND: usize = 10; +// Maximum number of convert description randomness parameters that can be +// generated on the hardware wallet. It is hard to compute the exact required +// number because the number of conversions that are used depends on the +// protocol's current state. +const MAX_HW_CONVERT: usize = 10; +// Maximum number of output description randomness parameters that can be +// generated on the hardware wallet. It is hard to compute the exact required +// number because the number of outputs depends on the number of dummy outputs +// introduced. +const MAX_HW_OUTPUT: usize = 10; + /// Wrapper around `signing::aux_signing_data` that stores the optional /// disposable address to the wallet pub async fn aux_signing_data( @@ -872,24 +890,25 @@ impl sapling::MapAuth // it does on the software client. async fn augment_masp_hardware_keys( namada: &impl Namada, - args: &mut args::TxShieldedTransfer, + args: &args::Tx, + sources: impl Iterator, ) -> Result, error::Error> { // Records the shielded keys that are on the hardware wallet let mut shielded_hw_keys = HashMap::new(); // Construct the build parameters that parameterized the Transaction // authorizations - if args.tx.use_device { - let transport = WalletTransport::from_arg(args.tx.device_transport); + if args.use_device { + let transport = WalletTransport::from_arg(args.device_transport); let app = NamadaApp::new(transport); let wallet = namada.wallet().await; // Augment the pseudo spending key with a proof authorization key - for data in &mut args.data { + for source in sources { // Only attempt an augmentation if proof authorization is not there - if data.source.to_spending_key().is_none() { + if source.to_spending_key().is_none() { // First find the derivation path corresponding to this viewing // key let viewing_key = - ExtendedViewingKey::from(data.source.to_viewing_key()); + ExtendedViewingKey::from(source.to_viewing_key()); let path = wallet .find_path_by_viewing_key(&viewing_key) .map_err(|err| { @@ -960,21 +979,18 @@ async fn augment_masp_hardware_keys( )) })?; // Augment the pseudo spending key - data.source.augment_proof_generation_key(pgk).map_err( - |_| { - error::Error::Other( - "Proof generation key in response from the \ - hardware wallet does not correspond to stored \ - viewing key." - .to_string(), - ) - }, - )?; + source.augment_proof_generation_key(pgk).map_err(|_| { + error::Error::Other( + "Proof generation key in response from the hardware \ + wallet does not correspond to stored viewing key." + .to_string(), + ) + })?; // Finally, augment an incorrect spend authorization key just to // make sure that the Transaction is built. - data.source.augment_spend_authorizing_key_unchecked( - PrivateKey(jubjub::Fr::default()), - ); + source.augment_spend_authorizing_key_unchecked(PrivateKey( + jubjub::Fr::default(), + )); shielded_hw_keys.insert(path.path, viewing_key); } } @@ -987,12 +1003,15 @@ async fn augment_masp_hardware_keys( // If the hardware wallet is beig used, use it to generate the random build // parameters for the spend, convert, and output descriptions. async fn generate_masp_build_params( - args: &args::TxShieldedTransfer, + spend_len: usize, + convert_len: usize, + output_len: usize, + args: &args::Tx, ) -> Result, error::Error> { // Construct the build parameters that parameterized the Transaction // authorizations - if args.tx.use_device { - let transport = WalletTransport::from_arg(args.tx.device_transport); + if args.use_device { + let transport = WalletTransport::from_arg(args.device_transport); let app = NamadaApp::new(transport); // Clear hardware wallet randomness buffers app.clean_randomness_buffers().await.map_err(|err| { @@ -1003,16 +1022,6 @@ async fn generate_masp_build_params( })?; // Get randomness to aid in construction of various descriptors let mut bparams = StoredBuildParams::default(); - // Number of spend descriptions is the number of transfers - let spend_len = args.data.len(); - // Number of convert description is assumed to be double the number of - // transfers. This is because each spend description might first be - // converted to epoch 0 before going to the intended epoch. - let convert_len = args.data.len() * 2; - // Number of output descriptions is assumed to be double the number of - // transfers. This is because there may be change from each output - // that's destined for the sender. - let output_len = args.data.len() * 2; for _ in 0..spend_len { let spend_randomness = app .get_spend_randomness() @@ -1021,7 +1030,6 @@ async fn generate_masp_build_params( bparams.spend_params.push(SpendBuildParams { rcv: jubjub::Fr::from_bytes(&spend_randomness.rcv).unwrap(), alpha: jubjub::Fr::from_bytes(&spend_randomness.alpha).unwrap(), - ..SpendBuildParams::default() }); } for _ in 0..convert_len { @@ -1162,9 +1170,20 @@ pub async fn submit_shielded_transfer( this command.", ); + let sources = args + .data + .iter_mut() + .map(|x| &mut x.source) + .chain(args.gas_spending_key.iter_mut()); let shielded_hw_keys = - augment_masp_hardware_keys(namada, &mut args).await?; - let mut bparams = generate_masp_build_params(&args).await?; + augment_masp_hardware_keys(namada, &args.tx, sources).await?; + let mut bparams = generate_masp_build_params( + MAX_HW_SPEND, + MAX_HW_CONVERT, + MAX_HW_OUTPUT, + &args.tx, + ) + .await?; let (mut tx, signing_data) = args.clone().build(namada, &mut bparams).await?; @@ -1195,7 +1214,15 @@ pub async fn submit_shielding_transfer( ) -> Result<(), error::Error> { // Repeat once if the tx fails on a crossover of an epoch for _ in 0..2 { - let (tx, signing_data, tx_epoch) = args.clone().build(namada).await?; + let mut bparams = generate_masp_build_params( + MAX_HW_SPEND, + MAX_HW_CONVERT, + MAX_HW_OUTPUT, + &args.tx, + ) + .await?; + let (tx, signing_data, tx_epoch) = + args.clone().build(namada, &mut bparams).await?; if args.tx.dump_tx || args.tx.dump_wrapper_tx { tx::dump_tx(namada.io(), &args.tx, tx)?; @@ -1247,7 +1274,7 @@ pub async fn submit_shielding_transfer( pub async fn submit_unshielding_transfer( namada: &impl Namada, - args: args::TxUnshieldingTransfer, + mut args: args::TxUnshieldingTransfer, ) -> Result<(), error::Error> { display_line!( namada.io(), @@ -1257,8 +1284,20 @@ pub async fn submit_unshielding_transfer( to date, make sure to run `namadac shielded-sync` before running \ this command.", ); - - let (mut tx, signing_data) = args.clone().build(namada).await?; + + let sources = std::iter::once(&mut args.source) + .chain(args.gas_spending_key.iter_mut()); + let shielded_hw_keys = + augment_masp_hardware_keys(namada, &args.tx, sources).await?; + let mut bparams = generate_masp_build_params( + MAX_HW_SPEND, + MAX_HW_CONVERT, + MAX_HW_OUTPUT, + &args.tx, + ) + .await?; + let (mut tx, signing_data) = + args.clone().build(namada, &mut bparams).await?; let masp_section = tx .sections @@ -1273,6 +1312,7 @@ pub async fn submit_unshielding_transfer( tx::dump_tx(namada.io(), &args.tx, tx)?; pre_cache_masp_data(namada, &masp_section).await; } else { + masp_sign(&mut tx, &args.tx, &signing_data, shielded_hw_keys).await?; sign(namada, &mut tx, &args.tx, signing_data).await?; let res = namada.submit(tx, &args.tx).await?; pre_cache_masp_data_on_tx_result(namada, &res, &masp_section).await; @@ -1282,12 +1322,26 @@ pub async fn submit_unshielding_transfer( pub async fn submit_ibc_transfer( namada: &N, - args: args::TxIbcTransfer, + mut args: args::TxIbcTransfer, ) -> Result<(), error::Error> where ::Error: std::fmt::Display, { - let (tx, signing_data, _) = args.build(namada).await?; + let sources = args + .source + .spending_key_mut() + .into_iter() + .chain(args.gas_spending_key.iter_mut()); + let shielded_hw_keys = + augment_masp_hardware_keys(namada, &args.tx, sources).await?; + let mut bparams = generate_masp_build_params( + MAX_HW_SPEND, + MAX_HW_CONVERT, + MAX_HW_OUTPUT, + &args.tx, + ) + .await?; + let (mut tx, signing_data, _) = args.build(namada, &mut bparams).await?; let opt_masp_section = tx.sections.iter().find_map(|section| section.masp_tx()); @@ -1297,6 +1351,7 @@ where pre_cache_masp_data(namada, &masp_section).await; } } else { + masp_sign(&mut tx, &args.tx, &signing_data, shielded_hw_keys).await?; let res = batch_opt_reveal_pk_and_submit( namada, &args.tx, diff --git a/crates/core/src/masp.rs b/crates/core/src/masp.rs index 962f487dfa..bd09367abf 100644 --- a/crates/core/src/masp.rs +++ b/crates/core/src/masp.rs @@ -561,6 +561,14 @@ impl TransferSource { } } + /// Get the contained ExtendedSpendingKey contained, if any + pub fn spending_key_mut(&mut self) -> Option<&mut PseudoExtendedKey> { + match self { + Self::ExtendedSpendingKey(x) => Some(x), + _ => None, + } + } + /// Get the contained Address, if any pub fn address(&self) -> Option
{ match self { diff --git a/crates/sdk/src/args.rs b/crates/sdk/src/args.rs index f4cecf68e1..eb962b6e0e 100644 --- a/crates/sdk/src/args.rs +++ b/crates/sdk/src/args.rs @@ -419,8 +419,9 @@ impl TxShieldingTransfer { pub async fn build( &mut self, context: &impl Namada, + bparams: &mut impl BuildParams, ) -> crate::error::Result<(namada_tx::Tx, SigningTxData, MaspEpoch)> { - tx::build_shielding_transfer(context, self).await + tx::build_shielding_transfer(context, self, bparams).await } } @@ -458,8 +459,9 @@ impl TxUnshieldingTransfer { pub async fn build( &mut self, context: &impl Namada, + bparams: &mut impl BuildParams, ) -> crate::error::Result<(namada_tx::Tx, SigningTxData)> { - tx::build_unshielding_transfer(context, self).await + tx::build_unshielding_transfer(context, self, bparams).await } } @@ -604,9 +606,10 @@ impl TxIbcTransfer { pub async fn build( &self, context: &impl Namada, + bparams: &mut impl BuildParams, ) -> crate::error::Result<(namada_tx::Tx, SigningTxData, Option)> { - tx::build_ibc_transfer(context, self).await + tx::build_ibc_transfer(context, self, bparams).await } } diff --git a/crates/sdk/src/tx.rs b/crates/sdk/src/tx.rs index 467b04e7c7..e6f7e9363a 100644 --- a/crates/sdk/src/tx.rs +++ b/crates/sdk/src/tx.rs @@ -2543,6 +2543,7 @@ pub async fn build_pgf_stewards_proposal( pub async fn build_ibc_transfer( context: &impl Namada, args: &args::TxIbcTransfer, + bparams: &mut impl BuildParams, ) -> Result<(Tx, SigningTxData, Option)> { if args.ibc_shielding_data.is_some() && args.ibc_memo.is_some() { return Err(Error::Other( @@ -2556,7 +2557,7 @@ pub async fn build_ibc_transfer( get_refund_target(context, &args.source, &args.refund_target).await?; let source = args.source.effective_address(); - let signing_data = signing::aux_signing_data( + let mut signing_data = signing::aux_signing_data( context, &args.tx, Some(source.clone()), @@ -2651,7 +2652,7 @@ pub async fn build_ibc_transfer( masp_transfer_data, masp_fee_data, args.tx.expiration.to_datetime(), - &mut RngBuildParams::new(OsRng), + bparams, ) .await?; let shielded_tx_epoch = shielded_parts.as_ref().map(|trans| trans.0.epoch); @@ -2702,6 +2703,7 @@ pub async fn build_ibc_transfer( let masp_tx_hash = tx.add_masp_tx_section(shielded_transfer.masp_tx.clone()).1; transfer.shielded_section_hash = Some(masp_tx_hash); + signing_data.shielded_hash = Some(masp_tx_hash); tx.add_masp_builder(MaspBuilder { asset_types, metadata: shielded_transfer.metadata, @@ -3200,6 +3202,7 @@ async fn get_masp_fee_payment_amount( pub async fn build_shielding_transfer( context: &N, args: &mut args::TxShieldingTransfer, + bparams: &mut impl BuildParams, ) -> Result<(Tx, SigningTxData, MaspEpoch)> { let source = if args.data.len() == 1 { // If only one transfer take its source as the signer @@ -3211,7 +3214,7 @@ pub async fn build_shielding_transfer( // argument None }; - let signing_data = signing::aux_signing_data( + let mut signing_data = signing::aux_signing_data( context, &args.tx, source.clone(), @@ -3285,7 +3288,7 @@ pub async fn build_shielding_transfer( transfer_data, None, args.tx.expiration.to_datetime(), - &mut RngBuildParams::new(OsRng), + bparams, ) .await? .expect("Shielding transfer must have shielded parts"); @@ -3316,6 +3319,7 @@ pub async fn build_shielding_transfer( }); data.shielded_section_hash = Some(shielded_section_hash); + signing_data.shielded_hash = Some(shielded_section_hash); tracing::debug!("Transfer data {data:?}"); Ok(()) }; @@ -3337,8 +3341,9 @@ pub async fn build_shielding_transfer( pub async fn build_unshielding_transfer( context: &N, args: &mut args::TxUnshieldingTransfer, + bparams: &mut impl BuildParams, ) -> Result<(Tx, SigningTxData)> { - let signing_data = signing::aux_signing_data( + let mut signing_data = signing::aux_signing_data( context, &args.tx, Some(MASP), @@ -3407,7 +3412,7 @@ pub async fn build_unshielding_transfer( transfer_data, masp_fee_data, args.tx.expiration.to_datetime(), - &mut RngBuildParams::new(OsRng), + bparams, ) .await? .expect("Shielding transfer must have shielded parts"); @@ -3437,6 +3442,7 @@ pub async fn build_unshielding_transfer( }); data.shielded_section_hash = Some(shielded_section_hash); + signing_data.shielded_hash = Some(shielded_section_hash); tracing::debug!("Transfer data {data:?}"); Ok(()) }; diff --git a/wasm/Cargo.lock b/wasm/Cargo.lock index 79caad5218..7c850bbae1 100644 --- a/wasm/Cargo.lock +++ b/wasm/Cargo.lock @@ -3449,7 +3449,7 @@ dependencies = [ [[package]] name = "masp_note_encryption" version = "1.0.0" -source = "git+https://github.com/anoma/masp?rev=a35f73be69b21ee62cd4940f37855161cbed2a56#a35f73be69b21ee62cd4940f37855161cbed2a56" +source = "git+https://github.com/anoma/masp?rev=2914e6ff9a922bae8f1cb63a79d796a69af3d8aa#2914e6ff9a922bae8f1cb63a79d796a69af3d8aa" dependencies = [ "borsh", "chacha20", @@ -3462,7 +3462,7 @@ dependencies = [ [[package]] name = "masp_primitives" version = "1.0.0" -source = "git+https://github.com/anoma/masp?rev=a35f73be69b21ee62cd4940f37855161cbed2a56#a35f73be69b21ee62cd4940f37855161cbed2a56" +source = "git+https://github.com/anoma/masp?rev=2914e6ff9a922bae8f1cb63a79d796a69af3d8aa#2914e6ff9a922bae8f1cb63a79d796a69af3d8aa" dependencies = [ "aes", "bip0039", @@ -3494,7 +3494,7 @@ dependencies = [ [[package]] name = "masp_proofs" version = "1.0.0" -source = "git+https://github.com/anoma/masp?rev=a35f73be69b21ee62cd4940f37855161cbed2a56#a35f73be69b21ee62cd4940f37855161cbed2a56" +source = "git+https://github.com/anoma/masp?rev=2914e6ff9a922bae8f1cb63a79d796a69af3d8aa#2914e6ff9a922bae8f1cb63a79d796a69af3d8aa" dependencies = [ "bellman", "blake2b_simd", diff --git a/wasm_for_tests/Cargo.lock b/wasm_for_tests/Cargo.lock index ccea7985d4..a7ed2f50c7 100644 --- a/wasm_for_tests/Cargo.lock +++ b/wasm_for_tests/Cargo.lock @@ -1863,7 +1863,7 @@ checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" [[package]] name = "masp_note_encryption" version = "1.0.0" -source = "git+https://github.com/anoma/masp?rev=a35f73be69b21ee62cd4940f37855161cbed2a56#a35f73be69b21ee62cd4940f37855161cbed2a56" +source = "git+https://github.com/anoma/masp?rev=2914e6ff9a922bae8f1cb63a79d796a69af3d8aa#2914e6ff9a922bae8f1cb63a79d796a69af3d8aa" dependencies = [ "borsh", "chacha20", @@ -1876,7 +1876,7 @@ dependencies = [ [[package]] name = "masp_primitives" version = "1.0.0" -source = "git+https://github.com/anoma/masp?rev=a35f73be69b21ee62cd4940f37855161cbed2a56#a35f73be69b21ee62cd4940f37855161cbed2a56" +source = "git+https://github.com/anoma/masp?rev=2914e6ff9a922bae8f1cb63a79d796a69af3d8aa#2914e6ff9a922bae8f1cb63a79d796a69af3d8aa" dependencies = [ "aes", "bip0039", @@ -1907,7 +1907,7 @@ dependencies = [ [[package]] name = "masp_proofs" version = "1.0.0" -source = "git+https://github.com/anoma/masp?rev=a35f73be69b21ee62cd4940f37855161cbed2a56#a35f73be69b21ee62cd4940f37855161cbed2a56" +source = "git+https://github.com/anoma/masp?rev=2914e6ff9a922bae8f1cb63a79d796a69af3d8aa#2914e6ff9a922bae8f1cb63a79d796a69af3d8aa" dependencies = [ "bellman", "blake2b_simd", From 9e7c9743b79f7654b28119600f7cb2d3a6fc65ab Mon Sep 17 00:00:00 2001 From: Murisi Tarusenga Date: Thu, 26 Sep 2024 16:30:47 +0200 Subject: [PATCH 04/12] Separate the storage of shielded keys from their birthdays. --- crates/apps_lib/src/cli.rs | 3 +- crates/apps_lib/src/cli/client.rs | 5 ++- crates/apps_lib/src/cli/context.rs | 25 ++++++------ crates/benches/native_vps.rs | 6 +-- crates/node/src/bench_utils.rs | 7 +++- crates/wallet/src/lib.rs | 20 ++++++--- crates/wallet/src/store.rs | 43 ++++++++++++-------- genesis/hardware/src/pre-genesis/wallet.toml | 2 + genesis/localnet/src/pre-genesis/wallet.toml | 2 + 9 files changed, 68 insertions(+), 45 deletions(-) diff --git a/crates/apps_lib/src/cli.rs b/crates/apps_lib/src/cli.rs index 36e0de0d7c..26d8cb7a7f 100644 --- a/crates/apps_lib/src/cli.rs +++ b/crates/apps_lib/src/cli.rs @@ -7766,8 +7766,7 @@ pub mod args { find_viewing_key(&mut wallet) } else { find_viewing_key(&mut ctx.borrow_mut_chain_or_exit().wallet) - } - .key; + }; Ok(PayAddressGen:: { alias: self.alias, diff --git a/crates/apps_lib/src/cli/client.rs b/crates/apps_lib/src/cli/client.rs index 6542a55b63..8939977af6 100644 --- a/crates/apps_lib/src/cli/client.rs +++ b/crates/apps_lib/src/cli/client.rs @@ -4,6 +4,7 @@ use color_eyre::eyre::Result; use namada_sdk::io::{display_line, Io, NamadaIo}; use namada_sdk::masp::ShieldedContext; use namada_sdk::{Namada, NamadaImpl}; +use namada_sdk::wallet::DatedViewingKey; use crate::cli; use crate::cli::api::{CliApi, CliClient}; @@ -349,8 +350,8 @@ impl CliApi { chain_ctx .wallet .get_viewing_keys() - .values() - .copied(), + .into_iter() + .map(|(k, v)| DatedViewingKey::new(v, chain_ctx.wallet.find_birthday(k).copied())), ); crate::client::masp::syncing( diff --git a/crates/apps_lib/src/cli/context.rs b/crates/apps_lib/src/cli/context.rs index 588342ff08..c242380724 100644 --- a/crates/apps_lib/src/cli/context.rs +++ b/crates/apps_lib/src/cli/context.rs @@ -588,7 +588,6 @@ impl ArgFromMutContext for ExtendedSpendingKey { // Or it is a stored alias of one ctx.wallet .find_spending_key(raw, None) - .map(|k| k.key) .map_err(|_find_err| format!("Unknown spending key {}", raw)) }) } @@ -613,9 +612,7 @@ impl ArgFromMutContext for PseudoExtendedKey { ctx.wallet .find_spending_key(raw, None) .map(|k| { - PseudoExtendedKey::from(MaspExtendedSpendingKey::from( - k.key, - )) + PseudoExtendedKey::from(MaspExtendedSpendingKey::from(k)) }) .map_err(|_find_err| { format!("Unknown spending key {}", raw) @@ -627,9 +624,7 @@ impl ArgFromMutContext for PseudoExtendedKey { .find_viewing_key(raw) .copied() .map(|k| { - PseudoExtendedKey::from(MaspExtendedViewingKey::from( - k.key, - )) + PseudoExtendedKey::from(MaspExtendedViewingKey::from(k)) }) .map_err(|_find_err| format!("Unknown viewing key {}", raw)) }) @@ -645,9 +640,12 @@ impl ArgFromMutContext for DatedSpendingKey { // Either the string is a raw extended spending key FromStr::from_str(raw).or_else(|_parse_err| { // Or it is a stored alias of one - ctx.wallet + let sk = ctx.wallet .find_spending_key(raw, None) - .map_err(|_find_err| format!("Unknown spending key {}", raw)) + .map_err(|_find_err| format!("Unknown spending key {}", raw))?; + let birthday = ctx.wallet + .find_birthday(raw); + Ok(DatedSpendingKey::new(sk, birthday.copied())) }) } } @@ -664,7 +662,6 @@ impl ArgFromMutContext for ExtendedViewingKey { ctx.wallet .find_viewing_key(raw) .copied() - .map(|k| k.key) .map_err(|_find_err| format!("Unknown viewing key {}", raw)) }) } @@ -679,10 +676,12 @@ impl ArgFromMutContext for DatedViewingKey { // Either the string is a raw full viewing key FromStr::from_str(raw).or_else(|_parse_err| { // Or it is a stored alias of one - ctx.wallet + let vk = ctx.wallet .find_viewing_key(raw) - .copied() - .map_err(|_find_err| format!("Unknown viewing key {}", raw)) + .map_err(|_find_err| format!("Unknown viewing key {}", raw))?; + let birthday = ctx.wallet + .find_birthday(raw); + Ok(DatedViewingKey::new(*vk, birthday.copied())) }) } } diff --git a/crates/benches/native_vps.rs b/crates/benches/native_vps.rs index 6e12b24523..474067abcd 100644 --- a/crates/benches/native_vps.rs +++ b/crates/benches/native_vps.rs @@ -412,7 +412,7 @@ fn prepare_ibc_tx_and_ctx(bench_name: &str) -> (BenchShieldedCtx, BatchedTx) { shielded_ctx.generate_shielded_action( Amount::native_whole(10), TransferSource::ExtendedSpendingKey( - ExtendedSpendingKey::from(albert_spending_key.key).into(), + ExtendedSpendingKey::from(albert_spending_key).into(), ), defaults::bertha_address().to_string(), ) @@ -606,14 +606,14 @@ fn setup_storage_for_masp_verification( "unshielding" => shielded_ctx.generate_masp_tx( amount, TransferSource::ExtendedSpendingKey( - ExtendedSpendingKey::from(albert_spending_key.key).into(), + ExtendedSpendingKey::from(albert_spending_key).into(), ), TransferTarget::Address(defaults::albert_address()), ), "shielded" => shielded_ctx.generate_masp_tx( amount, TransferSource::ExtendedSpendingKey( - ExtendedSpendingKey::from(albert_spending_key.key).into(), + ExtendedSpendingKey::from(albert_spending_key).into(), ), TransferTarget::PaymentAddress(bertha_payment_addr), ), diff --git a/crates/node/src/bench_utils.rs b/crates/node/src/bench_utils.rs index ea253938d5..948d94d9fb 100644 --- a/crates/node/src/bench_utils.rs +++ b/crates/node/src/bench_utils.rs @@ -106,7 +106,7 @@ pub use namada_sdk::tx::{ TX_UPDATE_STEWARD_COMMISSION, TX_VOTE_PROPOSAL as TX_VOTE_PROPOSAL_WASM, TX_WITHDRAW_WASM, VP_USER_WASM, }; -use namada_sdk::wallet::Wallet; +use namada_sdk::wallet::{DatedSpendingKey, Wallet}; use namada_sdk::{ parameters, proof_of_stake, tendermint, Namada, NamadaImpl, PaymentAddress, TransferSource, TransferTarget, @@ -1136,7 +1136,6 @@ impl Default for BenchShieldedCtx { .wallet .find_viewing_key(viewing_alias) .unwrap() - .key .to_string(), ); let viewing_key = ExtendedFullViewingKey::from( @@ -1179,6 +1178,10 @@ impl BenchShieldedCtx { .wallet .find_spending_key(ALBERT_SPENDING_KEY, None) .unwrap(); + let spending_key = DatedSpendingKey::new( + spending_key, + self.wallet.find_birthday(ALBERT_SPENDING_KEY).copied(), + ); self.shielded = async_runtime .block_on(namada_apps_lib::client::masp::syncing( self.shielded, diff --git a/crates/wallet/src/lib.rs b/crates/wallet/src/lib.rs index f78dd75ca7..48488d3363 100644 --- a/crates/wallet/src/lib.rs +++ b/crates/wallet/src/lib.rs @@ -274,7 +274,7 @@ pub struct Wallet { utils: U, store: Store, decrypted_key_cache: HashMap, - decrypted_spendkey_cache: HashMap, + decrypted_spendkey_cache: HashMap, } impl From> for Store { @@ -436,12 +436,20 @@ impl Wallet { pub fn find_viewing_key( &self, alias: impl AsRef, - ) -> Result<&DatedViewingKey, FindKeyError> { + ) -> Result<&ExtendedViewingKey, FindKeyError> { self.store.find_viewing_key(alias.as_ref()).ok_or_else(|| { FindKeyError::KeyNotFound(alias.as_ref().to_string()) }) } + /// Find the birthday of the given alias + pub fn find_birthday( + &self, + alias: impl AsRef, + ) -> Option<&BlockHeight> { + self.store.find_birthday(alias.as_ref()) + } + /// Find the payment address with the given alias in the wallet and return /// it pub fn find_payment_addr( @@ -501,7 +509,7 @@ impl Wallet { } /// Get all known viewing keys by their alias - pub fn get_viewing_keys(&self) -> HashMap { + pub fn get_viewing_keys(&self) -> HashMap { self.store .get_viewing_keys() .iter() @@ -512,7 +520,7 @@ impl Wallet { /// Get all known viewing keys by their alias pub fn get_spending_keys( &self, - ) -> HashMap> { + ) -> HashMap> { self.store .get_spending_keys() .iter() @@ -944,7 +952,7 @@ impl Wallet { &mut self, alias: impl AsRef, password: Option>, - ) -> Result { + ) -> Result { // Try cache first if let Some(cached_key) = self .decrypted_spendkey_cache @@ -1196,7 +1204,7 @@ impl Wallet { // Cache the newly added key self.decrypted_spendkey_cache.insert( alias.clone(), - DatedKeypair::new(spend_key, birthday), + spend_key, ); }) .map(Into::into) diff --git a/crates/wallet/src/store.rs b/crates/wallet/src/store.rs index 8237abbab5..cb15a6c359 100644 --- a/crates/wallet/src/store.rs +++ b/crates/wallet/src/store.rs @@ -22,7 +22,6 @@ use zeroize::Zeroizing; use super::alias::{self, Alias}; use super::derivation_path::DerivationPath; use super::pre_genesis; -use crate::keys::{DatedKeypair, DatedSpendingKey, DatedViewingKey}; use crate::{StoredKeypair, WalletIo}; /// Actions that can be taken when there is an alias conflict @@ -63,10 +62,12 @@ pub struct ValidatorData { /// A Storage area for keys and addresses #[derive(Serialize, Deserialize, Debug, Default)] pub struct Store { + /// Known birthdays + birthdays: BTreeMap, /// Known viewing keys - view_keys: BTreeMap, + view_keys: BTreeMap, /// Known spending keys - spend_keys: BTreeMap>, + spend_keys: BTreeMap>, /// Payment address book payment_addrs: BiBTreeMap, /// Cryptographic keypairs @@ -135,7 +136,7 @@ impl Store { pub fn find_spending_key( &self, alias: impl AsRef, - ) -> Option<&StoredKeypair> { + ) -> Option<&StoredKeypair> { self.spend_keys.get(&alias.into()) } @@ -143,10 +144,18 @@ impl Store { pub fn find_viewing_key( &self, alias: impl AsRef, - ) -> Option<&DatedViewingKey> { + ) -> Option<&ExtendedViewingKey> { self.view_keys.get(&alias.into()) } + /// Find the birthday of the given alias + pub fn find_birthday( + &self, + alias: impl AsRef, + ) -> Option<&BlockHeight> { + self.birthdays.get(&alias.into()) + } + /// Find the payment address with the given alias and return it pub fn find_payment_addr( &self, @@ -200,7 +209,7 @@ impl Store { viewing_key: &ExtendedViewingKey, ) -> Option { for (alias, vk) in &self.view_keys { - if *viewing_key == vk.key { + if *viewing_key == *vk { return self.derivation_paths.get(alias).cloned(); } } @@ -267,14 +276,14 @@ impl Store { } /// Get all known viewing keys by their alias. - pub fn get_viewing_keys(&self) -> &BTreeMap { + pub fn get_viewing_keys(&self) -> &BTreeMap { &self.view_keys } /// Get all known spending keys by their alias. pub fn get_spending_keys( &self, - ) -> &BTreeMap> { + ) -> &BTreeMap> { &self.spend_keys } @@ -412,15 +421,11 @@ impl Store { } self.remove_alias(&alias); - let (spendkey_to_store, _raw_spendkey) = - StoredKeypair::new(DatedKeypair::new(spendkey, birthday), password); + let (spendkey_to_store, _raw_spendkey) = StoredKeypair::new(spendkey, password); self.spend_keys.insert(alias.clone(), spendkey_to_store); // Simultaneously add the derived viewing key to ease balance viewing - let viewkey = DatedKeypair::new( - zip32::ExtendedFullViewingKey::from(&spendkey.into()).into(), - birthday, - ); - self.view_keys.insert(alias.clone(), viewkey); + birthday.map(|x| self.birthdays.insert(alias.clone(), x)); + self.view_keys.insert(alias.clone(), zip32::ExtendedFullViewingKey::from(&spendkey.into()).into()); path.map(|p| self.derivation_paths.insert(alias.clone(), p)); Some(alias) } @@ -456,8 +461,8 @@ impl Store { } } self.remove_alias(&alias); - self.view_keys - .insert(alias.clone(), DatedKeypair::new(viewkey, birthday)); + birthday.map(|x| self.birthdays.insert(alias.clone(), x)); + self.view_keys.insert(alias.clone(), viewkey); path.map(|p| self.derivation_paths.insert(alias.clone(), p)); Some(alias) } @@ -600,6 +605,7 @@ impl Store { || self.pkhs.values().contains(alias) || self.public_keys.contains_key(alias) || self.derivation_paths.contains_key(alias) + || self.birthdays.contains_key(alias) } /// Completely remove the given alias from all maps in the wallet @@ -612,12 +618,14 @@ impl Store { self.pkhs.retain(|_key, val| val != alias); self.public_keys.remove(alias); self.derivation_paths.remove(alias); + self.birthdays.remove(alias); } /// Extend this store from another store (typically pre-genesis). /// Note that this method ignores `validator_data` if any. pub fn extend(&mut self, store: Store) { let Self { + birthdays, view_keys, spend_keys, payment_addrs, @@ -629,6 +637,7 @@ impl Store { validator_data: _, address_vp_types, } = self; + birthdays.extend(store.birthdays); view_keys.extend(store.view_keys); spend_keys.extend(store.spend_keys); payment_addrs.extend(store.payment_addrs); diff --git a/genesis/hardware/src/pre-genesis/wallet.toml b/genesis/hardware/src/pre-genesis/wallet.toml index 1f36ffe432..7866cb9c2f 100644 --- a/genesis/hardware/src/pre-genesis/wallet.toml +++ b/genesis/hardware/src/pre-genesis/wallet.toml @@ -1,3 +1,5 @@ +[birthdays] + [view_keys] [spend_keys] diff --git a/genesis/localnet/src/pre-genesis/wallet.toml b/genesis/localnet/src/pre-genesis/wallet.toml index fbf083e87b..eb231c1e0e 100644 --- a/genesis/localnet/src/pre-genesis/wallet.toml +++ b/genesis/localnet/src/pre-genesis/wallet.toml @@ -1,3 +1,5 @@ +[birthdays] + [view_keys] [spend_keys] From 381531b9e519bf2aa8c526e6b737aaba2bd3a33c Mon Sep 17 00:00:00 2001 From: Murisi Tarusenga Date: Fri, 27 Sep 2024 16:14:57 +0200 Subject: [PATCH 05/12] Never use the hardware wallet to sign the fee header alone. Always ensure removal of MASP Builder data. --- crates/apps_lib/src/cli/client.rs | 12 ++++- crates/apps_lib/src/cli/context.rs | 16 ++++--- crates/apps_lib/src/client/tx.rs | 10 +++-- .../src/config/genesis/transactions.rs | 2 +- crates/apps_lib/src/config/genesis/utils.rs | 5 +-- crates/sdk/src/lib.rs | 3 +- crates/sdk/src/signing.rs | 45 +++++++++---------- crates/wallet/src/lib.rs | 6 +-- crates/wallet/src/store.rs | 8 +++- 9 files changed, 57 insertions(+), 50 deletions(-) diff --git a/crates/apps_lib/src/cli/client.rs b/crates/apps_lib/src/cli/client.rs index 8939977af6..6269773784 100644 --- a/crates/apps_lib/src/cli/client.rs +++ b/crates/apps_lib/src/cli/client.rs @@ -3,8 +3,8 @@ use std::io::Read; use color_eyre::eyre::Result; use namada_sdk::io::{display_line, Io, NamadaIo}; use namada_sdk::masp::ShieldedContext; -use namada_sdk::{Namada, NamadaImpl}; use namada_sdk::wallet::DatedViewingKey; +use namada_sdk::{Namada, NamadaImpl}; use crate::cli; use crate::cli::api::{CliApi, CliClient}; @@ -351,7 +351,15 @@ impl CliApi { .wallet .get_viewing_keys() .into_iter() - .map(|(k, v)| DatedViewingKey::new(v, chain_ctx.wallet.find_birthday(k).copied())), + .map(|(k, v)| { + DatedViewingKey::new( + v, + chain_ctx + .wallet + .find_birthday(k) + .copied(), + ) + }), ); crate::client::masp::syncing( diff --git a/crates/apps_lib/src/cli/context.rs b/crates/apps_lib/src/cli/context.rs index c242380724..15984847e1 100644 --- a/crates/apps_lib/src/cli/context.rs +++ b/crates/apps_lib/src/cli/context.rs @@ -612,7 +612,9 @@ impl ArgFromMutContext for PseudoExtendedKey { ctx.wallet .find_spending_key(raw, None) .map(|k| { - PseudoExtendedKey::from(MaspExtendedSpendingKey::from(k)) + PseudoExtendedKey::from(MaspExtendedSpendingKey::from( + k, + )) }) .map_err(|_find_err| { format!("Unknown spending key {}", raw) @@ -640,11 +642,11 @@ impl ArgFromMutContext for DatedSpendingKey { // Either the string is a raw extended spending key FromStr::from_str(raw).or_else(|_parse_err| { // Or it is a stored alias of one - let sk = ctx.wallet + let sk = ctx + .wallet .find_spending_key(raw, None) .map_err(|_find_err| format!("Unknown spending key {}", raw))?; - let birthday = ctx.wallet - .find_birthday(raw); + let birthday = ctx.wallet.find_birthday(raw); Ok(DatedSpendingKey::new(sk, birthday.copied())) }) } @@ -676,11 +678,11 @@ impl ArgFromMutContext for DatedViewingKey { // Either the string is a raw full viewing key FromStr::from_str(raw).or_else(|_parse_err| { // Or it is a stored alias of one - let vk = ctx.wallet + let vk = ctx + .wallet .find_viewing_key(raw) .map_err(|_find_err| format!("Unknown viewing key {}", raw))?; - let birthday = ctx.wallet - .find_birthday(raw); + let birthday = ctx.wallet.find_birthday(raw); Ok(DatedViewingKey::new(*vk, birthday.copied())) }) } diff --git a/crates/apps_lib/src/client/tx.rs b/crates/apps_lib/src/client/tx.rs index 97052a441a..4bb147f905 100644 --- a/crates/apps_lib/src/client/tx.rs +++ b/crates/apps_lib/src/client/tx.rs @@ -19,7 +19,7 @@ use masp_primitives::zip32::{ }; use namada_sdk::address::{Address, ImplicitAddress}; use namada_sdk::args::TxBecomeValidator; -use namada_sdk::collections::{HashMap, HashSet}; +use namada_sdk::collections::HashMap; use namada_sdk::governance::cli::onchain::{ DefaultProposal, PgfFundingProposal, PgfStewardProposal, }; @@ -105,7 +105,7 @@ pub async fn aux_signing_data( pub async fn with_hardware_wallet<'a, U, T>( mut tx: Tx, pubkey: common::PublicKey, - parts: HashSet, + parts: signing::Signable, (wallet, app): (&RwLock>, &NamadaApp), ) -> Result where @@ -152,7 +152,9 @@ where .await .map_err(|err| error::Error::Other(err.to_string()))?; // Sign the raw header if that is requested - if parts.contains(&signing::Signable::RawHeader) { + if parts == signing::Signable::RawHeader + || parts == signing::Signable::FeeRawHeader + { let pubkey = common::PublicKey::try_from_slice(&response.pubkey) .expect("unable to parse public key from Ledger"); let signature = @@ -170,7 +172,7 @@ where tx.add_section(Section::Authorization(compressed.expand(&tx))); } // Sign the fee header if that is requested - if parts.contains(&signing::Signable::FeeHeader) { + if parts == signing::Signable::FeeRawHeader { let pubkey = common::PublicKey::try_from_slice(&response.pubkey) .expect("unable to parse public key from Ledger"); let signature = diff --git a/crates/apps_lib/src/config/genesis/transactions.rs b/crates/apps_lib/src/config/genesis/transactions.rs index 8649884f9c..cb3e3fb7fa 100644 --- a/crates/apps_lib/src/config/genesis/transactions.rs +++ b/crates/apps_lib/src/config/genesis/transactions.rs @@ -795,7 +795,7 @@ impl Signed { async fn software_wallet_sign( tx: Tx, pubkey: common::PublicKey, - _parts: HashSet, + _parts: namada_sdk::signing::Signable, _user: (), ) -> Result { if pubkey == genesis_fee_payer_pk() { diff --git a/crates/apps_lib/src/config/genesis/utils.rs b/crates/apps_lib/src/config/genesis/utils.rs index c5971d9d2c..d5622111dd 100644 --- a/crates/apps_lib/src/config/genesis/utils.rs +++ b/crates/apps_lib/src/config/genesis/utils.rs @@ -2,7 +2,6 @@ use std::path::Path; use eyre::Context; use ledger_namada_rs::NamadaApp; -use namada_sdk::collections::HashSet; use namada_sdk::key::common; use namada_sdk::tx::Tx; use namada_sdk::wallet::Wallet; @@ -52,14 +51,14 @@ pub fn write_toml( pub(super) async fn with_hardware_wallet<'a, T>( tx: Tx, pubkey: common::PublicKey, - parts: HashSet, + parts: signing::Signable, (wallet, app): (&RwLock>, &NamadaApp), ) -> Result where T: ledger_transport::Exchange + Send + Sync, ::Error: std::error::Error, { - if parts.contains(&signing::Signable::FeeHeader) { + if parts == signing::Signable::FeeRawHeader { Ok(tx) } else { crate::client::tx::with_hardware_wallet( diff --git a/crates/sdk/src/lib.rs b/crates/sdk/src/lib.rs index 60d96cc7e1..f1471e0abf 100644 --- a/crates/sdk/src/lib.rs +++ b/crates/sdk/src/lib.rs @@ -47,7 +47,6 @@ use std::str::FromStr; use args::{DeviceTransport, InputAmount, SdkTypes}; use masp_primitives::zip32::PseudoExtendedKey; use namada_core::address::Address; -use namada_core::collections::HashSet; use namada_core::dec::Dec; use namada_core::ethereum_events::EthAddress; use namada_core::ibc::core::host::types::identifiers::{ChannelId, PortId}; @@ -609,7 +608,7 @@ pub trait Namada: NamadaIo { tx: &mut Tx, args: &args::Tx, signing_data: SigningTxData, - with: impl Fn(Tx, common::PublicKey, HashSet, D) -> F + with: impl Fn(Tx, common::PublicKey, signing::Signable, D) -> F + MaybeSend + MaybeSync, user_data: D, diff --git a/crates/sdk/src/signing.rs b/crates/sdk/src/signing.rs index 5768629110..131a86eddc 100644 --- a/crates/sdk/src/signing.rs +++ b/crates/sdk/src/signing.rs @@ -196,11 +196,12 @@ pub async fn tx_signers( } } -/// The different parts of a transaction that can be signed +/// The different parts of a transaction that can be signed. Note that it's +/// impossible to sign the fee header without signing the raw header. #[derive(Eq, Hash, PartialEq)] pub enum Signable { - /// Fee header - FeeHeader, + /// Fee and raw header + FeeRawHeader, /// Raw header RawHeader, } @@ -209,7 +210,7 @@ pub enum Signable { pub async fn default_sign( _tx: Tx, pubkey: common::PublicKey, - _parts: HashSet, + _parts: Signable, _user: (), ) -> Result { Err(Error::Other(format!( @@ -234,7 +235,7 @@ pub async fn sign_tx<'a, D, F, U>( args: &args::Tx, tx: &mut Tx, signing_data: SigningTxData, - sign: impl Fn(Tx, common::PublicKey, HashSet, D) -> F, + sign: impl Fn(Tx, common::PublicKey, Signable, D) -> F, user_data: D, ) -> Result<(), Error> where @@ -290,11 +291,13 @@ where // Then try to sign the raw header using the hardware wallet for pubkey in &signing_data.public_keys { - if !used_pubkeys.contains(pubkey) && *pubkey != signing_data.fee_payer { + if !used_pubkeys.contains(pubkey) && + (*pubkey != signing_data.fee_payer || args.wrapper_signature.is_some()) + { if let Ok(ntx) = sign( tx.clone(), pubkey.clone(), - HashSet::from([Signable::RawHeader]), + Signable::RawHeader, user_data.clone(), ) .await @@ -323,33 +326,25 @@ where Ok(fee_payer_keypair) => { tx.sign_wrapper(fee_payer_keypair); } - // The case where the fee payer also signs the inner transaction - Err(_) - if signing_data - .public_keys - .contains(&signing_data.fee_payer) => - { - *tx = sign( - tx.clone(), - signing_data.fee_payer.clone(), - HashSet::from([Signable::FeeHeader, Signable::RawHeader]), - user_data, - ) - .await?; - used_pubkeys.insert(signing_data.fee_payer.clone()); - } - // The case where the fee payer does not sign the inner transaction Err(_) => { *tx = sign( tx.clone(), signing_data.fee_payer.clone(), - HashSet::from([Signable::FeeHeader]), + Signable::FeeRawHeader, user_data, ) - .await?; + .await?; + if signing_data.public_keys.contains(&signing_data.fee_payer) { + used_pubkeys.insert(signing_data.fee_payer.clone()); + } } } } + // Remove redundant sections now that the signing process is complete. + // Though this call might be redundant in circumstances, it is placed here + // as a safeguard to prevent the transmission of private data to the + // network. + tx.protocol_filter(); // Then make sure that the number of public keys used exceeds the threshold let used_pubkeys_len = used_pubkeys .len() diff --git a/crates/wallet/src/lib.rs b/crates/wallet/src/lib.rs index 48488d3363..e5ba30b630 100644 --- a/crates/wallet/src/lib.rs +++ b/crates/wallet/src/lib.rs @@ -1202,10 +1202,8 @@ impl Wallet { ) .inspect(|alias| { // Cache the newly added key - self.decrypted_spendkey_cache.insert( - alias.clone(), - spend_key, - ); + self.decrypted_spendkey_cache + .insert(alias.clone(), spend_key); }) .map(Into::into) } diff --git a/crates/wallet/src/store.rs b/crates/wallet/src/store.rs index cb15a6c359..7eb42bbbc4 100644 --- a/crates/wallet/src/store.rs +++ b/crates/wallet/src/store.rs @@ -421,11 +421,15 @@ impl Store { } self.remove_alias(&alias); - let (spendkey_to_store, _raw_spendkey) = StoredKeypair::new(spendkey, password); + let (spendkey_to_store, _raw_spendkey) = + StoredKeypair::new(spendkey, password); self.spend_keys.insert(alias.clone(), spendkey_to_store); // Simultaneously add the derived viewing key to ease balance viewing birthday.map(|x| self.birthdays.insert(alias.clone(), x)); - self.view_keys.insert(alias.clone(), zip32::ExtendedFullViewingKey::from(&spendkey.into()).into()); + self.view_keys.insert( + alias.clone(), + zip32::ExtendedFullViewingKey::from(&spendkey.into()).into(), + ); path.map(|p| self.derivation_paths.insert(alias.clone(), p)); Some(alias) } From 0ef7b66ce23fa082f3269ee7da32b26c10d40f79 Mon Sep 17 00:00:00 2001 From: Murisi Tarusenga Date: Fri, 27 Sep 2024 20:13:29 +0200 Subject: [PATCH 06/12] Moved the shielded keys used in the integration tests into the localnet wallet. --- crates/apps_lib/src/client/tx.rs | 6 +- crates/tests/src/e2e/setup.rs | 20 +- crates/tests/src/integration/masp.rs | 426 +++++------------- genesis/hardware/src/pre-genesis/wallet.toml | 10 + genesis/localnet/balances.toml | 15 + .../pre-genesis/unsigned-transactions.toml | 6 + genesis/localnet/src/pre-genesis/wallet.toml | 15 + 7 files changed, 178 insertions(+), 320 deletions(-) diff --git a/crates/apps_lib/src/client/tx.rs b/crates/apps_lib/src/client/tx.rs index 4bb147f905..30385e67a1 100644 --- a/crates/apps_lib/src/client/tx.rs +++ b/crates/apps_lib/src/client/tx.rs @@ -51,17 +51,17 @@ use crate::wallet::{ // generated on the hardware wallet. It is hard to compute the exact required // number because a given MASP source could be distributed amongst several // notes. -const MAX_HW_SPEND: usize = 10; +const MAX_HW_SPEND: usize = 15; // Maximum number of convert description randomness parameters that can be // generated on the hardware wallet. It is hard to compute the exact required // number because the number of conversions that are used depends on the // protocol's current state. -const MAX_HW_CONVERT: usize = 10; +const MAX_HW_CONVERT: usize = 15; // Maximum number of output description randomness parameters that can be // generated on the hardware wallet. It is hard to compute the exact required // number because the number of outputs depends on the number of dummy outputs // introduced. -const MAX_HW_OUTPUT: usize = 10; +const MAX_HW_OUTPUT: usize = 15; /// Wrapper around `signing::aux_signing_data` that stores the optional /// disposable address to the wallet diff --git a/crates/tests/src/e2e/setup.rs b/crates/tests/src/e2e/setup.rs index ebd2329aaa..6dd8f44167 100644 --- a/crates/tests/src/e2e/setup.rs +++ b/crates/tests/src/e2e/setup.rs @@ -1555,23 +1555,23 @@ pub mod constants { pub const FRANK_KEY: &str = "Frank-key"; // Shielded spending and viewing keys and payment addresses - pub const A_SPENDING_KEY: &str = "zsknam1qdrk9kd8qqqqpqy3pxzxu2kexydl7ug22s3808htl604emmz9qlde9cl9mx6euhvh3cpl9w7guustfzjxsyaeqtefhden6q8776t9cr9vkqztj7u0mgs5k9nz945sypev9ppptn5d85as3ccsnu3q6g3acqp2gpsrwe6naqg3stqp43uk9x2cj79gcxuum8a7jayjqlv4ptcfnunqkqzsj6m2r3sn8ft0tyqqpv28nghe4ag68eccaqx7v5f65he95g5uwq2wr4yuqc06jgc7"; - pub const B_SPENDING_KEY: &str = "zsknam1qdml0zguqqqqpqx8elavks722m0cjelgh3r044cfregyw049jze9lwha2cfqdqnekecnttdvygd6s784kch2v3wjs45g5z0n36hpqv5ruy8jjfu5mz2snl8ljyz79h3szmyf43zve79l6hwnlfk94r422tfwr2f62vvgkeqvc4z2dgrvqy033ymq5ylz3gmf6wdzhsdmzm0h9uv9374x755rzgvmcxhxntu6v63acqktv6zk390e9pd6vr0pzqaq6auu59kwpnw0haczfyju8"; + pub const A_SPENDING_KEY: &str = "albert-svk"; + pub const B_SPENDING_KEY: &str = "bertha-svk"; // A payment address derived from A_SPENDING_KEY - pub const AA_PAYMENT_ADDRESS: &str = "znam1ky620tz7z658cralqt693qpvk42wvth468zp38nqvq2apmex5rfut3dfqm2asrsqv0tc7saqje7"; + pub const AA_PAYMENT_ADDRESS: &str = "albert-pa"; // A payment address derived from B_SPENDING_KEY - pub const AB_PAYMENT_ADDRESS: &str = "znam1zxt8e22uz666ce7hxqpc69yfj3tpd9v26ep2epwn34kvyuwjh98hhre9897shcjj4cnqugwlv4q"; + pub const AB_PAYMENT_ADDRESS: &str = "bertha-pa-a"; // A viewing key derived from B_SPENDING_KEY - pub const AB_VIEWING_KEY: &str = "zvknam1qdml0zguqqqqpqx8elavks722m0cjelgh3r044cfregyw049jze9lwha2cfqdqnekem0xdqf9ytuhaxzeunyl7svgvxjv5g73m24k7w0h6q7wtvcltvlzynzhc5grlfgv7037lfh8w3su5krnzzzjh4nsleydtlns4gl0vmnc4z2dgrvqy033ymq5ylz3gmf6wdzhsdmzm0h9uv9374x755rzgvmcxhxntu6v63acqktv6zk390e9pd6vr0pzqaq6auu59kwpnw0hacdsfkws"; + pub const AB_VIEWING_KEY: &str = "bertha-svk"; // A payment address derived from B_VIEWING_KEY - pub const BB_PAYMENT_ADDRESS: &str = "znam1mqt0ja2zccy70du2d6rcr77jscgq3gkekfvhrqe7zkxa8rr3qsjsrd66gxnrykdmdeh5wmglmcm"; + pub const BB_PAYMENT_ADDRESS: &str = "bertha-pa-b"; // A viewing key derived from A_SPENDING_KEY - pub const AA_VIEWING_KEY: &str = "zvknam1qdrk9kd8qqqqpqy3pxzxu2kexydl7ug22s3808htl604emmz9qlde9cl9mx6euhvhnc63hymme53jz3mmwrzfkr9tk82nqacf5vlmj9du3s3rjz0h6usnh47pw0ufw4u6yrfvf95wfa9xj0m8pcrns9yh90s0jkf3cqy2z7c3stqp43uk9x2cj79gcxuum8a7jayjqlv4ptcfnunqkqzsj6m2r3sn8ft0tyqqpv28nghe4ag68eccaqx7v5f65he95g5uwq2wr4yuqc8djdrp"; - pub const C_SPENDING_KEY: &str = "zsknam1qdy5g4udqqqqpqrfdzej0s45m8s6nprder4udwqm3ql8wx34e8f46dv8cwnmcjp40uj3qy5tgetj27jytvxk4vpa3pjsd80y332nj542w39wta8lsrzqzs822ydgmz5g2sd2k29hxc3uh77v5cmcext799fxn6sa9rd3zuggl6flgjz7wz9wwu9kxd4rth4clw6ug4drxln96y96nf8fmvgm5eddm93azuzlkjj0dpw343ukwcfuvkdhd772539cskgggcqsaaf0j7czshjwe"; + pub const AA_VIEWING_KEY: &str = "albert-svk"; + pub const C_SPENDING_KEY: &str = "christel-svk"; // A viewing key derived from C_SPENDING_KEY - pub const AC_VIEWING_KEY: &str = "zvknam1qdy5g4udqqqqpqrfdzej0s45m8s6nprder4udwqm3ql8wx34e8f46dv8cwnmcjp40lr4vutffut7ed5x6egd6etcdh9sxh3j9fe5dshhrn3nq4yfp78gt8ve59y4vnu45xlt93vtrzsxtwlxjjgu2p496lc3ye8m83qplsqfl6flgjz7wz9wwu9kxd4rth4clw6ug4drxln96y96nf8fmvgm5eddm93azuzlkjj0dpw343ukwcfuvkdhd772539cskgggcqsaaf0j7cfyd3jr"; + pub const AC_VIEWING_KEY: &str = "christel-svk"; // A viewing key derived from C_VIEWING_KEY - pub const AC_PAYMENT_ADDRESS: &str = "znam1xv4ml6fp3zqjhw20xj3srd75cq8tyejdst0xweq60c70732ty2chd2v39tllpzf4uf6s66vfm6w"; + pub const AC_PAYMENT_ADDRESS: &str = "christel-pa"; // Native VP aliases pub const GOVERNANCE_ADDRESS: &str = "governance"; diff --git a/crates/tests/src/integration/masp.rs b/crates/tests/src/integration/masp.rs index e75a3ea4a6..f2868b34ba 100644 --- a/crates/tests/src/integration/masp.rs +++ b/crates/tests/src/integration/masp.rs @@ -24,6 +24,7 @@ use namada_sdk::{tx, DEFAULT_GAS_LIMIT}; use test_log::test; use super::{helpers, setup}; +use crate::e2e::setup::apply_use_device; use crate::e2e::setup::constants::{ AA_PAYMENT_ADDRESS, AA_VIEWING_KEY, AB_PAYMENT_ADDRESS, AB_VIEWING_KEY, AC_PAYMENT_ADDRESS, AC_VIEWING_KEY, ALBERT, ALBERT_KEY, A_SPENDING_KEY, @@ -1459,7 +1460,7 @@ fn masp_incentives() -> Result<()> { run( &node, Bin::Client, - vec![ + apply_use_device(vec![ "shield", "--source", ALBERT, @@ -1469,9 +1470,11 @@ fn masp_incentives() -> Result<()> { BTC, "--amount", "1", + "--signing-keys", + ALBERT_KEY, "--node", validator_one_rpc, - ], + ]), ) }); assert!(captured.result.is_ok()); @@ -1716,7 +1719,7 @@ fn masp_incentives() -> Result<()> { run( &node, Bin::Client, - vec![ + apply_use_device(vec![ "shield", "--source", ALBERT, @@ -1726,9 +1729,11 @@ fn masp_incentives() -> Result<()> { ETH, "--amount", "0.001", + "--signing-keys", + ALBERT_KEY, "--node", validator_one_rpc, - ], + ]), ) }); assert!(captured.result.is_ok()); @@ -1826,7 +1831,7 @@ fn masp_incentives() -> Result<()> { ) }); assert!(captured.result.is_ok()); - assert!(captured.contains("nam: 0.725514")); + assert!(captured.contains("nam: 0.750883")); // Assert NAM balance at MASP pool is an accumulation of // rewards from both the shielded BTC and shielded ETH @@ -1846,7 +1851,7 @@ fn masp_incentives() -> Result<()> { ) }); assert!(captured.result.is_ok()); - assert!(captured.contains("nam: 1.358764")); + assert!(captured.contains("nam: 1.384131")); // Wait till epoch boundary node.next_masp_epoch(); @@ -1855,7 +1860,7 @@ fn masp_incentives() -> Result<()> { run( &node, Bin::Client, - vec![ + apply_use_device(vec![ "unshield", "--source", B_SPENDING_KEY, @@ -1869,7 +1874,7 @@ fn masp_incentives() -> Result<()> { BERTHA_KEY, "--node", validator_one_rpc, - ], + ]), ) }); assert!(captured.result.is_ok()); @@ -1927,7 +1932,7 @@ fn masp_incentives() -> Result<()> { ) }); assert!(captured.result.is_ok()); - assert!(captured.contains("nam: 1.451732")); + assert!(captured.contains("nam: 1.502496")); node.next_masp_epoch(); // sync the shielded context @@ -1955,7 +1960,7 @@ fn masp_incentives() -> Result<()> { ) }); assert!(captured.result.is_ok()); - assert!(captured.contains("nam: 3.219616")); + assert!(captured.contains("nam: 3.270374")); // Wait till epoch boundary node.next_masp_epoch(); @@ -1965,7 +1970,7 @@ fn masp_incentives() -> Result<()> { run( &node, Bin::Client, - vec![ + apply_use_device(vec![ "unshield", "--source", A_SPENDING_KEY, @@ -1979,7 +1984,7 @@ fn masp_incentives() -> Result<()> { ALBERT_KEY, "--node", validator_one_rpc, - ], + ]), ) }); assert!(captured.result.is_ok()); @@ -2048,7 +2053,7 @@ fn masp_incentives() -> Result<()> { ) }); assert!(captured.result.is_ok()); - assert!(captured.contains("nam: 3.723616")); + assert!(captured.contains("nam: 3.774374")); // Wait till epoch boundary node.next_masp_epoch(); @@ -2099,7 +2104,7 @@ fn masp_incentives() -> Result<()> { ) }); assert!(captured.result.is_ok()); - assert!(captured.contains("nam: 1.451732")); + assert!(captured.contains("nam: 1.502496")); // Assert NAM balance at MASP pool is // the accumulation of rewards from the shielded assets (BTC and ETH) @@ -2119,7 +2124,7 @@ fn masp_incentives() -> Result<()> { ) }); assert!(captured.result.is_ok()); - assert!(captured.contains("nam: 3.723616")); + assert!(captured.contains("nam: 3.774374")); // Wait till epoch boundary to prevent conversion expiry during transaction // construction @@ -2135,7 +2140,7 @@ fn masp_incentives() -> Result<()> { run( &node, Bin::Client, - vec![ + apply_use_device(vec![ "unshield", "--source", B_SPENDING_KEY, @@ -2144,14 +2149,14 @@ fn masp_incentives() -> Result<()> { "--token", NAM, "--amount", - "1.451732", + "1.502496", "--gas-limit", "60000", "--signing-keys", BERTHA_KEY, "--node", validator_one_rpc, - ], + ]), ) }); assert!(captured.result.is_ok()); @@ -2170,7 +2175,7 @@ fn masp_incentives() -> Result<()> { run( &node, Bin::Client, - vec![ + apply_use_device(vec![ "unshield", "--source", A_SPENDING_KEY, @@ -2184,7 +2189,7 @@ fn masp_incentives() -> Result<()> { ALBERT_KEY, "--node", validator_one_rpc, - ], + ]), ) }); assert!(captured.result.is_ok()); @@ -2258,7 +2263,7 @@ fn masp_incentives() -> Result<()> { ) }); assert!(captured.result.is_ok()); - assert!(captured.contains("nam: 0.003222")); + assert!(captured.contains("nam: 0.003216")); Ok(()) } @@ -2287,7 +2292,7 @@ fn spend_unconverted_asset_type() -> Result<()> { run( &node, Bin::Client, - vec![ + apply_use_device(vec![ "shield", "--source", ALBERT, @@ -2299,7 +2304,7 @@ fn spend_unconverted_asset_type() -> Result<()> { "20", "--node", validator_one_rpc, - ], + ]), ) }); assert!(captured.result.is_ok()); @@ -2311,7 +2316,7 @@ fn spend_unconverted_asset_type() -> Result<()> { run( &node, Bin::Client, - vec![ + apply_use_device(vec![ "shield", "--source", ALBERT, @@ -2323,7 +2328,7 @@ fn spend_unconverted_asset_type() -> Result<()> { "0.000001", "--node", validator_one_rpc, - ], + ]), ) }); assert!(captured.result.is_ok()); @@ -2370,7 +2375,7 @@ fn spend_unconverted_asset_type() -> Result<()> { run( &node, Bin::Client, - vec![ + apply_use_device(vec![ "transfer", "--source", B_SPENDING_KEY, @@ -2384,7 +2389,7 @@ fn spend_unconverted_asset_type() -> Result<()> { CHRISTEL_KEY, "--node", validator_one_rpc, - ], + ]), ) }); assert!(captured.result.is_ok()); @@ -2443,7 +2448,7 @@ fn masp_txs_and_queries() -> Result<()> { let txs_args = vec![ // 0. Attempt to spend 10 BTC at SK(A) to PA(B) ( - vec![ + apply_use_device(vec![ "transfer", "--source", A_SPENDING_KEY, @@ -2457,12 +2462,12 @@ fn masp_txs_and_queries() -> Result<()> { CHRISTEL_KEY, "--node", validator_one_rpc, - ], + ]), Response::Err(""), ), // 1. Attempt to spend 15 BTC at SK(A) to Bertha ( - vec![ + apply_use_device(vec![ "unshield", "--source", A_SPENDING_KEY, @@ -2476,12 +2481,12 @@ fn masp_txs_and_queries() -> Result<()> { CHRISTEL_KEY, "--node", validator_one_rpc, - ], + ]), Response::Err(""), ), // 2. Send 20 BTC from Albert to PA(A) ( - vec![ + apply_use_device(vec![ "shield", "--source", ALBERT, @@ -2493,12 +2498,12 @@ fn masp_txs_and_queries() -> Result<()> { "20", "--node", validator_one_rpc, - ], + ]), Response::Ok(TX_APPLIED_SUCCESS), ), // 3. Attempt to spend 10 ETH at SK(A) to PA(B) ( - vec![ + apply_use_device(vec![ "transfer", "--source", A_SPENDING_KEY, @@ -2512,12 +2517,12 @@ fn masp_txs_and_queries() -> Result<()> { CHRISTEL_KEY, "--node", validator_one_rpc, - ], + ]), Response::Err(""), ), // 4. Spend 7 BTC at SK(A) to PA(B) ( - vec![ + apply_use_device(vec![ "transfer", "--source", A_SPENDING_KEY, @@ -2531,12 +2536,12 @@ fn masp_txs_and_queries() -> Result<()> { CHRISTEL_KEY, "--node", validator_one_rpc, - ], + ]), Response::Ok(TX_APPLIED_SUCCESS), ), // 5. Spend 7 BTC at SK(A) to PA(B) ( - vec![ + apply_use_device(vec![ "transfer", "--source", A_SPENDING_KEY, @@ -2550,12 +2555,12 @@ fn masp_txs_and_queries() -> Result<()> { CHRISTEL_KEY, "--node", validator_one_rpc, - ], + ]), Response::Ok(TX_APPLIED_SUCCESS), ), // 6. Attempt to spend 7 BTC at SK(A) to PA(B) ( - vec![ + apply_use_device(vec![ "transfer", "--source", A_SPENDING_KEY, @@ -2569,12 +2574,12 @@ fn masp_txs_and_queries() -> Result<()> { CHRISTEL_KEY, "--node", validator_one_rpc, - ], + ]), Response::Err(""), ), // 7. Spend 6 BTC at SK(A) to PA(B) ( - vec![ + apply_use_device(vec![ "transfer", "--source", A_SPENDING_KEY, @@ -2588,7 +2593,7 @@ fn masp_txs_and_queries() -> Result<()> { CHRISTEL_KEY, "--node", validator_one_rpc, - ], + ]), Response::Ok(TX_APPLIED_SUCCESS), ), // 8. Assert BTC balance at VK(A) is 0 @@ -2632,7 +2637,7 @@ fn masp_txs_and_queries() -> Result<()> { ), // 11. Send 20 BTC from SK(B) to Bertha ( - vec![ + apply_use_device(vec![ "unshield", "--source", B_SPENDING_KEY, @@ -2648,7 +2653,7 @@ fn masp_txs_and_queries() -> Result<()> { CHRISTEL_KEY, "--node", validator_one_rpc, - ], + ]), Response::Ok(TX_APPLIED_SUCCESS), ), ]; @@ -2749,40 +2754,13 @@ fn multiple_unfetched_txs_same_block() -> Result<()> { let (mut node, _services) = setup::setup()?; _ = node.next_epoch(); - // Add the relevant viewing keys to the wallet otherwise the shielded - // context won't precache the masp data - run( - &node, - Bin::Wallet, - vec![ - "add", - "--alias", - "alias_a", - "--value", - AA_VIEWING_KEY, - "--unsafe-dont-encrypt", - ], - )?; - run( - &node, - Bin::Wallet, - vec![ - "add", - "--alias", - "alias_b", - "--value", - AB_VIEWING_KEY, - "--unsafe-dont-encrypt", - ], - )?; - // 1. Shield tokens _ = node.next_epoch(); let captured = CapturedOutput::of(|| { run( &node, Bin::Client, - vec![ + apply_use_device(vec![ "shield", "--source", ALBERT_KEY, @@ -2794,7 +2772,7 @@ fn multiple_unfetched_txs_same_block() -> Result<()> { "100", "--ledger-address", validator_one_rpc, - ], + ]), ) }); assert!(captured.result.is_ok()); @@ -2804,7 +2782,7 @@ fn multiple_unfetched_txs_same_block() -> Result<()> { run( &node, Bin::Client, - vec![ + apply_use_device(vec![ "shield", "--source", ALBERT_KEY, @@ -2816,7 +2794,7 @@ fn multiple_unfetched_txs_same_block() -> Result<()> { "200", "--ledger-address", validator_one_rpc, - ], + ]), ) }); assert!(captured.result.is_ok()); @@ -2826,7 +2804,7 @@ fn multiple_unfetched_txs_same_block() -> Result<()> { run( &node, Bin::Client, - vec![ + apply_use_device(vec![ "shield", "--source", ALBERT_KEY, @@ -2838,11 +2816,12 @@ fn multiple_unfetched_txs_same_block() -> Result<()> { "100", "--ledger-address", validator_one_rpc, - ], + ]), ) }); assert!(captured.result.is_ok()); assert!(captured.contains(TX_APPLIED_SUCCESS)); + // sync shielded context run( &node, @@ -2860,7 +2839,7 @@ fn multiple_unfetched_txs_same_block() -> Result<()> { run( &node, Bin::Client, - vec![ + apply_use_device(vec![ "transfer", "--source", A_SPENDING_KEY, @@ -2877,10 +2856,11 @@ fn multiple_unfetched_txs_same_block() -> Result<()> { "--dump-tx", "--ledger-address", validator_one_rpc, - ], + ]), ) }); assert!(captured.result.is_ok()); + let file_path = tempdir .path() .read_dir() @@ -2896,7 +2876,7 @@ fn multiple_unfetched_txs_same_block() -> Result<()> { run( &node, Bin::Client, - vec![ + apply_use_device(vec![ "transfer", "--source", A_SPENDING_KEY, @@ -2913,10 +2893,11 @@ fn multiple_unfetched_txs_same_block() -> Result<()> { "--dump-tx", "--ledger-address", validator_one_rpc, - ], + ]), ) }); assert!(captured.result.is_ok()); + let file_path = tempdir .path() .read_dir() @@ -2932,7 +2913,7 @@ fn multiple_unfetched_txs_same_block() -> Result<()> { run( &node, Bin::Client, - vec![ + apply_use_device(vec![ "transfer", "--source", B_SPENDING_KEY, @@ -2949,10 +2930,11 @@ fn multiple_unfetched_txs_same_block() -> Result<()> { "--dump-tx", "--ledger-address", validator_one_rpc, - ], + ]), ) }); assert!(captured.result.is_ok()); + let file_path = tempdir .path() .read_dir() @@ -3010,27 +2992,12 @@ fn expired_masp_tx() -> Result<()> { let (mut node, _services) = setup::setup()?; _ = node.next_epoch(); - // Add the relevant viewing keys to the wallet otherwise the shielded - // context won't precache the masp data - run( - &node, - Bin::Wallet, - vec![ - "add", - "--alias", - "alias_a", - "--value", - AA_VIEWING_KEY, - "--unsafe-dont-encrypt", - ], - )?; - // 1. Shield tokens _ = node.next_epoch(); run( &node, Bin::Client, - vec![ + apply_use_device(vec![ "shield", "--source", ALBERT_KEY, @@ -3042,7 +3009,7 @@ fn expired_masp_tx() -> Result<()> { "100", "--ledger-address", validator_one_rpc, - ], + ]), )?; // sync shielded context run( @@ -3060,7 +3027,7 @@ fn expired_masp_tx() -> Result<()> { run( &node, Bin::Client, - vec![ + apply_use_device(vec![ "transfer", "--source", A_SPENDING_KEY, @@ -3089,7 +3056,7 @@ fn expired_masp_tx() -> Result<()> { "--dump-tx", "--ledger-address", validator_one_rpc, - ], + ]), ) }); assert!(captured.result.is_ok()); @@ -3197,7 +3164,7 @@ fn cross_epoch_unshield() -> Result<()> { run( &node, Bin::Client, - vec![ + apply_use_device(vec![ "shield", "--source", ALBERT, @@ -3207,9 +3174,11 @@ fn cross_epoch_unshield() -> Result<()> { NAM, "--amount", "1000", + "--signing-keys", + ALBERT_KEY, "--ledger-address", validator_one_rpc, - ], + ]), ) }); assert!(captured.result.is_ok()); @@ -3234,7 +3203,7 @@ fn cross_epoch_unshield() -> Result<()> { run( &node, Bin::Client, - vec![ + apply_use_device(vec![ "unshield", "--source", A_SPENDING_KEY, @@ -3251,7 +3220,7 @@ fn cross_epoch_unshield() -> Result<()> { "--dump-tx", "--ledger-address", validator_one_rpc, - ], + ]), ) }); assert!(captured.result.is_ok()); @@ -3272,7 +3241,7 @@ fn cross_epoch_unshield() -> Result<()> { run( &node, Bin::Client, - vec![ + apply_use_device(vec![ "tx", "--owner", ALBERT_KEY, @@ -3280,7 +3249,7 @@ fn cross_epoch_unshield() -> Result<()> { tx_path.to_str().unwrap(), "--ledger-address", validator_one_rpc, - ], + ]), ) }); assert!(captured.result.is_ok()); @@ -3344,7 +3313,7 @@ fn dynamic_assets() -> Result<()> { run( &node, Bin::Client, - vec![ + apply_use_device(vec![ "shield", "--source", ALBERT, @@ -3356,11 +3325,12 @@ fn dynamic_assets() -> Result<()> { "1", "--node", validator_one_rpc, - ], + ]), ) }); assert!(captured.result.is_ok()); assert!(captured.contains(TX_APPLIED_SUCCESS)); + // sync the shielded context run( &node, @@ -3479,7 +3449,7 @@ fn dynamic_assets() -> Result<()> { run( &node, Bin::Client, - vec![ + apply_use_device(vec![ "shield", "--source", ALBERT, @@ -3491,11 +3461,12 @@ fn dynamic_assets() -> Result<()> { "1", "--node", validator_one_rpc, - ], + ]), ) }); assert!(captured.result.is_ok()); assert!(captured.contains(TX_APPLIED_SUCCESS)); + // sync the shielded context run( &node, @@ -3939,39 +3910,12 @@ fn masp_fee_payment() -> Result<()> { let (mut node, _services) = setup::setup()?; _ = node.next_masp_epoch(); - // Add the relevant viewing keys to the wallet otherwise the shielded - // context won't precache the masp data - run( - &node, - Bin::Wallet, - vec![ - "add", - "--alias", - "alias_a", - "--value", - AA_VIEWING_KEY, - "--unsafe-dont-encrypt", - ], - )?; - run( - &node, - Bin::Wallet, - vec![ - "add", - "--alias", - "alias_b", - "--value", - AB_VIEWING_KEY, - "--unsafe-dont-encrypt", - ], - )?; - // Shield some tokens let captured = CapturedOutput::of(|| { run( &node, Bin::Client, - vec![ + apply_use_device(vec![ "shield", "--source", ALBERT_KEY, @@ -3985,11 +3929,12 @@ fn masp_fee_payment() -> Result<()> { CHRISTEL_KEY, "--ledger-address", validator_one_rpc, - ], + ]), ) }); assert!(captured.result.is_ok()); assert!(captured.contains(TX_APPLIED_SUCCESS)); + _ = node.next_masp_epoch(); // sync shielded context run( @@ -4020,7 +3965,7 @@ fn masp_fee_payment() -> Result<()> { run( &node, Bin::Client, - vec![ + apply_use_device(vec![ "transfer", "--source", A_SPENDING_KEY, @@ -4039,7 +3984,7 @@ fn masp_fee_payment() -> Result<()> { "--disposable-gas-payer", "--ledger-address", validator_one_rpc, - ], + ]), ) }); assert!(captured.result.is_err()); @@ -4162,7 +4107,7 @@ fn masp_fee_payment() -> Result<()> { run( &node, Bin::Client, - vec![ + apply_use_device(vec![ "transfer", "--source", A_SPENDING_KEY, @@ -4179,11 +4124,12 @@ fn masp_fee_payment() -> Result<()> { "--disposable-gas-payer", "--ledger-address", validator_one_rpc, - ], + ]), ) }); assert!(captured.result.is_ok()); assert!(captured.contains(TX_APPLIED_SUCCESS)); + // sync shielded context run( &node, @@ -4246,39 +4192,12 @@ fn masp_fee_payment_gas_limit() -> Result<()> { })?; _ = node.next_masp_epoch(); - // Add the relevant viewing keys to the wallet otherwise the shielded - // context won't precache the masp data - run( - &node, - Bin::Wallet, - vec![ - "add", - "--alias", - "alias_a", - "--value", - AA_VIEWING_KEY, - "--unsafe-dont-encrypt", - ], - )?; - run( - &node, - Bin::Wallet, - vec![ - "add", - "--alias", - "alias_b", - "--value", - AB_VIEWING_KEY, - "--unsafe-dont-encrypt", - ], - )?; - // Shield some tokens let captured = CapturedOutput::of(|| { run( &node, Bin::Client, - vec![ + apply_use_device(vec![ "shield", "--source", ALBERT_KEY, @@ -4290,7 +4209,7 @@ fn masp_fee_payment_gas_limit() -> Result<()> { "1000000", "--ledger-address", validator_one_rpc, - ], + ]), ) }); assert!(captured.result.is_ok()); @@ -4330,7 +4249,7 @@ fn masp_fee_payment_gas_limit() -> Result<()> { run( &node, Bin::Client, - vec![ + apply_use_device(vec![ "unshield", "--source", A_SPENDING_KEY, @@ -4347,7 +4266,7 @@ fn masp_fee_payment_gas_limit() -> Result<()> { "--disposable-gas-payer", "--ledger-address", validator_one_rpc, - ], + ]), ) }); assert!(captured.result.is_err()); @@ -4394,39 +4313,12 @@ fn masp_fee_payment_with_non_disposable() -> Result<()> { let (mut node, _services) = setup::setup()?; _ = node.next_masp_epoch(); - // Add the relevant viewing keys to the wallet otherwise the shielded - // context won't precache the masp data - run( - &node, - Bin::Wallet, - vec![ - "add", - "--alias", - "alias_a", - "--value", - AA_VIEWING_KEY, - "--unsafe-dont-encrypt", - ], - )?; - run( - &node, - Bin::Wallet, - vec![ - "add", - "--alias", - "alias_b", - "--value", - AB_VIEWING_KEY, - "--unsafe-dont-encrypt", - ], - )?; - // Shield some tokens let captured = CapturedOutput::of(|| { run( &node, Bin::Client, - vec![ + apply_use_device(vec![ "shield", "--source", ALBERT_KEY, @@ -4442,7 +4334,7 @@ fn masp_fee_payment_with_non_disposable() -> Result<()> { BERTHA_KEY, "--ledger-address", validator_one_rpc, - ], + ]), ) }); assert!(captured.result.is_ok()); @@ -4498,7 +4390,7 @@ fn masp_fee_payment_with_non_disposable() -> Result<()> { run( &node, Bin::Client, - vec![ + apply_use_device(vec![ "unshield", "--source", A_SPENDING_KEY, @@ -4518,7 +4410,7 @@ fn masp_fee_payment_with_non_disposable() -> Result<()> { A_SPENDING_KEY, "--ledger-address", validator_one_rpc, - ], + ]), ) }); assert!(captured.result.is_ok()); @@ -4584,51 +4476,12 @@ fn masp_fee_payment_with_custom_spending_key() -> Result<()> { let (mut node, _services) = setup::setup()?; _ = node.next_masp_epoch(); - // Add the relevant viewing keys to the wallet otherwise the shielded - // context won't precache the masp data - run( - &node, - Bin::Wallet, - vec![ - "add", - "--alias", - "alias_a", - "--value", - AA_VIEWING_KEY, - "--unsafe-dont-encrypt", - ], - )?; - run( - &node, - Bin::Wallet, - vec![ - "add", - "--alias", - "alias_b", - "--value", - AB_VIEWING_KEY, - "--unsafe-dont-encrypt", - ], - )?; - run( - &node, - Bin::Wallet, - vec![ - "add", - "--alias", - "alias_c", - "--value", - AC_VIEWING_KEY, - "--unsafe-dont-encrypt", - ], - )?; - // Shield some tokens let captured = CapturedOutput::of(|| { run( &node, Bin::Client, - vec![ + apply_use_device(vec![ "shield", "--source", ALBERT_KEY, @@ -4640,7 +4493,7 @@ fn masp_fee_payment_with_custom_spending_key() -> Result<()> { "10000", "--ledger-address", validator_one_rpc, - ], + ]), ) }); assert!(captured.result.is_ok()); @@ -4649,7 +4502,7 @@ fn masp_fee_payment_with_custom_spending_key() -> Result<()> { run( &node, Bin::Client, - vec![ + apply_use_device(vec![ "shield", "--source", ALBERT_KEY, @@ -4661,7 +4514,7 @@ fn masp_fee_payment_with_custom_spending_key() -> Result<()> { "300000", "--ledger-address", validator_one_rpc, - ], + ]), ) }); assert!(captured.result.is_ok()); @@ -4716,7 +4569,7 @@ fn masp_fee_payment_with_custom_spending_key() -> Result<()> { run( &node, Bin::Client, - vec![ + apply_use_device(vec![ "transfer", "--source", A_SPENDING_KEY, @@ -4735,7 +4588,7 @@ fn masp_fee_payment_with_custom_spending_key() -> Result<()> { "--disposable-gas-payer", "--ledger-address", validator_one_rpc, - ], + ]), ) }); assert!(captured.result.is_ok()); @@ -4825,39 +4678,12 @@ fn masp_fee_payment_with_different_token() -> Result<()> { })?; _ = node.next_masp_epoch(); - // Add the relevant viewing keys to the wallet otherwise the shielded - // context won't precache the masp data - run( - &node, - Bin::Wallet, - vec![ - "add", - "--alias", - "alias_a", - "--value", - AA_VIEWING_KEY, - "--unsafe-dont-encrypt", - ], - )?; - run( - &node, - Bin::Wallet, - vec![ - "add", - "--alias", - "alias_b", - "--value", - AB_VIEWING_KEY, - "--unsafe-dont-encrypt", - ], - )?; - // Shield some tokens let captured = CapturedOutput::of(|| { run( &node, Bin::Client, - vec![ + apply_use_device(vec![ "shield", "--source", ALBERT_KEY, @@ -4869,7 +4695,7 @@ fn masp_fee_payment_with_different_token() -> Result<()> { "1", "--ledger-address", validator_one_rpc, - ], + ]), ) }); assert!(captured.result.is_ok()); @@ -4878,7 +4704,7 @@ fn masp_fee_payment_with_different_token() -> Result<()> { run( &node, Bin::Client, - vec![ + apply_use_device(vec![ "shield", "--source", ALBERT, @@ -4892,7 +4718,7 @@ fn masp_fee_payment_with_different_token() -> Result<()> { ALBERT_KEY, "--ledger-address", validator_one_rpc, - ], + ]), ) }); assert!(captured.result.is_ok()); @@ -4901,7 +4727,7 @@ fn masp_fee_payment_with_different_token() -> Result<()> { run( &node, Bin::Client, - vec![ + apply_use_device(vec![ "shield", "--source", ALBERT, @@ -4915,7 +4741,7 @@ fn masp_fee_payment_with_different_token() -> Result<()> { ALBERT_KEY, "--ledger-address", validator_one_rpc, - ], + ]), ) }); assert!(captured.result.is_ok()); @@ -4987,7 +4813,7 @@ fn masp_fee_payment_with_different_token() -> Result<()> { run( &node, Bin::Client, - vec![ + apply_use_device(vec![ "transfer", "--source", A_SPENDING_KEY, @@ -5008,7 +4834,7 @@ fn masp_fee_payment_with_different_token() -> Result<()> { "--disposable-gas-payer", "--ledger-address", validator_one_rpc, - ], + ]), ) }); assert!(captured.result.is_ok()); @@ -5112,27 +4938,12 @@ fn identical_output_descriptions() -> Result<()> { _ = node.next_masp_epoch(); let tempdir = tempfile::tempdir().unwrap(); - // Add the relevant viewing keys to the wallet otherwise the shielded - // context won't precache the masp data - run( - &node, - Bin::Wallet, - vec![ - "add", - "--alias", - "alias_a", - "--value", - AA_VIEWING_KEY, - "--unsafe-dont-encrypt", - ], - )?; - // Generate a tx to shield some tokens let captured = CapturedOutput::of(|| { run( &node, Bin::Client, - vec![ + apply_use_device(vec![ "shield", "--source", ALBERT_KEY, @@ -5149,10 +4960,11 @@ fn identical_output_descriptions() -> Result<()> { "--dump-wrapper-tx", "--ledger-address", validator_one_rpc, - ], + ]), ) }); assert!(captured.result.is_ok()); + let file_path = tempdir .path() .read_dir() @@ -5308,7 +5120,7 @@ fn identical_output_descriptions() -> Result<()> { run( &node, Bin::Client, - vec![ + apply_use_device(vec![ "unshield", "--source", A_SPENDING_KEY, @@ -5323,7 +5135,7 @@ fn identical_output_descriptions() -> Result<()> { BERTHA_KEY, "--node", validator_one_rpc, - ], + ]), ) }); assert!(captured.result.is_ok()); diff --git a/genesis/hardware/src/pre-genesis/wallet.toml b/genesis/hardware/src/pre-genesis/wallet.toml index 7866cb9c2f..f349cb64cf 100644 --- a/genesis/hardware/src/pre-genesis/wallet.toml +++ b/genesis/hardware/src/pre-genesis/wallet.toml @@ -1,10 +1,17 @@ [birthdays] [view_keys] +albert-svk = "zvknam1qw7ysd8dqyqqpqp3rpe8e66t6y7elv4p5xgqh7904ck0ch87nsu8m3ftxnzzydg6l8q9yuzmczdgp9zjh4w8dtpmr880mn0r6wzefz35zdcucwqc8v2gz5cne222tszq20z9etczeeqs498zpjprfvkjl8uzqxcqp5a7665x6fuxdh8p8mn2haeryp8yjk4np6ka4xsdtmfw2hjwq3s7mk07pc6gjllc0u4yjnwu8fklf40rvcvgwqn6t87x97nd8ajqrgdffayv48q54ghg7" +bertha-svk = "zvknam1qw7ysd8dqgqqpqzvpu7a7edpt7rwfwk4y99f0j4ngvules039mt205ljusd0q5jcf6spkwcdgpruphr54exyxwsuxaxkdpgl60wnpa7vzzrsk3w94rqv3ul03efva6w3kvpucwcrmj8hravjhf0xg8nkyrl865hadhty5ye590gr7xempm62s38yw4nxepytnrjn6mnln7f0qgnhpkj5850nwrvqkpfygvvhy4wp9edm4j4haftmclvxeymcktepjul847klrasr6rctw0mw8" +christel-svk = "zvknam1qw7ysd8dqvqqpqxy9fcc0qc4ntgjz5rxnlds3ywqryel8xk9regvpynx0syfmmq8ngcagfgsd5g0rrlh0ux5trlsepwwlnhes24gx77zk3emft6nyxs6jjp7y6j2gph9h3y3utndzywsa365hfcj2em9svkgguu0hvm3ey4qj3y5hwr37vwmclchx8sztfc7547glxs9nhmtys78ysl5rekdqu8z0lw8cafejwj3ajce3vf86su2pa3pffrgqscmvacsehph82stsucn0r9gu" [spend_keys] [payment_addrs] +albert-pa = "znam1zsdp40r8e52vg33fyd4gg4tkcjvvmj554l24m76zn6404wkklpjluexvrmppz7jkr8t4vvwfyan" +bertha-pa-a = "znam13e60xy9n3ze7w385d00a5hzxp0qvwkg89kvqlv3gpv48h5n5w5d2shgqfjl5q0lp8zp9yx2kqvw" +bertha-pa-b = "znam1dz4wxnjwvyz0ymvptwgp2fkr0fsjsgcum28swj6nm9uajwa8rt0aynf0463q6h8cw4sqsd9rg6g" +christel-pa = "znam14gxuky9uh0md3uj7d3s60e2fwcne0nnu9w562lxjspdfvuawfjxuta4vp2nxv6rr9j72jmqpzf5" [secret_keys] faucet-key = "unencrypted:00548aa8393422b88dce5f4be8ee0320638061c3e0649ada1b0dacbec4c0c75bb2" @@ -22,8 +29,11 @@ frank-key = "ED25519_PK_PREFIXtpknam1qqwfpuvn8x7yqtquejhppef4vddv9ghusec2rkaxav3 [derivation_paths] albert-key = "m/44'/877'/0'/0'/0'" +albert-svk = "m/32'/877'/1'" bertha-key = "m/44'/877'/0'/0'/1'" +bertha-svk = "m/32'/877'/2'" christel-key = "m/44'/877'/0'/0'/2'" +christel-svk = "m/32'/877'/3'" daewon = "m/44'/877'/0'/0'/3'" ester = "m/44'/877'/0'/0'/4'" validator-0-account-key = "m/44'/877'/0'/0'/5'" diff --git a/genesis/localnet/balances.toml b/genesis/localnet/balances.toml index e4db4e5c85..64f5facdbf 100644 --- a/genesis/localnet/balances.toml +++ b/genesis/localnet/balances.toml @@ -33,6 +33,9 @@ tnam1q9vhfdur7gadtwx4r223agpal0fvlqhywylf2mzx = "200000" tnam1qrdrgx6d3rzl2f5yn6nde6wg20sl6kmtug3ecg7z = "200000" # validator-0-account-key tnam1qzwnw8rdyg8c5nrdwrcd87pgdxygr2eyguzy9c44 = "1000000" +# frank +tnam1qx9ggvnemv8j3a7u92r7mktgfq45q4cj3vch6wmn = "2000000" +tnam1qq0345c0vr04wyjfkp0lfqkdp5n0t7ua4cswzkhm = "2000000" [token.BTC] # albert @@ -47,6 +50,8 @@ tnam1qpca48f45pdtpcz06rue7k4kfdcjrvrux5cr3pwn = "1000000" tnam1qpm3dpsv76ttu382vfggtr7m8n00na3sfyzm2g2q = "1000000" # validator-0 tnam1q9vhfdur7gadtwx4r223agpal0fvlqhywylf2mzx = "1000000" +# frank +tnam1qx9ggvnemv8j3a7u92r7mktgfq45q4cj3vch6wmn = "1000000" [token.ETH] # albert @@ -61,6 +66,8 @@ tnam1qpca48f45pdtpcz06rue7k4kfdcjrvrux5cr3pwn = "1000000" tnam1qpm3dpsv76ttu382vfggtr7m8n00na3sfyzm2g2q = "1000000" # validator-0 tnam1q9vhfdur7gadtwx4r223agpal0fvlqhywylf2mzx = "1000000" +# frank +tnam1qx9ggvnemv8j3a7u92r7mktgfq45q4cj3vch6wmn = "1000000" [token.DOT] @@ -76,6 +83,8 @@ tnam1qpca48f45pdtpcz06rue7k4kfdcjrvrux5cr3pwn = "1000000" tnam1qpm3dpsv76ttu382vfggtr7m8n00na3sfyzm2g2q = "1000000" # validator-0 tnam1q9vhfdur7gadtwx4r223agpal0fvlqhywylf2mzx = "1000000" +# frank +tnam1qx9ggvnemv8j3a7u92r7mktgfq45q4cj3vch6wmn = "1000000" [token.Schnitzel] # albert @@ -90,6 +99,8 @@ tnam1qpca48f45pdtpcz06rue7k4kfdcjrvrux5cr3pwn = "1000000" tnam1qpm3dpsv76ttu382vfggtr7m8n00na3sfyzm2g2q = "1000000" # validator-0 tnam1q9vhfdur7gadtwx4r223agpal0fvlqhywylf2mzx = "1000000" +# frank +tnam1qx9ggvnemv8j3a7u92r7mktgfq45q4cj3vch6wmn = "1000000" [token.Apfel] # albert @@ -104,6 +115,8 @@ tnam1qpca48f45pdtpcz06rue7k4kfdcjrvrux5cr3pwn = "1000000" tnam1qpm3dpsv76ttu382vfggtr7m8n00na3sfyzm2g2q = "1000000" # validator-0 tnam1q9vhfdur7gadtwx4r223agpal0fvlqhywylf2mzx = "1000000" +# frank +tnam1qx9ggvnemv8j3a7u92r7mktgfq45q4cj3vch6wmn = "1000000" [token.Kartoffel] # albert @@ -118,3 +131,5 @@ tnam1qpca48f45pdtpcz06rue7k4kfdcjrvrux5cr3pwn = "1000000" tnam1qpm3dpsv76ttu382vfggtr7m8n00na3sfyzm2g2q = "1000000" # validator-0 tnam1q9vhfdur7gadtwx4r223agpal0fvlqhywylf2mzx = "1000000" +# frank +tnam1qx9ggvnemv8j3a7u92r7mktgfq45q4cj3vch6wmn = "1000000" diff --git a/genesis/localnet/src/pre-genesis/unsigned-transactions.toml b/genesis/localnet/src/pre-genesis/unsigned-transactions.toml index 32dc9fff47..784e8846ba 100644 --- a/genesis/localnet/src/pre-genesis/unsigned-transactions.toml +++ b/genesis/localnet/src/pre-genesis/unsigned-transactions.toml @@ -28,6 +28,12 @@ vp = "vp_user" threshold = 1 public_keys = ["tpknam1qqwfpuvn8x7yqtquejhppef4vddv9ghusec2rkaxav38amamxaxpgj9cs79"] +# Frank +[[established_account]] +vp = "vp_user" +threshold = 1 +public_keys = ["tpknam1qz0vuxgzsz5lu7peghyr4yx5tuexecm27hdgglkpe444v6nmy6d8yuxhn0r"] + ########################################################################################## # Albert bonds to `validator-0` diff --git a/genesis/localnet/src/pre-genesis/wallet.toml b/genesis/localnet/src/pre-genesis/wallet.toml index eb231c1e0e..71cac3309f 100644 --- a/genesis/localnet/src/pre-genesis/wallet.toml +++ b/genesis/localnet/src/pre-genesis/wallet.toml @@ -1,10 +1,20 @@ [birthdays] [view_keys] +albert-svk = "zvknam1qdrk9kd8qqqqpqy3pxzxu2kexydl7ug22s3808htl604emmz9qlde9cl9mx6euhvhnc63hymme53jz3mmwrzfkr9tk82nqacf5vlmj9du3s3rjz0h6usnh47pw0ufw4u6yrfvf95wfa9xj0m8pcrns9yh90s0jkf3cqy2z7c3stqp43uk9x2cj79gcxuum8a7jayjqlv4ptcfnunqkqzsj6m2r3sn8ft0tyqqpv28nghe4ag68eccaqx7v5f65he95g5uwq2wr4yuqc8djdrp" +bertha-svk = "zvknam1qdml0zguqqqqpqx8elavks722m0cjelgh3r044cfregyw049jze9lwha2cfqdqnekem0xdqf9ytuhaxzeunyl7svgvxjv5g73m24k7w0h6q7wtvcltvlzynzhc5grlfgv7037lfh8w3su5krnzzzjh4nsleydtlns4gl0vmnc4z2dgrvqy033ymq5ylz3gmf6wdzhsdmzm0h9uv9374x755rzgvmcxhxntu6v63acqktv6zk390e9pd6vr0pzqaq6auu59kwpnw0hacdsfkws" +christel-svk = "zvknam1qdy5g4udqqqqpqrfdzej0s45m8s6nprder4udwqm3ql8wx34e8f46dv8cwnmcjp40lr4vutffut7ed5x6egd6etcdh9sxh3j9fe5dshhrn3nq4yfp78gt8ve59y4vnu45xlt93vtrzsxtwlxjjgu2p496lc3ye8m83qplsqfl6flgjz7wz9wwu9kxd4rth4clw6ug4drxln96y96nf8fmvgm5eddm93azuzlkjj0dpw343ukwcfuvkdhd772539cskgggcqsaaf0j7cfyd3jr" [spend_keys] +albert-svk = "unencrypted:zsknam1qdrk9kd8qqqqpqy3pxzxu2kexydl7ug22s3808htl604emmz9qlde9cl9mx6euhvh3cpl9w7guustfzjxsyaeqtefhden6q8776t9cr9vkqztj7u0mgs5k9nz945sypev9ppptn5d85as3ccsnu3q6g3acqp2gpsrwe6naqg3stqp43uk9x2cj79gcxuum8a7jayjqlv4ptcfnunqkqzsj6m2r3sn8ft0tyqqpv28nghe4ag68eccaqx7v5f65he95g5uwq2wr4yuqc06jgc7" +bertha-svk = "unencrypted:zsknam1qdml0zguqqqqpqx8elavks722m0cjelgh3r044cfregyw049jze9lwha2cfqdqnekecnttdvygd6s784kch2v3wjs45g5z0n36hpqv5ruy8jjfu5mz2snl8ljyz79h3szmyf43zve79l6hwnlfk94r422tfwr2f62vvgkeqvc4z2dgrvqy033ymq5ylz3gmf6wdzhsdmzm0h9uv9374x755rzgvmcxhxntu6v63acqktv6zk390e9pd6vr0pzqaq6auu59kwpnw0haczfyju8" +christel-svk = "unencrypted:zsknam1qdy5g4udqqqqpqrfdzej0s45m8s6nprder4udwqm3ql8wx34e8f46dv8cwnmcjp40uj3qy5tgetj27jytvxk4vpa3pjsd80y332nj542w39wta8lsrzqzs822ydgmz5g2sd2k29hxc3uh77v5cmcext799fxn6sa9rd3zuggl6flgjz7wz9wwu9kxd4rth4clw6ug4drxln96y96nf8fmvgm5eddm93azuzlkjj0dpw343ukwcfuvkdhd772539cskgggcqsaaf0j7czshjwe" [payment_addrs] +albert-pa = "znam1ky620tz7z658cralqt693qpvk42wvth468zp38nqvq2apmex5rfut3dfqm2asrsqv0tc7saqje7" +bertha-pa-a = "znam1zxt8e22uz666ce7hxqpc69yfj3tpd9v26ep2epwn34kvyuwjh98hhre9897shcjj4cnqugwlv4q" +bertha-pa-b = "znam1mqt0ja2zccy70du2d6rcr77jscgq3gkekfvhrqe7zkxa8rr3qsjsrd66gxnrykdmdeh5wmglmcm" +christel-pa = "znam1xv4ml6fp3zqjhw20xj3srd75cq8tyejdst0xweq60c70732ty2chd2v39tllpzf4uf6s66vfm6w" [secret_keys] albert-key = "unencrypted:000d5e9d7d66f0e4307edacde6e6578e31d331bcf234352647d00d20955102d3ce" @@ -13,6 +23,7 @@ christel-key = "unencrypted:00a08de8d33b9798328d2e4476fade49f515dc82754451fc6ef7 daewon = "unencrypted:00d19e226c0e7d123d79f5908b5948d4c461b66a5f8aa95600c28b55ab6f5dc772" ester = "unencrypted:01369093e2035d84f72a7e5a17c89b7a938b5d08cc87b2289805e3afcc66ef9a42" faucet-key = "unencrypted:00548aa8393422b88dce5f4be8ee0320638061c3e0649ada1b0dacbec4c0c75bb2" +frank-key = "unencrypted:00a925a940b1a82fbafd8f4c1e4f49ae697b6f4e71540320c7603f8eef2341158c" validator-0-account-key = "unencrypted:0024204e13c51b26ed9b42c05647bc46b3821bb453e53d194962ede57ce5ec66ac" [public_keys] @@ -22,6 +33,7 @@ christel-key = "ED25519_PK_PREFIXtpknam1qqwfpuvn8x7yqtquejhppef4vddv9ghusec2rkax daewon = "ED25519_PK_PREFIXtpknam1qzz4x4fammhdcfa0g8xw4udkq8s4n6kjhzlxh00ul3da05wuu9wkykqqvjm" ester = "SECP256K1_PK_PREFIXtpknam1qypvqpzu74nafjahlwyq272dj76qq9rz30dulyc94883tmj893mquqs74gxv4" faucet-key = "ED25519_PK_PREFIXtpknam1qzh2d8vk9wvj2j63fa3cvjru9uldpdjctjjxpafl5r8vwwf56pdgyq0vra4" +frank-key = "ED25519_PK_PREFIXtpknam1qz0vuxgzsz5lu7peghyr4yx5tuexecm27hdgglkpe444v6nmy6d8yuxhn0r" validator-0-account-key = "ED25519_PK_PREFIXtpknam1qpg2tsrplvhu3fd7z7tq5ztc2ne3s7e2ahjl2a2cddufrzdyr752g666ytj" [derivation_paths] @@ -37,6 +49,8 @@ daewon = "tnam1qpca48f45pdtpcz06rue7k4kfdcjrvrux5cr3pwn" ester = "tnam1qpm3dpsv76ttu382vfggtr7m8n00na3sfyzm2g2q" faucet-key = "tnam1qzgcl2znamndmku7ujw6e79dmvd4v7rfd5c89dfz" validator-0 = "tnam1q9vhfdur7gadtwx4r223agpal0fvlqhywylf2mzx" +frank = "tnam1qx9ggvnemv8j3a7u92r7mktgfq45q4cj3vch6wmn" +frank-key = "tnam1qq0345c0vr04wyjfkp0lfqkdp5n0t7ua4cswzkhm" [pkhs] 30A4674B47A0F8CFF0BC8746F8AD012438C7BD3A = "bertha-key" @@ -46,5 +60,6 @@ C671BDF31A7552BD2928909151461CD376CBBE18 = "albert-key" 9F36671A3EB250DA0724EFBA35A03DB3E92B3925 = "christel-key" 7716860CF696BE44EA6250858FDB3CDEF9F63049 = "ester" 9D371C6D220F8A4C6D70F0D3F828698881AB2447 = "validator-0-account-key" +1F1AD30F60DF571249B05FF482CD0D26F5FB9DAE = "frank-key" [address_vp_types] From 2d8c41ce2eb23639cb4057467e7e831ed62bb6e5 Mon Sep 17 00:00:00 2001 From: Murisi Tarusenga Date: Sun, 29 Sep 2024 18:33:57 +0200 Subject: [PATCH 07/12] Dont do a dry run if using a device in the MASP integration tests. --- crates/tests/src/integration/masp.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/crates/tests/src/integration/masp.rs b/crates/tests/src/integration/masp.rs index f2868b34ba..90411a2393 100644 --- a/crates/tests/src/integration/masp.rs +++ b/crates/tests/src/integration/masp.rs @@ -3,9 +3,7 @@ use std::str::FromStr; use color_eyre::eyre::Result; use color_eyre::owo_colors::OwoColorize; -use namada_apps_lib::wallet::defaults::{ - albert_keypair, bertha_keypair, christel_keypair, -}; +use namada_apps_lib::wallet::defaults::{albert_keypair, bertha_keypair, christel_keypair, is_use_device}; use namada_core::address::Address; use namada_core::dec::Dec; use namada_core::masp::{MaspTxId, TokenMap}; @@ -2677,7 +2675,10 @@ fn masp_txs_and_queries() -> Result<()> { Bin::Client, vec!["shielded-sync", "--node", validator_one_rpc], )?; - let tx_args = if dry_run { + let tx_args = if dry_run && is_use_device() + { + continue; + } else if dry_run { [tx_args.clone(), vec!["--dry-run"]].concat() } else { tx_args.clone() From 3e72fe16caa30948b1051254332b95693f8fc411 Mon Sep 17 00:00:00 2001 From: Murisi Tarusenga Date: Mon, 30 Sep 2024 12:52:19 +0200 Subject: [PATCH 08/12] Always sign MASP Transactions before dumping because randomness parameters cannot be reused. Fixed MASP integration tests depending on access to secret keys. --- crates/apps_lib/src/client/tx.rs | 6 +- crates/apps_lib/src/wallet/defaults.rs | 13 +- crates/tests/src/integration/helpers.rs | 64 ++++++++ crates/tests/src/integration/masp.rs | 151 +++++++++++------- .../established-account-tx-frank.toml | 4 + .../src/pre-genesis/signed-transactions.toml | 5 + genesis/localnet/transactions.toml | 5 + 7 files changed, 184 insertions(+), 64 deletions(-) create mode 100644 genesis/localnet/src/pre-genesis/established/established-account-tx-frank.toml diff --git a/crates/apps_lib/src/client/tx.rs b/crates/apps_lib/src/client/tx.rs index 30385e67a1..d9e002ba0c 100644 --- a/crates/apps_lib/src/client/tx.rs +++ b/crates/apps_lib/src/client/tx.rs @@ -1188,6 +1188,7 @@ pub async fn submit_shielded_transfer( .await?; let (mut tx, signing_data) = args.clone().build(namada, &mut bparams).await?; + masp_sign(&mut tx, &args.tx, &signing_data, shielded_hw_keys).await?; let masp_section = tx .sections @@ -1202,7 +1203,6 @@ pub async fn submit_shielded_transfer( tx::dump_tx(namada.io(), &args.tx, tx)?; pre_cache_masp_data(namada, &masp_section).await; } else { - masp_sign(&mut tx, &args.tx, &signing_data, shielded_hw_keys).await?; sign(namada, &mut tx, &args.tx, signing_data).await?; let res = namada.submit(tx, &args.tx).await?; pre_cache_masp_data_on_tx_result(namada, &res, &masp_section).await; @@ -1300,6 +1300,7 @@ pub async fn submit_unshielding_transfer( .await?; let (mut tx, signing_data) = args.clone().build(namada, &mut bparams).await?; + masp_sign(&mut tx, &args.tx, &signing_data, shielded_hw_keys).await?; let masp_section = tx .sections @@ -1314,7 +1315,6 @@ pub async fn submit_unshielding_transfer( tx::dump_tx(namada.io(), &args.tx, tx)?; pre_cache_masp_data(namada, &masp_section).await; } else { - masp_sign(&mut tx, &args.tx, &signing_data, shielded_hw_keys).await?; sign(namada, &mut tx, &args.tx, signing_data).await?; let res = namada.submit(tx, &args.tx).await?; pre_cache_masp_data_on_tx_result(namada, &res, &masp_section).await; @@ -1344,6 +1344,7 @@ where ) .await?; let (mut tx, signing_data, _) = args.build(namada, &mut bparams).await?; + masp_sign(&mut tx, &args.tx, &signing_data, shielded_hw_keys).await?; let opt_masp_section = tx.sections.iter().find_map(|section| section.masp_tx()); @@ -1353,7 +1354,6 @@ where pre_cache_masp_data(namada, &masp_section).await; } } else { - masp_sign(&mut tx, &args.tx, &signing_data, shielded_hw_keys).await?; let res = batch_opt_reveal_pk_and_submit( namada, &args.tx, diff --git a/crates/apps_lib/src/wallet/defaults.rs b/crates/apps_lib/src/wallet/defaults.rs index 9a97a60ff3..b2dd13b4d0 100644 --- a/crates/apps_lib/src/wallet/defaults.rs +++ b/crates/apps_lib/src/wallet/defaults.rs @@ -4,9 +4,10 @@ pub use dev::{ addresses, albert_address, albert_keypair, bertha_address, bertha_keypair, christel_address, christel_keypair, daewon_address, daewon_keypair, - derive_template_dir, ester_address, ester_keypair, get_unencrypted_keypair, - is_use_device, keys, tokens, validator_account_keypair, validator_address, - validator_keypair, validator_keys, + derive_template_dir, ester_address, ester_keypair, frank_keypair, + get_unencrypted_keypair, is_use_device, keys, tokens, + validator_account_keypair, validator_address, validator_keypair, + validator_keys, }; #[cfg(any(test, feature = "testing", feature = "benches"))] @@ -46,6 +47,7 @@ mod dev { ("albert".into(), albert_keypair()), ("bertha".into(), bertha_keypair()), ("christel".into(), christel_keypair()), + ("frank".into(), frank_keypair()), ("daewon".into(), daewon_keypair()), ("ester".into(), ester_keypair()), ("validator".into(), validator_keypair()), @@ -175,6 +177,11 @@ mod dev { get_unencrypted_keypair("ester") } + /// Get frank's keypair from the pre-genesis wallet. + pub fn frank_keypair() -> common::SecretKey { + get_unencrypted_keypair("frank-key") + } + /// Get the validator consensus keypair from the wallet. pub fn validator_keypair() -> common::SecretKey { VALIDATOR_WALLET.consensus_key.clone() diff --git a/crates/tests/src/integration/helpers.rs b/crates/tests/src/integration/helpers.rs index 487ffab972..f142362583 100644 --- a/crates/tests/src/integration/helpers.rs +++ b/crates/tests/src/integration/helpers.rs @@ -7,6 +7,8 @@ use namada_node::shell::testing::client::run; use namada_node::shell::testing::node::MockNode; use namada_node::shell::testing::utils::{Bin, CapturedOutput}; use namada_sdk::key::common; +use crate::e2e::setup::constants::{FRANK, FRANK_KEY}; +use crate::strings::TX_APPLIED_SUCCESS; /// Query the wallet to get an address from a given alias. pub fn find_address( @@ -78,6 +80,68 @@ pub fn find_keypair( }) } +// Make a temporary account with the given balance and return its key. This +// function is useful because the integration tests can no longer assume that +// the secret keys are accessible. +pub fn make_temp_account( + node: &MockNode, + ledger_address: &str, + key_alias: impl AsRef, + token: impl AsRef, + amount: u64, +) -> eyre::Result<(impl AsRef, common::SecretKey)> { + // a. Generate a new key for an implicit account. + run( + node, + Bin::Wallet, + vec![ + "gen", + "--alias", + key_alias.as_ref(), + "--unsafe-dont-encrypt", + "--raw", + ], + )?; + // b. Reveal the public key associated with an address + let reveal_args = vec![ + "reveal-pk", + "--public-key", + key_alias.as_ref(), + "--gas-payer", + FRANK_KEY, + "--node", + ledger_address, + ]; + let captured = + CapturedOutput::of(|| run(node, Bin::Client, reveal_args)); + assert!(captured.result.is_ok()); + assert!(captured.contains(TX_APPLIED_SUCCESS)); + // c. Send some funds to the implicit account. + let amount = amount.to_string(); + let credit_args = vec![ + "transparent-transfer", + "--source", + FRANK, + "--target", + key_alias.as_ref(), + "--token", + token.as_ref(), + "--amount", + &amount, + "--signing-keys", + FRANK_KEY, + "--node", + ledger_address, + ]; + let captured = + CapturedOutput::of(|| run(node, Bin::Client, credit_args)); + assert!(captured.result.is_ok()); + assert!(captured.contains(TX_APPLIED_SUCCESS)); + // d. Obtain the key pair associated with the new address + let keypair = find_keypair(node, key_alias.as_ref())?; + Ok((key_alias, keypair)) +} + fn strip_trailing_newline(input: &str) -> &str { input .strip_suffix("\r\n") diff --git a/crates/tests/src/integration/masp.rs b/crates/tests/src/integration/masp.rs index 90411a2393..4030b89f2a 100644 --- a/crates/tests/src/integration/masp.rs +++ b/crates/tests/src/integration/masp.rs @@ -3,8 +3,10 @@ use std::str::FromStr; use color_eyre::eyre::Result; use color_eyre::owo_colors::OwoColorize; -use namada_apps_lib::wallet::defaults::{albert_keypair, bertha_keypair, christel_keypair, is_use_device}; use namada_core::address::Address; +use namada_apps_lib::wallet::defaults::{ + get_unencrypted_keypair, is_use_device, +}; use namada_core::dec::Dec; use namada_core::masp::{MaspTxId, TokenMap}; use namada_node::shell::testing::client::run; @@ -22,13 +24,14 @@ use namada_sdk::{tx, DEFAULT_GAS_LIMIT}; use test_log::test; use super::{helpers, setup}; -use crate::e2e::setup::apply_use_device; use crate::e2e::setup::constants::{ AA_PAYMENT_ADDRESS, AA_VIEWING_KEY, AB_PAYMENT_ADDRESS, AB_VIEWING_KEY, AC_PAYMENT_ADDRESS, AC_VIEWING_KEY, ALBERT, ALBERT_KEY, A_SPENDING_KEY, BB_PAYMENT_ADDRESS, BERTHA, BERTHA_KEY, BTC, B_SPENDING_KEY, CHRISTEL, - CHRISTEL_KEY, C_SPENDING_KEY, ETH, MASP, NAM, + CHRISTEL_KEY, C_SPENDING_KEY, ETH, FRANK_KEY, MASP, NAM, }; +use crate::e2e::setup::{apply_use_device, ensure_hot_key}; +use crate::integration::helpers::make_temp_account; use crate::strings::TX_APPLIED_SUCCESS; /// Enable masp rewards before some token is shielded, @@ -2675,8 +2678,7 @@ fn masp_txs_and_queries() -> Result<()> { Bin::Client, vec!["shielded-sync", "--node", validator_one_rpc], )?; - let tx_args = if dry_run && is_use_device() - { + let tx_args = if dry_run && is_use_device() { continue; } else if dry_run { [tx_args.clone(), vec!["--dry-run"]].concat() @@ -2947,7 +2949,9 @@ fn multiple_unfetched_txs_same_block() -> Result<()> { txs_bytes.push(std::fs::read(&file_path).unwrap()); std::fs::remove_file(&file_path).unwrap(); - let sk = christel_keypair(); + let sk = get_unencrypted_keypair( + &ensure_hot_key(CHRISTEL_KEY).to_ascii_lowercase(), + ); let pk = sk.to_public(); let native_token = node @@ -3073,7 +3077,9 @@ fn expired_masp_tx() -> Result<()> { let tx_bytes = std::fs::read(&file_path).unwrap(); std::fs::remove_file(&file_path).unwrap(); - let sk = christel_keypair(); + let sk = get_unencrypted_keypair( + &ensure_hot_key(CHRISTEL_KEY).to_ascii_lowercase(), + ); let pk = sk.to_public(); let native_token = node @@ -4947,7 +4953,7 @@ fn identical_output_descriptions() -> Result<()> { apply_use_device(vec![ "shield", "--source", - ALBERT_KEY, + ensure_hot_key(ALBERT_KEY), "--target", AA_PAYMENT_ADDRESS, "--token", @@ -4955,7 +4961,7 @@ fn identical_output_descriptions() -> Result<()> { "--amount", "1000", "--gas-payer", - BERTHA_KEY, + ensure_hot_key(ALBERT_KEY), "--output-folder-path", tempdir.path().to_str().unwrap(), "--dump-wrapper-tx", @@ -4983,12 +4989,15 @@ fn identical_output_descriptions() -> Result<()> { let mut tx_clone = tx.clone(); tx_clone.add_memo(&[1, 2, 3]); + let keypair = get_unencrypted_keypair( + &ensure_hot_key(ALBERT_KEY).to_ascii_lowercase(), + ); let signing_data = SigningTxData { owner: None, - public_keys: vec![albert_keypair().to_public()], + public_keys: vec![keypair.to_public()], threshold: 1, account_public_keys_map: None, - fee_payer: albert_keypair().to_public(), + fee_payer: keypair.to_public(), shielded_hash: None, }; @@ -4999,13 +5008,13 @@ fn identical_output_descriptions() -> Result<()> { .unwrap(); batched_tx.sign_raw( - vec![albert_keypair()], + vec![keypair.clone()], AccountPublicKeysMap::from_iter( - vec![(albert_keypair().to_public())].into_iter(), + vec![(keypair.to_public())].into_iter(), ), None, ); - batched_tx.sign_wrapper(bertha_keypair()); + batched_tx.sign_wrapper(keypair); let wrapper_hash = batched_tx.wrapper_hash(); let inner_cmts = batched_tx.commitments(); @@ -5206,11 +5215,19 @@ fn masp_batch() -> Result<()> { _ = node.next_masp_epoch(); let tempdir = tempfile::tempdir().unwrap(); + // Initialize accounts we can access the secret keys of + let (adam_alias, adam_key) = + make_temp_account(&node, validator_one_rpc, "Adam", NAM, 500_000)?; + let (bradley_alias, _bradley_key) = + make_temp_account(&node, validator_one_rpc, "Bradley", NAM, 500_000)?; + let (cooper_alias, cooper_key) = + make_temp_account(&node, validator_one_rpc, "Cooper", NAM, 500_000)?; + // Assert reference NAM balances at VK(A), Albert and Bertha for (owner, balance) in [ (AA_VIEWING_KEY, 0), - (ALBERT_KEY, 2_000_000), - (BERTHA_KEY, 2_000_000), + (adam_alias.as_ref(), 500_000), + (bradley_alias.as_ref(), 500_000), ] { let captured = CapturedOutput::of(|| { run( @@ -5234,7 +5251,7 @@ fn masp_batch() -> Result<()> { // Generate txs for the batch to shield some tokens. Use two different // sources let mut batch = vec![]; - for source in [ALBERT_KEY, BERTHA_KEY] { + for source in [adam_alias.as_ref(), bradley_alias.as_ref()] { let captured = CapturedOutput::of(|| { run( &node, @@ -5252,7 +5269,7 @@ fn masp_batch() -> Result<()> { "--gas-limit", "60000", "--gas-payer", - CHRISTEL_KEY, + cooper_alias.as_ref(), "--output-folder-path", tempdir.path().to_str().unwrap(), "--dump-wrapper-tx", @@ -5281,10 +5298,10 @@ fn masp_batch() -> Result<()> { let signing_data = SigningTxData { owner: None, - public_keys: vec![albert_keypair().to_public()], + public_keys: vec![adam_key.to_public()], threshold: 1, account_public_keys_map: None, - fee_payer: albert_keypair().to_public(), + fee_payer: adam_key.to_public(), shielded_hash: None, }; @@ -5312,13 +5329,13 @@ fn masp_batch() -> Result<()> { // Sign the batch with just the signer of one tx to force the failure of // the other one batched_tx.sign_raw( - vec![albert_keypair()], + vec![adam_key.clone()], AccountPublicKeysMap::from_iter( - vec![(albert_keypair().to_public())].into_iter(), + vec![(adam_key.to_public())].into_iter(), ), None, ); - batched_tx.sign_wrapper(christel_keypair()); + batched_tx.sign_wrapper(cooper_key.clone()); wrapper_hashes.push(batched_tx.wrapper_hash()); for cmt in batched_tx.commitments() { @@ -5406,11 +5423,11 @@ fn masp_batch() -> Result<()> { ], )?; - // Assert NAM balances at VK(A), Albert and Bertha + // Assert NAM balances at VK(A), Bob and Bertha for (owner, balance) in [ (AA_VIEWING_KEY, 2_000), - (ALBERT_KEY, 1_998_000), - (BERTHA_KEY, 2_000_000), + (adam_alias.as_ref(), 498_000), + (bradley_alias.as_ref(), 500_000), ] { let captured = CapturedOutput::of(|| { run( @@ -5448,11 +5465,19 @@ fn masp_atomic_batch() -> Result<()> { _ = node.next_masp_epoch(); let tempdir = tempfile::tempdir().unwrap(); + // Initialize accounts we can access the secret keys of + let (adam_alias, adam_key) = + make_temp_account(&node, validator_one_rpc, "Adam", NAM, 500_000)?; + let (bradley_alias, _bradley_key) = + make_temp_account(&node, validator_one_rpc, "Bradley", NAM, 500_000)?; + let (cooper_alias, cooper_key) = + make_temp_account(&node, validator_one_rpc, "Cooper", NAM, 500_000)?; + // Assert reference NAM balances at VK(A), Albert and Bertha are unchanged for (owner, balance) in [ (AA_VIEWING_KEY, 0), - (ALBERT_KEY, 2_000_000), - (BERTHA_KEY, 2_000_000), + (adam_alias.as_ref(), 500_000), + (bradley_alias.as_ref(), 500_000), ] { let captured = CapturedOutput::of(|| { run( @@ -5476,7 +5501,7 @@ fn masp_atomic_batch() -> Result<()> { // Generate txs for the batch to shield some tokens. Use two different // sources let mut batch = vec![]; - for source in [ALBERT_KEY, BERTHA_KEY] { + for source in [adam_alias.as_ref(), bradley_alias.as_ref()] { let captured = CapturedOutput::of(|| { run( &node, @@ -5494,7 +5519,7 @@ fn masp_atomic_batch() -> Result<()> { "--gas-limit", "60000", "--gas-payer", - CHRISTEL_KEY, + cooper_alias.as_ref(), "--output-folder-path", tempdir.path().to_str().unwrap(), "--dump-wrapper-tx", @@ -5522,10 +5547,10 @@ fn masp_atomic_batch() -> Result<()> { let signing_data = SigningTxData { owner: None, - public_keys: vec![albert_keypair().to_public()], + public_keys: vec![adam_key.to_public()], threshold: 1, account_public_keys_map: None, - fee_payer: albert_keypair().to_public(), + fee_payer: adam_key.to_public(), shielded_hash: None, }; @@ -5553,13 +5578,13 @@ fn masp_atomic_batch() -> Result<()> { // Sign the batch with just the signer of one tx to force the failure of // the other one batched_tx.sign_raw( - vec![albert_keypair()], + vec![adam_key.clone()], AccountPublicKeysMap::from_iter( - vec![(albert_keypair().to_public())].into_iter(), + vec![(adam_key.to_public())].into_iter(), ), None, ); - batched_tx.sign_wrapper(christel_keypair()); + batched_tx.sign_wrapper(cooper_key.clone()); wrapper_hashes.push(batched_tx.wrapper_hash()); for cmt in batched_tx.commitments() { @@ -5647,8 +5672,8 @@ fn masp_atomic_batch() -> Result<()> { // Assert NAM balances at VK(A), Albert and Bertha are unchanged for (owner, balance) in [ (AA_VIEWING_KEY, 0), - (ALBERT_KEY, 2_000_000), - (BERTHA_KEY, 2_000_000), + (adam_alias.as_ref(), 500_000), + (bradley_alias.as_ref(), 500_000), ] { let captured = CapturedOutput::of(|| { run( @@ -5687,13 +5712,23 @@ fn tricky_masp_txs() -> Result<()> { _ = node.next_masp_epoch(); let tempdir = tempfile::tempdir().unwrap(); + // Initialize accounts we can access the secret keys of + let (adam_alias, _adam_key) = + make_temp_account(&node, validator_one_rpc, "Adam", NAM, 500_000)?; + let (arthur_alias, arthur_key) = + make_temp_account(&node, validator_one_rpc, "Arthur", NAM, 500_000)?; + let (bradley_alias, bradley_key) = + make_temp_account(&node, validator_one_rpc, "Bradley", NAM, 500_000)?; + let (cooper_alias, _cooper_key) = + make_temp_account(&node, validator_one_rpc, "Cooper", NAM, 500_000)?; + // Assert reference NAM balances at VK(A), Albert, Bertha and Christel for (owner, balance) in [ (AA_VIEWING_KEY, 0), - (ALBERT_KEY, 2_000_000), - (BERTHA_KEY, 2_000_000), - (ALBERT, 1_980_000), - (CHRISTEL, 2_000_000), + (arthur_alias.as_ref(), 500_000), + (bradley_alias.as_ref(), 500_000), + (adam_alias.as_ref(), 500_000), + (cooper_alias.as_ref(), 500_000), ] { let captured = CapturedOutput::of(|| { run( @@ -5722,7 +5757,7 @@ fn tricky_masp_txs() -> Result<()> { vec![ "shield", "--source", - ALBERT, + adam_alias.as_ref(), "--target", AA_PAYMENT_ADDRESS, "--token", @@ -5730,7 +5765,7 @@ fn tricky_masp_txs() -> Result<()> { "--amount", "1000", "--gas-payer", - CHRISTEL_KEY, + cooper_alias.as_ref(), "--output-folder-path", tempdir.path().to_str().unwrap(), "--dump-tx", @@ -5766,15 +5801,15 @@ fn tricky_masp_txs() -> Result<()> { vec![ "transparent-transfer", "--source", - ALBERT_KEY, + arthur_alias.as_ref(), "--target", - CHRISTEL, + cooper_alias.as_ref(), "--token", NAM, "--amount", "1000", "--gas-payer", - CHRISTEL_KEY, + FRANK_KEY, "--output-folder-path", tempdir.path().to_str().unwrap(), "--dump-wrapper-tx", @@ -5801,13 +5836,13 @@ fn tricky_masp_txs() -> Result<()> { tx0.add_masp_tx_section(masp_transaction.clone()); tx0.sign_raw( - vec![albert_keypair()], + vec![arthur_key.clone()], AccountPublicKeysMap::from_iter( - vec![(albert_keypair().to_public())].into_iter(), + vec![(arthur_key.to_public())].into_iter(), ), None, ); - tx0.sign_wrapper(christel_keypair()); + tx0.sign_wrapper(get_unencrypted_keypair("frank-key")); // Generate second tx let captured = CapturedOutput::of(|| { @@ -5817,7 +5852,7 @@ fn tricky_masp_txs() -> Result<()> { vec![ "shield", "--source", - BERTHA_KEY, + bradley_alias.as_ref(), "--target", AA_PAYMENT_ADDRESS, "--token", @@ -5825,7 +5860,7 @@ fn tricky_masp_txs() -> Result<()> { "--amount", "1000", "--gas-payer", - CHRISTEL_KEY, + FRANK_KEY, "--output-folder-path", tempdir.path().to_str().unwrap(), "--dump-wrapper-tx", @@ -5852,13 +5887,13 @@ fn tricky_masp_txs() -> Result<()> { tx1.add_masp_tx_section(masp_transaction); tx1.sign_raw( - vec![bertha_keypair()], + vec![bradley_key.clone()], AccountPublicKeysMap::from_iter( - vec![(bertha_keypair().to_public())].into_iter(), + vec![(bradley_key.to_public())].into_iter(), ), None, ); - tx1.sign_wrapper(christel_keypair()); + tx1.sign_wrapper(get_unencrypted_keypair("frank-key")); let txs = vec![tx0.to_bytes(), tx1.to_bytes()]; node.clear_results(); @@ -5881,10 +5916,10 @@ fn tricky_masp_txs() -> Result<()> { // Assert NAM balances at VK(A), Albert, Bertha and Christel for (owner, balance) in [ (AA_VIEWING_KEY, 1_000), - (ALBERT_KEY, 1_999_000), - (BERTHA_KEY, 1_999_000), - (ALBERT, 1_980_000), - (CHRISTEL, 2_001_000), + (arthur_alias.as_ref(), 499_000), + (bradley_alias.as_ref(), 499_000), + (adam_alias.as_ref(), 500_000), + (cooper_alias.as_ref(), 501_000), ] { let captured = CapturedOutput::of(|| { run( diff --git a/genesis/localnet/src/pre-genesis/established/established-account-tx-frank.toml b/genesis/localnet/src/pre-genesis/established/established-account-tx-frank.toml new file mode 100644 index 0000000000..7e3dbfc6f6 --- /dev/null +++ b/genesis/localnet/src/pre-genesis/established/established-account-tx-frank.toml @@ -0,0 +1,4 @@ +[[established_account]] +vp = "vp_user" +threshold = 1 +public_keys = ["tpknam1qz0vuxgzsz5lu7peghyr4yx5tuexecm27hdgglkpe444v6nmy6d8yuxhn0r"] diff --git a/genesis/localnet/src/pre-genesis/signed-transactions.toml b/genesis/localnet/src/pre-genesis/signed-transactions.toml index ba13452927..2ede877849 100644 --- a/genesis/localnet/src/pre-genesis/signed-transactions.toml +++ b/genesis/localnet/src/pre-genesis/signed-transactions.toml @@ -1,3 +1,8 @@ +[[established_account]] +vp = "vp_user" +threshold = 1 +public_keys = ["tpknam1qz0vuxgzsz5lu7peghyr4yx5tuexecm27hdgglkpe444v6nmy6d8yuxhn0r"] + [[established_account]] vp = "vp_user" threshold = 1 diff --git a/genesis/localnet/transactions.toml b/genesis/localnet/transactions.toml index 8447b9e471..7e990f1544 100644 --- a/genesis/localnet/transactions.toml +++ b/genesis/localnet/transactions.toml @@ -53,6 +53,11 @@ tpknam1qpg2tsrplvhu3fd7z7tq5ztc2ne3s7e2ahjl2a2cddufrzdyr752g666ytj = "signam1qpk # 2. +[[established_account]] +vp = "vp_user" +threshold = 1 +public_keys = ["tpknam1qz0vuxgzsz5lu7peghyr4yx5tuexecm27hdgglkpe444v6nmy6d8yuxhn0r"] + [[established_account]] vp = "vp_user" threshold = 1 From fd48de21f68e04615ba125e315e646c79f57cdd5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Zemanovi=C4=8D?= Date: Thu, 3 Oct 2024 13:58:07 +0100 Subject: [PATCH 09/12] test/e2e/masp: add support for testing with HW wallet --- crates/tests/src/e2e/ledger_tests.rs | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/crates/tests/src/e2e/ledger_tests.rs b/crates/tests/src/e2e/ledger_tests.rs index cdccd01470..973dfb9f33 100644 --- a/crates/tests/src/e2e/ledger_tests.rs +++ b/crates/tests/src/e2e/ledger_tests.rs @@ -28,6 +28,7 @@ use namada_apps_lib::config::utils::convert_tm_addr_to_socket_addr; use namada_apps_lib::config::{self, ethereum_bridge}; use namada_apps_lib::tendermint_config::net::Address as TendermintAddress; use namada_apps_lib::wallet::{self, Alias}; +use namada_apps_lib::wallet::defaults::is_use_device; use namada_core::chain::ChainId; use namada_core::token::NATIVE_MAX_DECIMAL_PLACES; use namada_sdk::address::Address; @@ -2508,7 +2509,7 @@ fn masp_txs_and_queries() -> Result<()> { let txs_args = vec![ // 2. Shield 20 BTC from Albert to PA(A) ( - vec![ + apply_use_device(vec![ "shield", "--source", ALBERT, @@ -2518,12 +2519,12 @@ fn masp_txs_and_queries() -> Result<()> { BTC, "--amount", "20", - ], + ]), TX_APPLIED_SUCCESS, ), // 3. Transfer 7 BTC from SK(A) to PA(B) ( - vec![ + apply_use_device(vec![ "transfer", "--source", A_SPENDING_KEY, @@ -2535,7 +2536,7 @@ fn masp_txs_and_queries() -> Result<()> { "7", "--gas-payer", CHRISTEL_KEY, - ], + ]), TX_APPLIED_SUCCESS, ), // 4. Assert BTC balance at VK(A) is 13 @@ -2545,7 +2546,7 @@ fn masp_txs_and_queries() -> Result<()> { ), // 5. Unshield 5 BTC from SK(B) to Bertha ( - vec![ + apply_use_device(vec![ "unshield", "--source", B_SPENDING_KEY, @@ -2557,7 +2558,7 @@ fn masp_txs_and_queries() -> Result<()> { "5", "--gas-payer", CHRISTEL_KEY, - ], + ]), TX_APPLIED_SUCCESS, ), // 6. Assert BTC balance at VK(B) is 2 @@ -2578,6 +2579,9 @@ fn masp_txs_and_queries() -> Result<()> { )?; sync.assert_success(); for &dry_run in &[true, false] { + if dry_run && is_use_device() { + continue; + } let tx_args = if dry_run && (tx_args[0] == "transfer" || tx_args[0] == "shield" From bdd8e9fe44dac28556aee36ca29be992cd931ba4 Mon Sep 17 00:00:00 2001 From: Murisi Tarusenga Date: Tue, 29 Oct 2024 20:17:09 +0200 Subject: [PATCH 10/12] Sometimes use literals instead of aliases in the IBC tests. --- crates/sdk/src/lib.rs | 2 +- crates/sdk/src/tx.rs | 2 +- .../src/masp/shielded_wallet.rs | 2 +- crates/tests/src/e2e/helpers.rs | 26 +++++++++++++++++++ crates/tests/src/e2e/ibc_tests.rs | 18 ++++++++----- 5 files changed, 41 insertions(+), 9 deletions(-) diff --git a/crates/sdk/src/lib.rs b/crates/sdk/src/lib.rs index f1471e0abf..52f0eb3398 100644 --- a/crates/sdk/src/lib.rs +++ b/crates/sdk/src/lib.rs @@ -862,7 +862,7 @@ pub mod testing { use namada_core::address::testing::{ arb_established_address, arb_non_internal_address, }; - use namada_core::collections::HashMap; + use namada_core::collections::{HashMap, HashSet}; use namada_core::eth_bridge_pool::PendingTransfer; use namada_core::hash::testing::arb_hash; use namada_core::key::testing::arb_common_keypair; diff --git a/crates/sdk/src/tx.rs b/crates/sdk/src/tx.rs index e6f7e9363a..ba8b7e16a4 100644 --- a/crates/sdk/src/tx.rs +++ b/crates/sdk/src/tx.rs @@ -20,7 +20,7 @@ use masp_primitives::transaction::components::transparent::fees::{ InputView as TransparentInputView, OutputView as TransparentOutputView, }; use masp_primitives::transaction::components::I128Sum; -use masp_primitives::transaction::{builder, Transaction as MaspTransaction}; +use masp_primitives::transaction::Transaction as MaspTransaction; use masp_primitives::zip32::PseudoExtendedKey; use namada_account::{InitAccount, UpdateAccount}; use namada_core::address::{Address, IBC, MASP}; diff --git a/crates/shielded_token/src/masp/shielded_wallet.rs b/crates/shielded_token/src/masp/shielded_wallet.rs index 724f5e3165..a8fd36aaea 100644 --- a/crates/shielded_token/src/masp/shielded_wallet.rs +++ b/crates/shielded_token/src/masp/shielded_wallet.rs @@ -50,7 +50,7 @@ use rand_core::{OsRng, SeedableRng}; use crate::masp::utils::MaspClient; use crate::masp::{ - cloned_pair, to_viewing_key, ContextSyncStatus, Conversions, MaspAmount, + cloned_pair, ContextSyncStatus, Conversions, MaspAmount, MaspDataLogEntry, MaspFeeData, MaspSourceTransferData, MaspTargetTransferData, MaspTransferData, MaspTxReorderedData, NoteIndex, ShieldedSyncConfig, ShieldedTransfer, ShieldedUtils, SpentNotesTracker, diff --git a/crates/tests/src/e2e/helpers.rs b/crates/tests/src/e2e/helpers.rs index ab3579a1a2..0dc5fbeaf8 100644 --- a/crates/tests/src/e2e/helpers.rs +++ b/crates/tests/src/e2e/helpers.rs @@ -18,6 +18,7 @@ use eyre::eyre; use namada_apps_lib::cli::context::ENV_VAR_CHAIN_ID; use namada_apps_lib::config::utils::convert_tm_addr_to_socket_addr; use namada_apps_lib::config::{Config, TendermintMode}; +use namada_core::masp::PaymentAddress; use namada_core::token::NATIVE_MAX_DECIMAL_PLACES; use namada_sdk::address::Address; use namada_sdk::chain::Epoch; @@ -128,6 +129,31 @@ pub fn find_address(test: &Test, alias: impl AsRef) -> Result
{ Ok(address) } +/// Find the address of an account by its alias from the wallet +pub fn find_payment_address(test: &Test, alias: impl AsRef) -> Result { + let mut find = run!( + test, + Bin::Wallet, + &["find", "--addr", "--alias", alias.as_ref()], + Some(10) + )?; + find.exp_string("Found payment address:")?; + let (unread, matched) = find.exp_regex("\".*\": .*")?; + let address_str = strip_trailing_newline(&matched) + .trim() + .rsplit_once(' ') + .unwrap() + .1; + let address = PaymentAddress::from_str(address_str).map_err(|e| { + eyre!(format!( + "Address: {} parsed from {}, Error: {}\n\nOutput: {}", + address_str, matched, e, unread + )) + })?; + println!("Found {}", address); + Ok(address) +} + /// Find the balance of specific token for an account. #[allow(dead_code)] pub fn find_balance( diff --git a/crates/tests/src/e2e/ibc_tests.rs b/crates/tests/src/e2e/ibc_tests.rs index bde2ca2fa3..0b563883e3 100644 --- a/crates/tests/src/e2e/ibc_tests.rs +++ b/crates/tests/src/e2e/ibc_tests.rs @@ -47,7 +47,8 @@ use sha2::{Digest, Sha256}; use crate::e2e::helpers::{ epoch_sleep, epochs_per_year_from_min_duration, find_address, - find_cosmos_address, get_actor_rpc, get_cosmos_gov_address, get_epoch, + find_payment_address, get_actor_rpc, find_cosmos_address, + get_cosmos_gov_address, get_epoch, }; use crate::e2e::ledger_tests::{ start_namada_ledger_node_wait_wasm, write_json_file, @@ -231,10 +232,11 @@ fn ibc_transfers() -> Result<()> { &port_id_namada, &channel_id_namada, )?; + let masp_receiver = find_payment_address(&test, AA_PAYMENT_ADDRESS)?.to_string(); transfer_from_cosmos( &test_gaia, COSMOS_USER, - AA_PAYMENT_ADDRESS, + masp_receiver.clone(), COSMOS_COIN, 100, &port_id_gaia, @@ -289,10 +291,11 @@ fn ibc_transfers() -> Result<()> { &port_id_namada, &channel_id_namada, )?; + let masp_receiver = find_payment_address(&test, AA_PAYMENT_ADDRESS)?.to_string(); transfer_from_cosmos( &test_gaia, COSMOS_USER, - AA_PAYMENT_ADDRESS, + masp_receiver, get_gaia_denom_hash(&ibc_denom_on_gaia), 1_000_000, &port_id_gaia, @@ -412,10 +415,11 @@ fn ibc_transfers() -> Result<()> { check_cosmos_balance(&test_gaia, COSMOS_USER, COSMOS_COIN, 810)?; // Missing memo + let masp_receiver = find_payment_address(&test, AA_PAYMENT_ADDRESS)?.to_string(); transfer_from_cosmos( &test_gaia, COSMOS_USER, - AA_PAYMENT_ADDRESS, + masp_receiver, COSMOS_COIN, 100, &port_id_gaia, @@ -438,10 +442,11 @@ fn ibc_transfers() -> Result<()> { &port_id_namada, &channel_id_namada, )?; + let masp_receiver = find_payment_address(&test, AA_PAYMENT_ADDRESS)?.to_string(); transfer_from_cosmos( &test_gaia, COSMOS_USER, - AA_PAYMENT_ADDRESS, + masp_receiver, COSMOS_COIN, 101, &port_id_gaia, @@ -863,10 +868,11 @@ fn ibc_token_inflation() -> Result<()> { &port_id_namada, &channel_id_namada, )?; + let masp_receiver = find_payment_address(&test, AA_PAYMENT_ADDRESS)?.to_string(); transfer_from_cosmos( &test_gaia, COSMOS_USER, - AA_PAYMENT_ADDRESS, + masp_receiver, COSMOS_COIN, 1, &port_id_gaia, From 706a143f04cc3735c15438380ca4b7a9fb1305c0 Mon Sep 17 00:00:00 2001 From: Murisi Tarusenga Date: Wed, 30 Oct 2024 10:25:22 +0200 Subject: [PATCH 11/12] Make shielded balance checking more robust for IBC tests. --- crates/tests/src/e2e/ibc_tests.rs | 79 +++++++++++++++++++++++-------- 1 file changed, 59 insertions(+), 20 deletions(-) diff --git a/crates/tests/src/e2e/ibc_tests.rs b/crates/tests/src/e2e/ibc_tests.rs index 0b563883e3..555e81f479 100644 --- a/crates/tests/src/e2e/ibc_tests.rs +++ b/crates/tests/src/e2e/ibc_tests.rs @@ -135,6 +135,7 @@ fn ibc_transfers() -> Result<()> { None, None, None, + false, )?; wait_for_packet_relay(&port_id_namada, &channel_id_namada, &test)?; @@ -206,6 +207,7 @@ fn ibc_transfers() -> Result<()> { None, None, None, + false, )?; wait_for_packet_relay(&port_id_namada, &channel_id_namada, &test)?; @@ -246,7 +248,7 @@ fn ibc_transfers() -> Result<()> { )?; wait_for_packet_relay(&port_id_gaia, &channel_id_gaia, &test_gaia)?; // Check the token on Namada - check_balance(&test, AA_VIEWING_KEY, &ibc_denom_on_namada, 100)?; + check_shielded_balance(&test, AA_VIEWING_KEY, &ibc_denom_on_namada, 100)?; check_cosmos_balance(&test_gaia, COSMOS_USER, COSMOS_COIN, 800)?; // Shielded transfer 50 samoleans on Namada @@ -260,8 +262,8 @@ fn ibc_transfers() -> Result<()> { ALBERT_KEY, &[], )?; - check_balance(&test, AA_VIEWING_KEY, &ibc_denom_on_namada, 50)?; - check_balance(&test, AB_VIEWING_KEY, &ibc_denom_on_namada, 50)?; + check_shielded_balance(&test, AA_VIEWING_KEY, &ibc_denom_on_namada, 50)?; + check_shielded_balance(&test, AB_VIEWING_KEY, &ibc_denom_on_namada, 50)?; // Unshielding transfer 10 samoleans from Namada to Gaia transfer( @@ -276,9 +278,10 @@ fn ibc_transfers() -> Result<()> { None, None, None, + true, )?; wait_for_packet_relay(&port_id_namada, &channel_id_namada, &test)?; - check_balance(&test, AB_VIEWING_KEY, &ibc_denom_on_namada, 40)?; + check_shielded_balance(&test, AB_VIEWING_KEY, &ibc_denom_on_namada, 40)?; check_cosmos_balance(&test_gaia, COSMOS_USER, COSMOS_COIN, 810)?; // 4. Shielding transfer the received token back to a shielded account on @@ -305,7 +308,7 @@ fn ibc_transfers() -> Result<()> { )?; wait_for_packet_relay(&port_id_gaia, &channel_id_gaia, &test)?; // Check the token on Namada - check_balance(&test, AA_VIEWING_KEY, APFEL, 1)?; + check_shielded_balance(&test, AA_VIEWING_KEY, APFEL, 1)?; // 5. Refunding when transfer failure @@ -323,6 +326,7 @@ fn ibc_transfers() -> Result<()> { None, None, None, + false, )?; wait_for_packet_relay(&port_id_namada, &channel_id_namada, &test)?; // The balance should not be changed @@ -345,6 +349,7 @@ fn ibc_transfers() -> Result<()> { Some(Duration::new(10, 0)), None, None, + false, )?; // wait for the timeout sleep(10); @@ -371,10 +376,11 @@ fn ibc_transfers() -> Result<()> { None, None, None, + true, )?; wait_for_packet_relay(&port_id_namada, &channel_id_namada, &test)?; // Check the token has been refunded to the refund target - check_balance(&test, AA_VIEWING_KEY, &ibc_denom_on_namada, 40)?; + check_shielded_balance(&test, AA_VIEWING_KEY, &ibc_denom_on_namada, 40)?; check_balance(&test, IBC_REFUND_TARGET_ALIAS, &ibc_denom_on_namada, 10)?; // Stop Hermes for timeout test @@ -395,6 +401,7 @@ fn ibc_transfers() -> Result<()> { Some(Duration::new(10, 0)), None, None, + true, )?; // wait for the timeout sleep(10); @@ -405,13 +412,13 @@ fn ibc_transfers() -> Result<()> { wait_for_packet_relay(&port_id_namada, &channel_id_namada, &test)?; // Check the token has been refunded to the refund target - check_balance(&test, AA_VIEWING_KEY, APFEL, 0)?; + check_shielded_balance(&test, AA_VIEWING_KEY, APFEL, 0)?; check_balance(&test, IBC_REFUND_TARGET_ALIAS, APFEL, 1)?; // 6. Malformed shielded actions // Check initial balance - check_balance(&test, AA_VIEWING_KEY, &ibc_denom_on_namada, 40)?; + check_shielded_balance(&test, AA_VIEWING_KEY, &ibc_denom_on_namada, 40)?; check_cosmos_balance(&test_gaia, COSMOS_USER, COSMOS_COIN, 810)?; // Missing memo @@ -430,7 +437,7 @@ fn ibc_transfers() -> Result<()> { )?; wait_for_packet_relay(&port_id_namada, &channel_id_namada, &test)?; // Check the balance didn't change - check_balance(&test, AA_VIEWING_KEY, &ibc_denom_on_namada, 40)?; + check_shielded_balance(&test, AA_VIEWING_KEY, &ibc_denom_on_namada, 40)?; check_cosmos_balance(&test_gaia, COSMOS_USER, COSMOS_COIN, 810)?; // Wrong memo (different amount) @@ -457,7 +464,7 @@ fn ibc_transfers() -> Result<()> { )?; wait_for_packet_relay(&port_id_gaia, &channel_id_gaia, &test_gaia)?; // Check the balances didn't change - check_balance(&test, AA_VIEWING_KEY, &ibc_denom_on_namada, 40)?; + check_shielded_balance(&test, AA_VIEWING_KEY, &ibc_denom_on_namada, 40)?; check_cosmos_balance(&test_gaia, COSMOS_USER, COSMOS_COIN, 810)?; Ok(()) @@ -533,6 +540,7 @@ fn ibc_nft_transfers() -> Result<()> { None, None, None, + false, )?; clear_packet(&port_id_namada, &channel_id_namada, &test)?; check_balance(&test, &namada_receiver, &ibc_trace_on_namada, 0)?; @@ -547,10 +555,11 @@ fn ibc_nft_transfers() -> Result<()> { &port_id_namada, &channel_id_namada, )?; + let masp_receiver = find_payment_address(&test, AA_PAYMENT_ADDRESS)?.to_string(); nft_transfer_from_cosmos( &test_cosmwasm, COSMOS_USER, - AA_PAYMENT_ADDRESS, + masp_receiver, NFT_ID, &cw721_contract, &ics721_contract, @@ -559,7 +568,7 @@ fn ibc_nft_transfers() -> Result<()> { None, )?; clear_packet(&port_id_cosmwasm, &channel_id_cosmwasm, &test_cosmwasm)?; - check_balance(&test, AA_VIEWING_KEY, &ibc_trace_on_namada, 1)?; + check_shielded_balance(&test, AA_VIEWING_KEY, &ibc_trace_on_namada, 1)?; // Shielded transfer on Namada transfer_on_chain( @@ -572,8 +581,8 @@ fn ibc_nft_transfers() -> Result<()> { ALBERT_KEY, &[], )?; - check_balance(&test, AA_VIEWING_KEY, &ibc_trace_on_namada, 0)?; - check_balance(&test, AB_VIEWING_KEY, &ibc_trace_on_namada, 1)?; + check_shielded_balance(&test, AA_VIEWING_KEY, &ibc_trace_on_namada, 0)?; + check_shielded_balance(&test, AB_VIEWING_KEY, &ibc_trace_on_namada, 1)?; // Unshielding transfer transfer( @@ -588,9 +597,10 @@ fn ibc_nft_transfers() -> Result<()> { None, None, None, + true, )?; clear_packet(&port_id_namada, &channel_id_namada, &test)?; - check_balance(&test, AB_VIEWING_KEY, &ibc_trace_on_namada, 0)?; + check_shielded_balance(&test, AB_VIEWING_KEY, &ibc_trace_on_namada, 0)?; Ok(()) } @@ -858,7 +868,7 @@ fn ibc_token_inflation() -> Result<()> { } // Check the target balance is zero before the inflation - check_balance(&test, AA_VIEWING_KEY, NAM, 0)?; + check_shielded_balance(&test, AA_VIEWING_KEY, NAM, 0)?; // Shielding transfer 1 samoleans from Gaia to Namada let shielding_data_path = gen_ibc_shielding_data( &test, @@ -1017,6 +1027,7 @@ fn ibc_rate_limit() -> Result<()> { None, None, None, + false, )?; // Transfer 1 NAM from Namada to Gaia again will fail @@ -1035,6 +1046,7 @@ fn ibc_rate_limit() -> Result<()> { Some( "Transfer exceeding the per-epoch throughput limit is not allowed", ), + false, )?; // wait for the next epoch @@ -1057,6 +1069,7 @@ fn ibc_rate_limit() -> Result<()> { None, None, None, + false, )?; // wait for the next epoch @@ -1333,6 +1346,7 @@ fn try_invalid_transfers( None, // the IBC denom can't be parsed when using an invalid port Some(&format!("Invalid IBC denom: {nam_addr}")), + false, )?; // invalid channel @@ -1348,6 +1362,7 @@ fn try_invalid_transfers( None, None, Some("IBC token transfer error: context error: `ICS04 Channel error"), + false, )?; Ok(()) @@ -1402,6 +1417,7 @@ fn transfer( timeout_sec: Option, shielding_data_path: Option, expected_err: Option<&str>, + gen_refund_target: bool, ) -> Result { let rpc = get_actor_rpc(test, Who::Validator(0)); @@ -1449,7 +1465,7 @@ fn transfer( tx_args.push(&memo); } - if sender.as_ref().starts_with("zsk") { + if gen_refund_target { let mut cmd = run!( test, Bin::Wallet, @@ -1912,9 +1928,32 @@ fn check_balance( ) -> Result<()> { let rpc = get_actor_rpc(test, Who::Validator(0)); - if owner.as_ref().starts_with("zvk") { - shielded_sync(test, owner.as_ref())?; - } + let query_args = vec![ + "balance", + "--owner", + owner.as_ref(), + "--token", + token.as_ref(), + "--node", + &rpc, + ]; + let mut client = run!(test, Bin::Client, query_args, Some(40))?; + let expected = + format!("{}: {expected_amount}", token.as_ref().to_lowercase()); + client.exp_string(&expected)?; + client.assert_success(); + Ok(()) +} + +fn check_shielded_balance( + test: &Test, + owner: impl AsRef, + token: impl AsRef, + expected_amount: u64, +) -> Result<()> { + let rpc = get_actor_rpc(test, Who::Validator(0)); + + shielded_sync(test, owner.as_ref())?; let query_args = vec![ "balance", From 24fcb3bf76e0afc43c65f1b22a682ba43dd4f40a Mon Sep 17 00:00:00 2001 From: Murisi Tarusenga Date: Wed, 20 Nov 2024 17:03:11 +0200 Subject: [PATCH 12/12] Adjust integration tests to work with both hardware and localnet genesis files. --- crates/apps_lib/src/client/tx.rs | 6 +- crates/core/src/masp.rs | 18 +- crates/node/src/shell/testing/client.rs | 8 +- crates/sdk/src/signing.rs | 7 +- crates/sdk/src/tx.rs | 4 +- .../src/masp/shielded_wallet.rs | 14 +- crates/tests/src/e2e/helpers.rs | 15 +- crates/tests/src/e2e/ibc_tests.rs | 20 +- crates/tests/src/e2e/ledger_tests.rs | 2 +- crates/tests/src/e2e/setup.rs | 12 -- crates/tests/src/integration/helpers.rs | 7 +- crates/tests/src/integration/ledger_tests.rs | 92 ++++----- crates/tests/src/integration/masp.rs | 187 ++++++++++-------- 13 files changed, 204 insertions(+), 188 deletions(-) diff --git a/crates/apps_lib/src/client/tx.rs b/crates/apps_lib/src/client/tx.rs index d9e002ba0c..cc95af5ab0 100644 --- a/crates/apps_lib/src/client/tx.rs +++ b/crates/apps_lib/src/client/tx.rs @@ -4,7 +4,6 @@ use std::io::Write; use borsh::BorshDeserialize; use borsh_ext::BorshSerializeExt; use color_eyre::owo_colors::OwoColorize; -use namada_core::masp::MaspTransaction; use ledger_namada_rs::{BIP44Path, KeyResponse, NamadaApp, NamadaKeys}; use masp_primitives::sapling::redjubjub::PrivateKey; use masp_primitives::sapling::{redjubjub, ProofGenerationKey}; @@ -17,6 +16,7 @@ use masp_primitives::transaction::components::sapling::fees::InputView; use masp_primitives::zip32::{ ExtendedFullViewingKey, ExtendedKey, PseudoExtendedKey, }; +use namada_core::masp::MaspTransaction; use namada_sdk::address::{Address, ImplicitAddress}; use namada_sdk::args::TxBecomeValidator; use namada_sdk::collections::HashMap; @@ -1171,7 +1171,7 @@ pub async fn submit_shielded_transfer( to date, make sure to run `namadac shielded-sync` before running \ this command.", ); - + let sources = args .data .iter_mut() @@ -1286,7 +1286,7 @@ pub async fn submit_unshielding_transfer( to date, make sure to run `namadac shielded-sync` before running \ this command.", ); - + let sources = std::iter::once(&mut args.source) .chain(args.gas_spending_key.iter_mut()); let shielded_hw_keys = diff --git a/crates/core/src/masp.rs b/crates/core/src/masp.rs index bd09367abf..13cda85ba3 100644 --- a/crates/core/src/masp.rs +++ b/crates/core/src/masp.rs @@ -841,11 +841,10 @@ mod test { .address(); assert_eq!(addr.unwrap(), address::testing::established_address_1()); - let addr = - TransferSource::ExtendedSpendingKey( - masp_primitives::zip32::ExtendedSpendingKey::master(&[0_u8]).into(), - ) - .address(); + let addr = TransferSource::ExtendedSpendingKey( + masp_primitives::zip32::ExtendedSpendingKey::master(&[0_u8]).into(), + ) + .address(); assert!(addr.is_none()); } @@ -859,11 +858,10 @@ mod test { TAddrData::Addr(address::testing::established_address_1()) ); - let addr = - TransferSource::ExtendedSpendingKey( - masp_primitives::zip32::ExtendedSpendingKey::master(&[0_u8]).into(), - ) - .address(); + let addr = TransferSource::ExtendedSpendingKey( + masp_primitives::zip32::ExtendedSpendingKey::master(&[0_u8]).into(), + ) + .address(); assert!(addr.is_none()); } diff --git a/crates/node/src/shell/testing/client.rs b/crates/node/src/shell/testing/client.rs index 21ff520bff..8bf1236b4a 100644 --- a/crates/node/src/shell/testing/client.rs +++ b/crates/node/src/shell/testing/client.rs @@ -47,11 +47,15 @@ pub fn run( NamadaClient::WithoutContext(Box::new((sub_cmd, global))) } }; - rt.block_on(CliApi::handle_client_command( + let result = rt.block_on(CliApi::handle_client_command( Some(node.clone()), cmd, TestingIo, - )) + )); + if let Err(err) = &result { + TestingIo.eprintln(format!("{}", err)); + } + result } Bin::Wallet => { args.insert(0, "wallet"); diff --git a/crates/sdk/src/signing.rs b/crates/sdk/src/signing.rs index 131a86eddc..98d87332ec 100644 --- a/crates/sdk/src/signing.rs +++ b/crates/sdk/src/signing.rs @@ -291,8 +291,9 @@ where // Then try to sign the raw header using the hardware wallet for pubkey in &signing_data.public_keys { - if !used_pubkeys.contains(pubkey) && - (*pubkey != signing_data.fee_payer || args.wrapper_signature.is_some()) + if !used_pubkeys.contains(pubkey) + && (*pubkey != signing_data.fee_payer + || args.wrapper_signature.is_some()) { if let Ok(ntx) = sign( tx.clone(), @@ -333,7 +334,7 @@ where Signable::FeeRawHeader, user_data, ) - .await?; + .await?; if signing_data.public_keys.contains(&signing_data.fee_payer) { used_pubkeys.insert(signing_data.fee_payer.clone()); } diff --git a/crates/sdk/src/tx.rs b/crates/sdk/src/tx.rs index ba8b7e16a4..7b9a6ad42b 100644 --- a/crates/sdk/src/tx.rs +++ b/crates/sdk/src/tx.rs @@ -3479,9 +3479,7 @@ async fn construct_shielded_parts( .await; shielded - .gen_shielded_transfer( - context, data, fee_data, expiration, bparams, - ) + .gen_shielded_transfer(context, data, fee_data, expiration, bparams) .await }; diff --git a/crates/shielded_token/src/masp/shielded_wallet.rs b/crates/shielded_token/src/masp/shielded_wallet.rs index a8fd36aaea..50224423d9 100644 --- a/crates/shielded_token/src/masp/shielded_wallet.rs +++ b/crates/shielded_token/src/masp/shielded_wallet.rs @@ -50,11 +50,11 @@ use rand_core::{OsRng, SeedableRng}; use crate::masp::utils::MaspClient; use crate::masp::{ - cloned_pair, ContextSyncStatus, Conversions, MaspAmount, - MaspDataLogEntry, MaspFeeData, MaspSourceTransferData, - MaspTargetTransferData, MaspTransferData, MaspTxReorderedData, NoteIndex, - ShieldedSyncConfig, ShieldedTransfer, ShieldedUtils, SpentNotesTracker, - TransferErr, WalletMap, WitnessMap, NETWORK, + cloned_pair, ContextSyncStatus, Conversions, MaspAmount, MaspDataLogEntry, + MaspFeeData, MaspSourceTransferData, MaspTargetTransferData, + MaspTransferData, MaspTxReorderedData, NoteIndex, ShieldedSyncConfig, + ShieldedTransfer, ShieldedUtils, SpentNotesTracker, TransferErr, WalletMap, + WitnessMap, NETWORK, }; #[cfg(any(test, feature = "testing"))] use crate::masp::{testing, ENV_VAR_MASP_TEST_SEED}; @@ -1623,9 +1623,7 @@ pub trait ShieldedApi: // If we are sending to a shielded address, we need the outgoing // viewing key in the following computations. let ovk_opt = source.clone().and_then(|source| { - source - .spending_key() - .map(|x| x.to_viewing_key().fvk.ovk) + source.spending_key().map(|x| x.to_viewing_key().fvk.ovk) }); // Make transaction output tied to the current token, // denomination, and epoch. diff --git a/crates/tests/src/e2e/helpers.rs b/crates/tests/src/e2e/helpers.rs index 0dc5fbeaf8..5c3a9d25a1 100644 --- a/crates/tests/src/e2e/helpers.rs +++ b/crates/tests/src/e2e/helpers.rs @@ -31,10 +31,10 @@ use namada_sdk::wallet::Wallet; use toml::Value; use super::setup::{ - self, ensure_hot_key, run_cosmos_cmd, sleep, NamadaBgCmd, NamadaCmd, Test, - ENV_VAR_DEBUG, ENV_VAR_USE_PREBUILT_BINARIES, + self, run_cosmos_cmd, sleep, NamadaBgCmd, NamadaCmd, Test, ENV_VAR_DEBUG, + ENV_VAR_USE_PREBUILT_BINARIES, }; -use crate::e2e::setup::{Bin, CosmosChainType, Who, APPS_PACKAGE}; +use crate::e2e::setup::{constants, Bin, CosmosChainType, Who, APPS_PACKAGE}; use crate::strings::{LEDGER_STARTED, TX_APPLIED_SUCCESS}; use crate::{run, run_as}; @@ -130,7 +130,10 @@ pub fn find_address(test: &Test, alias: impl AsRef) -> Result
{ } /// Find the address of an account by its alias from the wallet -pub fn find_payment_address(test: &Test, alias: impl AsRef) -> Result { +pub fn find_payment_address( + test: &Test, + alias: impl AsRef, +) -> Result { let mut find = run!( test, Bin::Wallet, @@ -588,9 +591,7 @@ fn make_hermes_chain_config(test: &Test) -> Value { chain.insert("account_prefix".to_owned(), Value::String("".to_owned())); chain.insert( "key_name".to_owned(), - Value::String( - ensure_hot_key(setup::constants::CHRISTEL_KEY).to_owned(), - ), + Value::String(constants::FRANK_KEY.to_owned()), ); chain.insert("store_prefix".to_owned(), Value::String("ibc".to_owned())); let mut table = toml::map::Map::new(); diff --git a/crates/tests/src/e2e/ibc_tests.rs b/crates/tests/src/e2e/ibc_tests.rs index 555e81f479..cee0f7b8fd 100644 --- a/crates/tests/src/e2e/ibc_tests.rs +++ b/crates/tests/src/e2e/ibc_tests.rs @@ -47,7 +47,7 @@ use sha2::{Digest, Sha256}; use crate::e2e::helpers::{ epoch_sleep, epochs_per_year_from_min_duration, find_address, - find_payment_address, get_actor_rpc, find_cosmos_address, + find_cosmos_address, find_payment_address, get_actor_rpc, get_cosmos_gov_address, get_epoch, }; use crate::e2e::ledger_tests::{ @@ -234,7 +234,8 @@ fn ibc_transfers() -> Result<()> { &port_id_namada, &channel_id_namada, )?; - let masp_receiver = find_payment_address(&test, AA_PAYMENT_ADDRESS)?.to_string(); + let masp_receiver = + find_payment_address(&test, AA_PAYMENT_ADDRESS)?.to_string(); transfer_from_cosmos( &test_gaia, COSMOS_USER, @@ -294,7 +295,8 @@ fn ibc_transfers() -> Result<()> { &port_id_namada, &channel_id_namada, )?; - let masp_receiver = find_payment_address(&test, AA_PAYMENT_ADDRESS)?.to_string(); + let masp_receiver = + find_payment_address(&test, AA_PAYMENT_ADDRESS)?.to_string(); transfer_from_cosmos( &test_gaia, COSMOS_USER, @@ -422,7 +424,8 @@ fn ibc_transfers() -> Result<()> { check_cosmos_balance(&test_gaia, COSMOS_USER, COSMOS_COIN, 810)?; // Missing memo - let masp_receiver = find_payment_address(&test, AA_PAYMENT_ADDRESS)?.to_string(); + let masp_receiver = + find_payment_address(&test, AA_PAYMENT_ADDRESS)?.to_string(); transfer_from_cosmos( &test_gaia, COSMOS_USER, @@ -449,7 +452,8 @@ fn ibc_transfers() -> Result<()> { &port_id_namada, &channel_id_namada, )?; - let masp_receiver = find_payment_address(&test, AA_PAYMENT_ADDRESS)?.to_string(); + let masp_receiver = + find_payment_address(&test, AA_PAYMENT_ADDRESS)?.to_string(); transfer_from_cosmos( &test_gaia, COSMOS_USER, @@ -555,7 +559,8 @@ fn ibc_nft_transfers() -> Result<()> { &port_id_namada, &channel_id_namada, )?; - let masp_receiver = find_payment_address(&test, AA_PAYMENT_ADDRESS)?.to_string(); + let masp_receiver = + find_payment_address(&test, AA_PAYMENT_ADDRESS)?.to_string(); nft_transfer_from_cosmos( &test_cosmwasm, COSMOS_USER, @@ -878,7 +883,8 @@ fn ibc_token_inflation() -> Result<()> { &port_id_namada, &channel_id_namada, )?; - let masp_receiver = find_payment_address(&test, AA_PAYMENT_ADDRESS)?.to_string(); + let masp_receiver = + find_payment_address(&test, AA_PAYMENT_ADDRESS)?.to_string(); transfer_from_cosmos( &test_gaia, COSMOS_USER, diff --git a/crates/tests/src/e2e/ledger_tests.rs b/crates/tests/src/e2e/ledger_tests.rs index 973dfb9f33..cd7b0aef4b 100644 --- a/crates/tests/src/e2e/ledger_tests.rs +++ b/crates/tests/src/e2e/ledger_tests.rs @@ -27,8 +27,8 @@ use namada_apps_lib::config::genesis::templates::TokenBalances; use namada_apps_lib::config::utils::convert_tm_addr_to_socket_addr; use namada_apps_lib::config::{self, ethereum_bridge}; use namada_apps_lib::tendermint_config::net::Address as TendermintAddress; -use namada_apps_lib::wallet::{self, Alias}; use namada_apps_lib::wallet::defaults::is_use_device; +use namada_apps_lib::wallet::{self, Alias}; use namada_core::chain::ChainId; use namada_core::token::NATIVE_MAX_DECIMAL_PLACES; use namada_sdk::address::Address; diff --git a/crates/tests/src/e2e/setup.rs b/crates/tests/src/e2e/setup.rs index 6dd8f44167..d7c9a663e9 100644 --- a/crates/tests/src/e2e/setup.rs +++ b/crates/tests/src/e2e/setup.rs @@ -89,18 +89,6 @@ pub fn apply_use_device(mut tx_args: Vec<&str>) -> Vec<&str> { tx_args } -/// Replace the given key with a key that is stored unencrypted in the wallet. -/// This is useful for IBC tests where a keypair needs to be added to the Hermes -/// keyring or where IBC messages unsupported by the hardware wallet need to be -/// signed -pub fn ensure_hot_key(key: &str) -> &str { - if is_use_device() { - constants::FRANK_KEY - } else { - key - } -} - /// Default functions for offsetting ports when /// adding multiple validators to a network pub fn default_port_offset(ix: u8) -> u16 { diff --git a/crates/tests/src/integration/helpers.rs b/crates/tests/src/integration/helpers.rs index f142362583..c2447a3a50 100644 --- a/crates/tests/src/integration/helpers.rs +++ b/crates/tests/src/integration/helpers.rs @@ -7,6 +7,7 @@ use namada_node::shell::testing::client::run; use namada_node::shell::testing::node::MockNode; use namada_node::shell::testing::utils::{Bin, CapturedOutput}; use namada_sdk::key::common; + use crate::e2e::setup::constants::{FRANK, FRANK_KEY}; use crate::strings::TX_APPLIED_SUCCESS; @@ -112,8 +113,7 @@ pub fn make_temp_account( "--node", ledger_address, ]; - let captured = - CapturedOutput::of(|| run(node, Bin::Client, reveal_args)); + let captured = CapturedOutput::of(|| run(node, Bin::Client, reveal_args)); assert!(captured.result.is_ok()); assert!(captured.contains(TX_APPLIED_SUCCESS)); // c. Send some funds to the implicit account. @@ -133,8 +133,7 @@ pub fn make_temp_account( "--node", ledger_address, ]; - let captured = - CapturedOutput::of(|| run(node, Bin::Client, credit_args)); + let captured = CapturedOutput::of(|| run(node, Bin::Client, credit_args)); assert!(captured.result.is_ok()); assert!(captured.contains(TX_APPLIED_SUCCESS)); // d. Obtain the key pair associated with the new address diff --git a/crates/tests/src/integration/ledger_tests.rs b/crates/tests/src/integration/ledger_tests.rs index d609aaddd7..8dcaf35521 100644 --- a/crates/tests/src/integration/ledger_tests.rs +++ b/crates/tests/src/integration/ledger_tests.rs @@ -9,9 +9,7 @@ use borsh::BorshDeserialize; use borsh_ext::BorshSerializeExt; use color_eyre::eyre::Result; use data_encoding::HEXLOWER; -use namada_apps_lib::wallet::defaults::{ - self, get_unencrypted_keypair, is_use_device, -}; +use namada_apps_lib::wallet::defaults::{self, is_use_device}; use namada_core::chain::Epoch; use namada_core::dec::Dec; use namada_core::hash::Hash; @@ -34,14 +32,14 @@ use namada_test_utils::TestWasms; use test_log::test; use crate::e2e::ledger_tests::prepare_proposal_data; +use crate::e2e::setup::apply_use_device; use crate::e2e::setup::constants::{ ALBERT, ALBERT_KEY, APFEL, BERTHA, BERTHA_KEY, BTC, CHRISTEL, CHRISTEL_KEY, DAEWON, DOT, ESTER, ETH, GOVERNANCE_ADDRESS, KARTOFFEL, NAM, PGF_ADDRESS, SCHNITZEL, }; -use crate::e2e::setup::{apply_use_device, ensure_hot_key}; use crate::integration::helpers::{ - find_address, find_keypair, prepare_steward_commission_update_data, + find_address, make_temp_account, prepare_steward_commission_update_data, }; use crate::integration::setup; use crate::strings::{ @@ -553,10 +551,10 @@ fn pos_rewards() -> Result<()> { }); assert_matches!(captured.result, Ok(_)); let _res = captured - .matches(r"Current annual staking rewards rate: 63.483") + .matches(r"Current annual staking rewards rate: 65.705255877354") .expect("Test failed"); let _res = captured - .matches(r"PoS inflation rate: 0.066") + .matches(r"PoS inflation rate: 0.066593164444") .expect("Test failed"); Ok(()) @@ -987,20 +985,20 @@ fn inflation() -> Result<()> { })?; let pos_inflation = [ - 114400000.785983, - 114400001.632333, - 114400002.53905, - 114400003.506134, - 114400004.533585, + 118400000.813463, + 118400001.689407, + 118400002.627832, + 118400003.628738, + 118400004.692125, ]; let steward_inflation = [ - 1980000.36276, - 1980000.72552, - 1980001.08828, - 1980001.45104, - 1980001.8138, + 1980000.375443, + 1980000.750886, + 1980001.126329, + 1980001.501772, + 1980001.877215, ]; - let pgf_inflation = [0.399038, 0.792006, 1.200066, 1.623217, 2.06146]; + let pgf_inflation = [0.41299, 0.819698, 1.242026, 1.679974, 2.133543]; for epoch in 0..5 { node.next_epoch(); @@ -1285,7 +1283,7 @@ fn pgf_governance_proposal() -> Result<()> { let captured = CapturedOutput::of(|| run(&node, Bin::Client, query_balance_args)); assert_matches!(captured.result, Ok(_)); - assert!(captured.contains("nam: 13.785266")); + assert!(captured.contains("nam: 14.267253")); let query_total_supply_args = vec![ "total-supply", @@ -1298,7 +1296,7 @@ fn pgf_governance_proposal() -> Result<()> { CapturedOutput::of(|| run(&node, Bin::Client, query_total_supply_args)); assert_matches!(captured.result, Ok(_)); assert!(captured.contains( - "token tnam1q9kn74xfzytqkqyycfrhycr8ajam8ny935cge0z5: 114400023.904507" + "token tnam1q9kn74xfzytqkqyycfrhycr8ajam8ny935cge0z5: 118400024.740301" )); let query_native_supply_args = @@ -1307,7 +1305,7 @@ fn pgf_governance_proposal() -> Result<()> { run(&node, Bin::Client, query_native_supply_args) }); assert_matches!(captured.result, Ok(_)); - assert!(captured.contains("nam: 114400010.119241")); + assert!(captured.contains("nam: 118400010.473048")); // 8. Submit proposal funding let albert = defaults::albert_address(); @@ -1697,9 +1695,16 @@ fn change_validator_metadata() -> Result<()> { fn offline_sign() -> Result<()> { // This address doesn't matter for tests. But an argument is required. let validator_one_rpc = "http://127.0.0.1:26567"; + // 1. start the ledger node let (node, _services) = setup::setup()?; + // Initialize accounts we can access the secret keys of + let (bradley_alias, _bradley_key) = + make_temp_account(&node, validator_one_rpc, "Bradley", NAM, 500_000)?; + let (cooper_alias, _cooper_key) = + make_temp_account(&node, validator_one_rpc, "Cooper", NAM, 500_000)?; + let output_folder = tempfile::tempdir().unwrap(); // 2. Dump a wrapped transfer tx @@ -1710,7 +1715,7 @@ fn offline_sign() -> Result<()> { apply_use_device(vec![ "transparent-transfer", "--source", - BERTHA, + bradley_alias.as_ref(), "--target", ALBERT, "--token", @@ -1722,7 +1727,7 @@ fn offline_sign() -> Result<()> { "--gas-price", "1", "--gas-payer", - CHRISTEL_KEY, + cooper_alias.as_ref(), "--node", &validator_one_rpc, "--dump-wrapper-tx", @@ -1741,26 +1746,23 @@ fn offline_sign() -> Result<()> { .display() .to_string(); - let bertha_sk = find_keypair(&node, BERTHA_KEY).unwrap().to_string(); - let christel_sk = find_keypair(&node, CHRISTEL_KEY).unwrap().to_string(); - // 3. Sign the transaction offline let captured = CapturedOutput::of(|| { run( &node, Bin::Client, - apply_use_device(vec![ + vec![ "utils", "sign-offline", "--data-path", &offline_tx, "--secret-keys", - &bertha_sk, + &bradley_alias.as_ref(), "--secret-key", - &christel_sk, + &cooper_alias.as_ref(), "--output-folder-path", &output_folder.path().to_str().unwrap(), - ]), + ], ) }); assert!(captured.result.is_ok()); @@ -1823,7 +1825,7 @@ fn offline_sign() -> Result<()> { vec![ "balance", "--owner", - ensure_hot_key(BERTHA), + bradley_alias.as_ref(), "--token", NAM, "--node", @@ -1832,7 +1834,7 @@ fn offline_sign() -> Result<()> { ) }); assert!(captured.result.is_ok()); - assert!(captured.contains("nam: 1999900")); + assert!(captured.contains("nam: 499900")); let captured = CapturedOutput::of(|| { run( &node, @@ -1840,7 +1842,7 @@ fn offline_sign() -> Result<()> { vec![ "balance", "--owner", - ensure_hot_key(CHRISTEL_KEY), + cooper_alias.as_ref(), "--token", NAM, "--node", @@ -1849,7 +1851,7 @@ fn offline_sign() -> Result<()> { ) }); assert!(captured.result.is_ok()); - assert!(captured.contains("nam: 1800000")); + assert!(captured.contains("nam: 300000")); Ok(()) } @@ -1864,6 +1866,10 @@ fn enforce_fee_payment() -> Result<()> { // 1. start the ledger node let (node, _services) = setup::setup()?; + // Initialize accounts we can access the secret keys of + let (adam_alias, adam_key) = + make_temp_account(&node, validator_one_rpc, "Adam", NAM, 2_000_000)?; + let tempdir = tempfile::tempdir().unwrap(); let mut txs_bytes = vec![]; @@ -1874,7 +1880,7 @@ fn enforce_fee_payment() -> Result<()> { vec![ "balance", "--owner", - ensure_hot_key(ALBERT_KEY), + adam_alias.as_ref(), "--token", NAM, "--node", @@ -1891,7 +1897,7 @@ fn enforce_fee_payment() -> Result<()> { apply_use_device(vec![ "transparent-transfer", "--source", - ensure_hot_key(ALBERT_KEY), + adam_alias.as_ref(), "--target", BERTHA, "--token", @@ -1927,7 +1933,7 @@ fn enforce_fee_payment() -> Result<()> { apply_use_device(vec![ "transparent-transfer", "--source", - ensure_hot_key(ALBERT_KEY), + adam_alias.as_ref(), "--target", CHRISTEL, "--token", @@ -1935,7 +1941,7 @@ fn enforce_fee_payment() -> Result<()> { "--amount", "50", "--gas-payer", - ensure_hot_key(ALBERT_KEY), + adam_alias.as_ref(), "--output-folder-path", tempdir.path().to_str().unwrap(), "--dump-tx", @@ -1955,9 +1961,7 @@ fn enforce_fee_payment() -> Result<()> { txs_bytes.push(std::fs::read(&file_path).unwrap()); std::fs::remove_file(&file_path).unwrap(); - let sk = get_unencrypted_keypair( - &ensure_hot_key("albert-key").to_ascii_lowercase(), - ); + let sk = adam_key; let pk = sk.to_public(); let native_token = node @@ -2022,7 +2026,7 @@ fn enforce_fee_payment() -> Result<()> { vec![ "balance", "--owner", - ensure_hot_key(ALBERT_KEY), + adam_alias.as_ref(), "--token", NAM, "--node", @@ -2095,7 +2099,7 @@ fn apply_snapshot() -> Result<()> { for _ in 0..3 { node.next_epoch(); } - let tx_args = vec![ + let tx_args = apply_use_device(vec![ "transparent-transfer", "--source", BERTHA, @@ -2110,7 +2114,7 @@ fn apply_snapshot() -> Result<()> { "--node", &validator_one_rpc, "--force", - ]; + ]); let captured = CapturedOutput::of(|| run(&node, Bin::Client, tx_args)); assert_matches!(captured.result, Ok(_)); diff --git a/crates/tests/src/integration/masp.rs b/crates/tests/src/integration/masp.rs index 4030b89f2a..8169dc55ba 100644 --- a/crates/tests/src/integration/masp.rs +++ b/crates/tests/src/integration/masp.rs @@ -3,10 +3,10 @@ use std::str::FromStr; use color_eyre::eyre::Result; use color_eyre::owo_colors::OwoColorize; -use namada_core::address::Address; use namada_apps_lib::wallet::defaults::{ get_unencrypted_keypair, is_use_device, }; +use namada_core::address::Address; use namada_core::dec::Dec; use namada_core::masp::{MaspTxId, TokenMap}; use namada_node::shell::testing::client::run; @@ -24,13 +24,13 @@ use namada_sdk::{tx, DEFAULT_GAS_LIMIT}; use test_log::test; use super::{helpers, setup}; +use crate::e2e::setup::apply_use_device; use crate::e2e::setup::constants::{ AA_PAYMENT_ADDRESS, AA_VIEWING_KEY, AB_PAYMENT_ADDRESS, AB_VIEWING_KEY, AC_PAYMENT_ADDRESS, AC_VIEWING_KEY, ALBERT, ALBERT_KEY, A_SPENDING_KEY, BB_PAYMENT_ADDRESS, BERTHA, BERTHA_KEY, BTC, B_SPENDING_KEY, CHRISTEL, CHRISTEL_KEY, C_SPENDING_KEY, ETH, FRANK_KEY, MASP, NAM, }; -use crate::e2e::setup::{apply_use_device, ensure_hot_key}; use crate::integration::helpers::make_temp_account; use crate::strings::TX_APPLIED_SUCCESS; @@ -106,7 +106,7 @@ fn init_null_rewards() -> Result<()> { run( &node, Bin::Client, - vec![ + apply_use_device(vec![ "shield", "--source", BERTHA, @@ -118,7 +118,7 @@ fn init_null_rewards() -> Result<()> { "1000000", "--node", RPC, - ], + ]), ) }); assert!(captured.result.is_ok(), "{:?}", captured.result); @@ -245,7 +245,7 @@ fn init_null_rewards() -> Result<()> { run( &node, Bin::Client, - vec![ + apply_use_device(vec![ "unshield", "--source", A_SPENDING_KEY, @@ -259,7 +259,7 @@ fn init_null_rewards() -> Result<()> { BERTHA_KEY, "--node", RPC, - ], + ]), ) }); assert!(captured.result.is_ok(), "{:?}", captured.result); @@ -302,7 +302,7 @@ fn init_null_rewards() -> Result<()> { run( &node, Bin::Client, - vec![ + apply_use_device(vec![ "transfer", "--source", A_SPENDING_KEY, @@ -316,7 +316,7 @@ fn init_null_rewards() -> Result<()> { BERTHA_KEY, "--node", RPC, - ], + ]), ) }); assert!(captured.result.is_ok(), "{:?}", captured.result); @@ -359,7 +359,7 @@ fn init_null_rewards() -> Result<()> { run( &node, Bin::Client, - vec![ + apply_use_device(vec![ "unshield", "--source", A_SPENDING_KEY, @@ -373,7 +373,7 @@ fn init_null_rewards() -> Result<()> { BERTHA_KEY, "--node", RPC, - ], + ]), ) }); assert!(captured.result.is_ok(), "{:?}", captured.result); @@ -470,7 +470,7 @@ fn values_spanning_multiple_masp_digits() -> Result<()> { run( &node, Bin::Client, - vec![ + apply_use_device(vec![ "shield", "--source", BERTHA, @@ -482,7 +482,7 @@ fn values_spanning_multiple_masp_digits() -> Result<()> { HALF_TEST_TOKEN_INITIAL_SUPPLY, "--node", RPC, - ], + ]), ) }); assert!(captured.result.is_ok(), "{:?}", captured.result); @@ -552,7 +552,7 @@ fn values_spanning_multiple_masp_digits() -> Result<()> { run( &node, Bin::Client, - vec![ + apply_use_device(vec![ "unshield", "--source", A_SPENDING_KEY, @@ -566,7 +566,7 @@ fn values_spanning_multiple_masp_digits() -> Result<()> { BERTHA_KEY, "--node", RPC, - ], + ]), ) }); assert!(captured.result.is_ok(), "{:?}", captured.result); @@ -639,7 +639,7 @@ fn values_spanning_multiple_masp_digits() -> Result<()> { run( &node, Bin::Client, - vec![ + apply_use_device(vec![ "shield", "--source", BERTHA, @@ -651,7 +651,7 @@ fn values_spanning_multiple_masp_digits() -> Result<()> { HALF_TEST_TOKEN_INITIAL_SUPPLY, "--node", RPC, - ], + ]), ) }); assert!(captured.result.is_ok(), "{:?}", captured.result); @@ -724,7 +724,7 @@ fn values_spanning_multiple_masp_digits() -> Result<()> { run( &node, Bin::Client, - vec![ + apply_use_device(vec![ "unshield", "--source", A_SPENDING_KEY, @@ -740,7 +740,7 @@ fn values_spanning_multiple_masp_digits() -> Result<()> { RPC, "--gas-limit", "65000", - ], + ]), ) }); assert!(captured.result.is_ok(), "{:?}", captured.result); @@ -783,7 +783,7 @@ fn values_spanning_multiple_masp_digits() -> Result<()> { run( &node, Bin::Client, - vec![ + apply_use_device(vec![ "shield", "--source", BERTHA_KEY, @@ -797,7 +797,7 @@ fn values_spanning_multiple_masp_digits() -> Result<()> { BERTHA_KEY, "--node", RPC, - ], + ]), ) }); assert!(captured.result.is_ok(), "{:?}", captured.result); @@ -842,7 +842,7 @@ fn values_spanning_multiple_masp_digits() -> Result<()> { run( &node, Bin::Client, - vec![ + apply_use_device(vec![ "unshield", "--source", A_SPENDING_KEY, @@ -859,7 +859,7 @@ fn values_spanning_multiple_masp_digits() -> Result<()> { C_SPENDING_KEY, "--gas-limit", "65000", - ], + ]), ) }); assert!(captured.result.is_ok(), "{:?}", captured.result); @@ -948,7 +948,7 @@ fn enable_rewards_after_shielding() -> Result<()> { run( &node, Bin::Client, - vec![ + apply_use_device(vec![ "shield", "--source", BERTHA, @@ -960,7 +960,7 @@ fn enable_rewards_after_shielding() -> Result<()> { "1000000", "--node", RPC, - ], + ]), ) }); assert!(captured.result.is_ok(), "{:?}", captured.result); @@ -1111,7 +1111,7 @@ fn enable_rewards_after_shielding() -> Result<()> { run( &node, Bin::Client, - vec![ + apply_use_device(vec![ "unshield", "--source", A_SPENDING_KEY, @@ -1125,7 +1125,7 @@ fn enable_rewards_after_shielding() -> Result<()> { BERTHA_KEY, "--node", RPC, - ], + ]), ) }); assert!(captured.result.is_ok(), "{:?}", captured.result); @@ -1171,7 +1171,7 @@ fn enable_rewards_after_shielding() -> Result<()> { run( &node, Bin::Client, - vec![ + apply_use_device(vec![ "shield", "--source", BERTHA, @@ -1183,7 +1183,7 @@ fn enable_rewards_after_shielding() -> Result<()> { "1000000", "--node", RPC, - ], + ]), ) }); assert!(captured.result.is_ok(), "{:?}", captured.result); @@ -1273,7 +1273,7 @@ fn enable_rewards_after_shielding() -> Result<()> { run( &node, Bin::Client, - vec![ + apply_use_device(vec![ "unshield", "--source", A_SPENDING_KEY, @@ -1287,7 +1287,7 @@ fn enable_rewards_after_shielding() -> Result<()> { BERTHA_KEY, "--node", RPC, - ], + ]), ) }); assert!(captured.result.is_ok(), "{:?}", captured.result); @@ -1330,7 +1330,7 @@ fn enable_rewards_after_shielding() -> Result<()> { run( &node, Bin::Client, - vec![ + apply_use_device(vec![ "transfer", "--source", A_SPENDING_KEY, @@ -1344,7 +1344,7 @@ fn enable_rewards_after_shielding() -> Result<()> { BERTHA_KEY, "--node", RPC, - ], + ]), ) }); assert!(captured.result.is_ok(), "{:?}", captured.result); @@ -1387,7 +1387,7 @@ fn enable_rewards_after_shielding() -> Result<()> { run( &node, Bin::Client, - vec![ + apply_use_device(vec![ "unshield", "--source", A_SPENDING_KEY, @@ -1401,7 +1401,7 @@ fn enable_rewards_after_shielding() -> Result<()> { BERTHA_KEY, "--node", RPC, - ], + ]), ) }); assert!(captured.result.is_ok(), "{:?}", captured.result); @@ -2757,6 +2757,10 @@ fn multiple_unfetched_txs_same_block() -> Result<()> { let (mut node, _services) = setup::setup()?; _ = node.next_epoch(); + // Initialize accounts we can access the secret keys of + let (cooper_alias, cooper_key) = + make_temp_account(&node, validator_one_rpc, "Cooper", NAM, 500_000)?; + // 1. Shield tokens _ = node.next_epoch(); let captured = CapturedOutput::of(|| { @@ -2890,7 +2894,7 @@ fn multiple_unfetched_txs_same_block() -> Result<()> { "--amount", "50", "--gas-payer", - CHRISTEL_KEY, + cooper_alias.as_ref(), "--output-folder-path", tempdir.path().to_str().unwrap(), "--dump-tx", @@ -2927,7 +2931,7 @@ fn multiple_unfetched_txs_same_block() -> Result<()> { "--amount", "50", "--gas-payer", - CHRISTEL_KEY, + cooper_alias.as_ref(), "--output-folder-path", tempdir.path().to_str().unwrap(), "--dump-tx", @@ -2949,9 +2953,7 @@ fn multiple_unfetched_txs_same_block() -> Result<()> { txs_bytes.push(std::fs::read(&file_path).unwrap()); std::fs::remove_file(&file_path).unwrap(); - let sk = get_unencrypted_keypair( - &ensure_hot_key(CHRISTEL_KEY).to_ascii_lowercase(), - ); + let sk = cooper_key; let pk = sk.to_public(); let native_token = node @@ -2997,6 +2999,10 @@ fn expired_masp_tx() -> Result<()> { let (mut node, _services) = setup::setup()?; _ = node.next_epoch(); + // Initialize accounts we can access the secret keys of + let (cooper_alias, cooper_key) = + make_temp_account(&node, validator_one_rpc, "Cooper", NAM, 500_000)?; + // 1. Shield tokens _ = node.next_epoch(); run( @@ -3043,7 +3049,7 @@ fn expired_masp_tx() -> Result<()> { "--amount", "50", "--gas-payer", - CHRISTEL_KEY, + cooper_alias.as_ref(), // We want to create an expired masp tx. Doing so will also set // the expiration field of the header which can // be a problem because this would lead to the @@ -3077,9 +3083,7 @@ fn expired_masp_tx() -> Result<()> { let tx_bytes = std::fs::read(&file_path).unwrap(); std::fs::remove_file(&file_path).unwrap(); - let sk = get_unencrypted_keypair( - &ensure_hot_key(CHRISTEL_KEY).to_ascii_lowercase(), - ); + let sk = cooper_key; let pk = sk.to_public(); let native_token = node @@ -3337,7 +3341,7 @@ fn dynamic_assets() -> Result<()> { }); assert!(captured.result.is_ok()); assert!(captured.contains(TX_APPLIED_SUCCESS)); - + // sync the shielded context run( &node, @@ -3473,7 +3477,7 @@ fn dynamic_assets() -> Result<()> { }); assert!(captured.result.is_ok()); assert!(captured.contains(TX_APPLIED_SUCCESS)); - + // sync the shielded context run( &node, @@ -3802,7 +3806,7 @@ fn dynamic_assets() -> Result<()> { run( &node, Bin::Client, - vec![ + apply_use_device(vec![ "unshield", "--source", A_SPENDING_KEY, @@ -3816,7 +3820,7 @@ fn dynamic_assets() -> Result<()> { BERTHA_KEY, "--ledger-address", validator_one_rpc, - ], + ]), ) }); assert!(captured.result.is_ok()); @@ -3853,7 +3857,7 @@ fn dynamic_assets() -> Result<()> { run( &node, Bin::Client, - vec![ + apply_use_device(vec![ "unshield", "--source", A_SPENDING_KEY, @@ -3867,7 +3871,7 @@ fn dynamic_assets() -> Result<()> { BERTHA_KEY, "--ledger-address", validator_one_rpc, - ], + ]), ) }); assert!(captured.result.is_ok()); @@ -3941,7 +3945,7 @@ fn masp_fee_payment() -> Result<()> { }); assert!(captured.result.is_ok()); assert!(captured.contains(TX_APPLIED_SUCCESS)); - + _ = node.next_masp_epoch(); // sync shielded context run( @@ -4026,7 +4030,7 @@ fn masp_fee_payment() -> Result<()> { run( &node, Bin::Client, - vec![ + apply_use_device(vec![ "transparent-transfer", "--source", ALBERT_KEY, @@ -4040,7 +4044,7 @@ fn masp_fee_payment() -> Result<()> { CHRISTEL_KEY, "--ledger-address", validator_one_rpc, - ], + ]), ) }); assert!(captured.result.is_ok()); @@ -4070,7 +4074,7 @@ fn masp_fee_payment() -> Result<()> { run( &node, Bin::Client, - vec![ + apply_use_device(vec![ "transparent-transfer", "--source", BERTHA_KEY, @@ -4086,7 +4090,7 @@ fn masp_fee_payment() -> Result<()> { validator_one_rpc, // Force to skip check in client "--force", - ], + ]), ) }); assert!(captured.result.is_err()); @@ -4136,7 +4140,7 @@ fn masp_fee_payment() -> Result<()> { }); assert!(captured.result.is_ok()); assert!(captured.contains(TX_APPLIED_SUCCESS)); - + // sync shielded context run( &node, @@ -4945,6 +4949,12 @@ fn identical_output_descriptions() -> Result<()> { _ = node.next_masp_epoch(); let tempdir = tempfile::tempdir().unwrap(); + // Initialize accounts we can access the secret keys of + let (adam_alias, adam_key) = + make_temp_account(&node, validator_one_rpc, "Adam", NAM, 500_000)?; + let (bradley_alias, bradley_key) = + make_temp_account(&node, validator_one_rpc, "Bradley", NAM, 500_000)?; + // Generate a tx to shield some tokens let captured = CapturedOutput::of(|| { run( @@ -4953,7 +4963,7 @@ fn identical_output_descriptions() -> Result<()> { apply_use_device(vec![ "shield", "--source", - ensure_hot_key(ALBERT_KEY), + adam_alias.as_ref(), "--target", AA_PAYMENT_ADDRESS, "--token", @@ -4961,7 +4971,7 @@ fn identical_output_descriptions() -> Result<()> { "--amount", "1000", "--gas-payer", - ensure_hot_key(ALBERT_KEY), + bradley_alias.as_ref(), "--output-folder-path", tempdir.path().to_str().unwrap(), "--dump-wrapper-tx", @@ -4971,7 +4981,7 @@ fn identical_output_descriptions() -> Result<()> { ) }); assert!(captured.result.is_ok()); - + let file_path = tempdir .path() .read_dir() @@ -4989,15 +4999,12 @@ fn identical_output_descriptions() -> Result<()> { let mut tx_clone = tx.clone(); tx_clone.add_memo(&[1, 2, 3]); - let keypair = get_unencrypted_keypair( - &ensure_hot_key(ALBERT_KEY).to_ascii_lowercase(), - ); let signing_data = SigningTxData { owner: None, - public_keys: vec![keypair.to_public()], + public_keys: vec![adam_key.to_public()], threshold: 1, account_public_keys_map: None, - fee_payer: keypair.to_public(), + fee_payer: adam_key.to_public(), shielded_hash: None, }; @@ -5008,13 +5015,13 @@ fn identical_output_descriptions() -> Result<()> { .unwrap(); batched_tx.sign_raw( - vec![keypair.clone()], + vec![adam_key.clone()], AccountPublicKeysMap::from_iter( - vec![(keypair.to_public())].into_iter(), + vec![(adam_key.to_public())].into_iter(), ), None, ); - batched_tx.sign_wrapper(keypair); + batched_tx.sign_wrapper(bradley_key); let wrapper_hash = batched_tx.wrapper_hash(); let inner_cmts = batched_tx.commitments(); @@ -5096,7 +5103,7 @@ fn identical_output_descriptions() -> Result<()> { vec![ "balance", "--owner", - ALBERT_KEY, + adam_alias.as_ref(), "--token", NAM, "--node", @@ -5105,7 +5112,7 @@ fn identical_output_descriptions() -> Result<()> { ) }); assert!(captured.result.is_ok()); - assert!(captured.contains("nam: 1998000")); + assert!(captured.contains("nam: 498000")); let captured = CapturedOutput::of(|| { run( @@ -5314,14 +5321,20 @@ fn masp_batch() -> Result<()> { for (tx0, tx1) in [(tx0.clone(), tx1.clone()), (tx1, tx0)] { let (mut batched_tx, _signing_data) = namada_sdk::tx::build_batch(vec![ - (tx0.clone(), SigningTxData { - shielded_hash: get_shielded_hash(&tx0), - ..signing_data.clone() - }), - (tx1.clone(), SigningTxData { - shielded_hash: get_shielded_hash(&tx1), - ..signing_data.clone() - }), + ( + tx0.clone(), + SigningTxData { + shielded_hash: get_shielded_hash(&tx0), + ..signing_data.clone() + }, + ), + ( + tx1.clone(), + SigningTxData { + shielded_hash: get_shielded_hash(&tx1), + ..signing_data.clone() + }, + ), ]) .unwrap(); batched_tx.header.atomic = false; @@ -5563,14 +5576,20 @@ fn masp_atomic_batch() -> Result<()> { for (tx0, tx1) in [(tx0.clone(), tx1.clone()), (tx1, tx0)] { let (mut batched_tx, _signing_data) = namada_sdk::tx::build_batch(vec![ - (tx0.clone(), SigningTxData { - shielded_hash: get_shielded_hash(&tx0), - ..signing_data.clone() - }), - (tx1.clone(), SigningTxData { - shielded_hash: get_shielded_hash(&tx1), - ..signing_data.clone() - }), + ( + tx0.clone(), + SigningTxData { + shielded_hash: get_shielded_hash(&tx0), + ..signing_data.clone() + }, + ), + ( + tx1.clone(), + SigningTxData { + shielded_hash: get_shielded_hash(&tx1), + ..signing_data.clone() + }, + ), ]) .unwrap(); batched_tx.header.atomic = true;