Skip to content

Commit

Permalink
Now use WalletUtils as a backup for when alias/password parameters ar…
Browse files Browse the repository at this point in the history
…e not supplied.
  • Loading branch information
murisi committed Feb 11, 2023
1 parent cc62475 commit fd98fda
Show file tree
Hide file tree
Showing 11 changed files with 102 additions and 50 deletions.
8 changes: 4 additions & 4 deletions apps/src/bin/namada-wallet/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ fn address_key_find(
println!("Viewing key: {}", viewing_key);
if unsafe_show_secret {
// Check if alias is also a spending key
match wallet.find_spending_key(&alias) {
match wallet.find_spending_key(&alias, None) {
Ok(spending_key) => println!("Spending key: {}", spending_key),
Err(FindKeyError::KeyNotFound) => {}
Err(err) => eprintln!("{}", err),
Expand Down Expand Up @@ -331,7 +331,7 @@ fn key_find(
) {
let mut wallet = ctx.wallet;
let found_keypair = match public_key {
Some(pk) => wallet.find_key_by_pk(&pk),
Some(pk) => wallet.find_key_by_pk(&pk, None),
None => {
let alias = alias.or(value);
match alias {
Expand All @@ -342,7 +342,7 @@ fn key_find(
);
cli::safe_exit(1)
}
Some(alias) => wallet.find_key(alias.to_lowercase()),
Some(alias) => wallet.find_key(alias.to_lowercase(), None),
}
}
};
Expand Down Expand Up @@ -414,7 +414,7 @@ fn key_list(
fn key_export(ctx: Context, args::KeyExport { alias }: args::KeyExport) {
let mut wallet = ctx.wallet;
wallet
.find_key(alias.to_lowercase())
.find_key(alias.to_lowercase(), None)
.map(|keypair| {
let file_data = keypair
.try_to_vec()
Expand Down
4 changes: 3 additions & 1 deletion apps/src/lib/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2813,6 +2813,7 @@ pub mod args {
signing_key: self.signing_key.map(|x| ctx.get_cached(&x)),
signer: self.signer.map(|x| ctx.get(&x)),
tx_code_path: ctx.read_wasm(self.tx_code_path),
password: self.password,
}
}
}
Expand Down Expand Up @@ -2877,10 +2878,10 @@ pub mod args {
let fee_amount = GAS_AMOUNT.parse(matches);
let fee_token = GAS_TOKEN.parse(matches);
let gas_limit = GAS_LIMIT.parse(matches).into();

let signing_key = SIGNING_KEY_OPT.parse(matches);
let signer = SIGNER.parse(matches);
let tx_code_path = PathBuf::from(TX_REVEAL_PK);
let password = None;
Self {
dry_run,
force,
Expand All @@ -2893,6 +2894,7 @@ pub mod args {
signing_key,
signer,
tx_code_path,
password,
}
}
}
Expand Down
8 changes: 4 additions & 4 deletions apps/src/lib/cli/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -347,7 +347,7 @@ impl ArgFromMutContext for common::SecretKey {
FromStr::from_str(raw).or_else(|_parse_err| {
// Or it can be an alias
ctx.wallet
.find_key(raw)
.find_key(raw, None)
.map_err(|_find_err| format!("Unknown key {}", raw))
})
}
Expand All @@ -364,13 +364,13 @@ impl ArgFromMutContext for common::PublicKey {
// Or it can be a public key hash in hex string
FromStr::from_str(raw)
.map(|pkh: PublicKeyHash| {
let key = ctx.wallet.find_key_by_pkh(&pkh).unwrap();
let key = ctx.wallet.find_key_by_pkh(&pkh, None).unwrap();
key.ref_to()
})
// Or it can be an alias that may be found in the wallet
.or_else(|_parse_err| {
ctx.wallet
.find_key(raw)
.find_key(raw, None)
.map(|x| x.ref_to())
.map_err(|x| x.to_string())
})
Expand All @@ -388,7 +388,7 @@ impl ArgFromMutContext for ExtendedSpendingKey {
FromStr::from_str(raw).or_else(|_parse_err| {
// Or it is a stored alias of one
ctx.wallet
.find_spending_key(raw)
.find_spending_key(raw, None)
.map_err(|_find_err| format!("Unknown spending key {}", raw))
})
}
Expand Down
3 changes: 2 additions & 1 deletion apps/src/lib/client/signing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ pub async fn find_keypair<
wallet: &mut Wallet<U>,
addr: &Address,
) -> Result<common::SecretKey, tx::Error> {
namada::ledger::signing::find_keypair::<C, U>(client, wallet, addr).await
namada::ledger::signing::find_keypair::<C, U>(client, wallet, addr, None)
.await
}

/// Given CLI arguments and some defaults, determine the rightful transaction
Expand Down
2 changes: 1 addition & 1 deletion apps/src/lib/node/ledger/shell/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -653,7 +653,7 @@ where
let pk = common::SecretKey::deserialize(&mut pk_bytes.as_slice())
.expect("Validator's public key should be deserializable")
.ref_to();
wallet.find_key_by_pk(&pk).expect(
wallet.find_key_by_pk(&pk, None).expect(
"A validator's established keypair should be stored in its \
wallet",
)
Expand Down
2 changes: 1 addition & 1 deletion apps/src/lib/wallet/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ pub fn gen_validator_keys(
) -> Result<ValidatorKeys, FindKeyError> {
let protocol_keypair = protocol_pk.map(|pk| {
wallet
.find_key_by_pkh(&PublicKeyHash::from(&pk))
.find_key_by_pkh(&PublicKeyHash::from(&pk), None)
.ok()
.or_else(|| {
wallet
Expand Down
2 changes: 2 additions & 0 deletions shared/src/ledger/args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -380,6 +380,8 @@ pub struct Tx<C: NamadaTypes = SdkTypes> {
pub signer: Option<C::Address>,
/// Path to the TX WASM code file
pub tx_code_path: C::Data,
/// Password to decrypt key
pub password: Option<String>,
}

/// MASP add key or address arguments
Expand Down
18 changes: 13 additions & 5 deletions shared/src/ledger/signing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,17 @@ use crate::types::storage::Epoch;
use crate::types::transaction::{hash_tx, Fee, WrapperTx};

/// Find the public key for the given address and try to load the keypair
/// for it from the wallet. Errors if the key cannot be found or loaded.
/// for it from the wallet. If the keypair is encrypted but a password is not
/// supplied, then it is interactively prompted. Errors if the key cannot be
/// found or loaded.
pub async fn find_keypair<
C: crate::ledger::queries::Client + Sync,
U: WalletUtils,
>(
client: &C,
wallet: &mut Wallet<U>,
addr: &Address,
password: Option<String>,
) -> Result<common::SecretKey, Error> {
match addr {
Address::Established(_) => {
Expand All @@ -33,7 +36,7 @@ pub async fn find_keypair<
addr.encode()
)),
)?;
wallet.find_key_by_pk(&public_key).map_err(|err| {
wallet.find_key_by_pk(&public_key, password).map_err(|err| {
Error::Other(format!(
"Unable to load the keypair from the wallet for public \
key {}. Failed with: {}",
Expand All @@ -42,7 +45,7 @@ pub async fn find_keypair<
})
}
Address::Implicit(ImplicitAddress(pkh)) => {
wallet.find_key_by_pkh(pkh).map_err(|err| {
wallet.find_key_by_pkh(pkh, password).map_err(|err| {
Error::Other(format!(
"Unable to load the keypair from the wallet for the \
implicit address {}. Failed with: {}",
Expand Down Expand Up @@ -98,8 +101,13 @@ pub async fn tx_signer<
TxSigningKey::WalletKeypair(signing_key) => Ok(signing_key),
TxSigningKey::WalletAddress(signer) => {
let signer = signer;
let signing_key =
find_keypair::<C, U>(client, wallet, &signer).await?;
let signing_key = find_keypair::<C, U>(
client,
wallet,
&signer,
args.password.clone(),
)
.await?;
// Check if the signer is implicit account that needs to reveal its
// PK first
if matches!(signer, Address::Implicit(_)) {
Expand Down
5 changes: 3 additions & 2 deletions shared/src/ledger/tx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -276,9 +276,10 @@ pub async fn submit_reveal_pk_aux<
Ok(signing_key.clone())
} else if let Some(signer) = args.signer.as_ref() {
let signer = signer;
find_keypair::<C, U>(client, wallet, signer).await
find_keypair::<C, U>(client, wallet, signer, args.password.clone())
.await
} else {
find_keypair::<C, U>(client, wallet, &addr).await
find_keypair::<C, U>(client, wallet, &addr, args.password.clone()).await
}?;
let epoch = rpc::query_epoch(client).await;
let to_broadcast = if args.dry_run {
Expand Down
64 changes: 51 additions & 13 deletions shared/src/ledger/wallet/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ mod store;

use std::collections::HashMap;
use std::fmt::Display;
use std::marker::PhantomData;
use std::str::FromStr;

pub use alias::Alias;
Expand Down Expand Up @@ -43,6 +44,29 @@ pub trait WalletUtils {
) -> store::ConfirmationResponse;
}

/// A degenerate implementation of wallet interactivity
pub struct SdkWalletUtils<U>(PhantomData<U>);

impl<U> WalletUtils for SdkWalletUtils<U> {
type Storage = U;

fn read_password(_prompt_msg: &str) -> String {
panic!("attempted to prompt for password in non-interactive mode");
}

fn read_alias(_prompt_msg: &str) -> String {
panic!("attempted to prompt for alias in non-interactive mode");
}

fn show_overwrite_confirmation(
_alias: &Alias,
_alias_for: &str,
) -> store::ConfirmationResponse {
// Automatically replace aliases in non-interactive mode
store::ConfirmationResponse::Replace
}
}

/// The error that is produced when a given key cannot be obtained
#[derive(Error, Debug)]
pub enum FindKeyError {
Expand Down Expand Up @@ -127,12 +151,13 @@ impl<U: WalletUtils> Wallet<U> {
}

/// Find the stored key by an alias, a public key hash or a public key.
/// If the key is encrypted, will prompt for password from stdin.
/// Any keys that are decrypted are stored in and read from a cache to avoid
/// prompting for password multiple times.
/// If the key is encrypted and password not supplied, then password will be
/// interactively prompted. Any keys that are decrypted are stored in and
/// read from a cache to avoid prompting for password multiple times.
pub fn find_key(
&mut self,
alias_pkh_or_pk: impl AsRef<str>,
password: Option<String>,
) -> Result<common::SecretKey, FindKeyError> {
// Try cache first
if let Some(cached_key) = self
Expand All @@ -150,13 +175,17 @@ impl<U: WalletUtils> Wallet<U> {
&mut self.decrypted_key_cache,
stored_key,
alias_pkh_or_pk.into(),
password,
)
}

/// Find the spending key with the given alias in the wallet and return it
/// Find the spending key with the given alias in the wallet and return it.
/// If the spending key is encrypted but a password is not supplied, then it
/// will be interactively prompted.
pub fn find_spending_key(
&mut self,
alias: impl AsRef<str>,
password: Option<String>,
) -> Result<ExtendedSpendingKey, FindKeyError> {
// Try cache first
if let Some(cached_key) =
Expand All @@ -173,6 +202,7 @@ impl<U: WalletUtils> Wallet<U> {
&mut self.decrypted_spendkey_cache,
stored_spendkey,
alias.into(),
password,
)
}

Expand All @@ -196,12 +226,13 @@ impl<U: WalletUtils> Wallet<U> {
}

/// Find the stored key by a public key.
/// If the key is encrypted, will prompt for password from stdin.
/// Any keys that are decrypted are stored in and read from a cache to avoid
/// prompting for password multiple times.
/// If the key is encrypted and password not supplied, then password will be
/// interactively prompted for. Any keys that are decrypted are stored in
/// and read from a cache to avoid prompting for password multiple times.
pub fn find_key_by_pk(
&mut self,
pk: &common::PublicKey,
password: Option<String>,
) -> Result<common::SecretKey, FindKeyError> {
// Try to look-up alias for the given pk. Otherwise, use the PKH string.
let pkh: PublicKeyHash = pk.into();
Expand All @@ -222,16 +253,18 @@ impl<U: WalletUtils> Wallet<U> {
&mut self.decrypted_key_cache,
stored_key,
alias,
password,
)
}

/// Find the stored key by a public key hash.
/// If the key is encrypted, will prompt for password from stdin.
/// Any keys that are decrypted are stored in and read from a cache to avoid
/// prompting for password multiple times.
/// If the key is encrypted and password is not supplied, then password will
/// be interactively prompted for. Any keys that are decrypted are stored in
/// and read from a cache to avoid prompting for password multiple times.
pub fn find_key_by_pkh(
&mut self,
pkh: &PublicKeyHash,
password: Option<String>,
) -> Result<common::SecretKey, FindKeyError> {
// Try to look-up alias for the given pk. Otherwise, use the PKH string.
let alias = self
Expand All @@ -251,25 +284,30 @@ impl<U: WalletUtils> Wallet<U> {
&mut self.decrypted_key_cache,
stored_key,
alias,
password,
)
}

/// Decrypt stored key, if it's not stored un-encrypted.
/// If a given storage key needs to be decrypted, prompt for password from
/// stdin and if successfully decrypted, store it in a cache.
/// If a given storage key needs to be decrypted and password is not
/// supplied, then interactively prompt for password and if successfully
/// decrypted, store it in a cache.
fn decrypt_stored_key<
T: FromStr + Display + BorshSerialize + BorshDeserialize + Clone,
>(
decrypted_key_cache: &mut HashMap<Alias, T>,
stored_key: &StoredKeypair<T>,
alias: Alias,
password: Option<String>,
) -> Result<T, FindKeyError>
where
<T as std::str::FromStr>::Err: Display,
{
match stored_key {
StoredKeypair::Encrypted(encrypted) => {
let password = U::read_password("Enter decryption password: ");
let password = password.unwrap_or_else(|| {
U::read_password("Enter decryption password: ")
});
let key = encrypted
.decrypt(password)
.map_err(FindKeyError::KeyDecryptionError)?;
Expand Down
36 changes: 18 additions & 18 deletions wasm/checksums.json
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
{
"tx_bond.wasm": "tx_bond.8dd78cddd65198c913edd032d8e2d864d5995c57808f69a4108f307187f16fdc.wasm",
"tx_change_validator_commission.wasm": "tx_change_validator_commission.0cd7df497599d34bc9c4f3614768e362e8d96e4169c2ee700060a5c9349c4ee0.wasm",
"tx_ibc.wasm": "tx_ibc.f67ddffe00c5c8273c17de95d25822c99c59427712c7ac114cd77086ef32adcc.wasm",
"tx_init_account.wasm": "tx_init_account.39a30513f8b5f7fa89c597c936ad69143c5e97c0cc4f0b11b49b2140c03c1735.wasm",
"tx_init_proposal.wasm": "tx_init_proposal.313b6facdc6a8d350d7319bad7fc71b78ee14225739e4cd670bd6d07aac1faf4.wasm",
"tx_init_validator.wasm": "tx_init_validator.85ef7aac819377bc0e601feb265908fc0aad56df9b6f02138ad80e51eba68935.wasm",
"tx_reveal_pk.wasm": "tx_reveal_pk.4863466a5464833bd1203411d4eb549cb87848f7e2c9c7b45f5c73e5122e022d.wasm",
"tx_transfer.wasm": "tx_transfer.ca670e5a21b23dc7d214fa8eff053cb2818067930a31f086621b4120a9a5f947.wasm",
"tx_unbond.wasm": "tx_unbond.f2aee3b86de8d5533d08ab3ede8cc7f333364a8a4221128e75ac6769afa46e8d.wasm",
"tx_update_vp.wasm": "tx_update_vp.077679787c5c2c67884503032295b13fe24a913cc32a03bd03bcb5c60b917ff9.wasm",
"tx_vote_proposal.wasm": "tx_vote_proposal.d92d32836372561a12bde8d36100b63b135b6a7da0a7878dd4af9744a7e5c023.wasm",
"tx_withdraw.wasm": "tx_withdraw.5fd90d417a90695b6b5ce5f4662b6c6b4d5c24377caa2056868fdded4f7753c0.wasm",
"vp_implicit.wasm": "vp_implicit.f92f68a709ff250272f3c70125f2f8bf15eeccb0f463ec119b5b7c4203cb6541.wasm",
"vp_masp.wasm": "vp_masp.e5b2294b67928573d79fe44409c46e5a504633125461d0b1cd868b7889854f57.wasm",
"vp_testnet_faucet.wasm": "vp_testnet_faucet.449e39c73fec113f3d2a5f3a0b7569933a89a0ffbff62ca5891851b036115b62.wasm",
"vp_token.wasm": "vp_token.533f6662665a1a2a59968cdc93f87e87f31dc6268075f83355880a6fdca406be.wasm",
"vp_user.wasm": "vp_user.b09918e5e083ffcfbde4710c75f9903b651ffcbe7beaf8e737250b4de3c9986d.wasm",
"vp_validator.wasm": "vp_validator.939832589c41e0b29c629cbca00de695fb882888d7fd9e84e8c42cb1daab4dde.wasm"
"tx_bond.wasm": "tx_bond.fd0584036bed91278878e939ca75d1d1eea1356b08652d9802a33ae7d40e63a1.wasm",
"tx_change_validator_commission.wasm": "tx_change_validator_commission.7d8ebecc8001aa06b19bfb58852044ce5c928ba63ef0681532d329092b2c07d2.wasm",
"tx_ibc.wasm": "tx_ibc.621225d32e24f0a6a62d496d360398e0211b45d0b044e62ad776b667dae2e5b0.wasm",
"tx_init_account.wasm": "tx_init_account.05a2fd217ca9a8fca2a3b145b78fa4677cd6f236c7ef4090fe96803555923c68.wasm",
"tx_init_proposal.wasm": "tx_init_proposal.5f8d4e0956dd908eb9a5a93fa8705ce57a3f0375acb57993e1ed88efdd3be75a.wasm",
"tx_init_validator.wasm": "tx_init_validator.79e1d78674a1ec7fdaab5adee0965222401625892eb0e75b1ce4b1d83f521d8b.wasm",
"tx_reveal_pk.wasm": "tx_reveal_pk.0db1e35f022e3efbcc974409fcbe0ded8062a38fe015002b87c6da396688c28e.wasm",
"tx_transfer.wasm": "tx_transfer.047e3ab42ddeb3e045db4ca0e3c3896edaf392cf98563ac17e40ecd3d155c612.wasm",
"tx_unbond.wasm": "tx_unbond.e01b0032a40beaf212611a03240be463c855841a5d446425090b2438c71b2dc9.wasm",
"tx_update_vp.wasm": "tx_update_vp.e19d594ea1eced596b96b21ce4a8513be4f8859d807a80b3fbe57d4f67fe93fc.wasm",
"tx_vote_proposal.wasm": "tx_vote_proposal.fcd7372363098e5905f133e48b713b186234640f575cf25100154c9ce1218507.wasm",
"tx_withdraw.wasm": "tx_withdraw.0fbc63d71a67e5c6d6c3bc1e25e99f1ebcdf4b9335fadf73c555984e05190e39.wasm",
"vp_implicit.wasm": "vp_implicit.a5798a2500270bfd286552f43e52abc3ba3a2844966595b2aa46d20c6b4a32db.wasm",
"vp_masp.wasm": "vp_masp.a055ca419be1fb826c912b1f37dc01a70e75d6b7672924bcfc8fe4eb6730e7db.wasm",
"vp_testnet_faucet.wasm": "vp_testnet_faucet.0bbb333a4f6947d52c2c73b6d99abb4d482961e487a0dca72c6278bc1e883485.wasm",
"vp_token.wasm": "vp_token.9cd955a27b2bcc98849185faa35cdd3debe1573cdae08a841a04fddd86ef65c9.wasm",
"vp_user.wasm": "vp_user.27c17d97530284f1690273ef8affe1925153dedbf05d8556bfe9178be18ad866.wasm",
"vp_validator.wasm": "vp_validator.42db54ef509b4310cb984e04fa76ff1861775dfe54e6cb0187a072322d819df7.wasm"
}

0 comments on commit fd98fda

Please sign in to comment.