From baf1b41e35ac7b7ad3a2aa26eac172b43daa5aa6 Mon Sep 17 00:00:00 2001 From: moana Date: Thu, 3 Oct 2024 19:16:30 +0200 Subject: [PATCH 1/2] rusk-wallet: WIP fix address management --- rusk-wallet/src/bin/command.rs | 175 ++++++----- rusk-wallet/src/bin/interactive.rs | 46 ++- rusk-wallet/src/clients.rs | 6 +- rusk-wallet/src/lib.rs | 1 - rusk-wallet/src/wallet.rs | 482 ++++++++++++++--------------- rusk-wallet/src/wallet/address.rs | 29 +- 6 files changed, 391 insertions(+), 348 deletions(-) diff --git a/rusk-wallet/src/bin/command.rs b/rusk-wallet/src/bin/command.rs index fa50c3756..fcffc3690 100644 --- a/rusk-wallet/src/bin/command.rs +++ b/rusk-wallet/src/bin/command.rs @@ -474,22 +474,22 @@ impl Command { } } - let addr = match addr { + let addr_idx = match addr { Some(addr) => wallet.claim_as_address(addr)?, - None => wallet.default_address(), + None => 0, }; - let balance = wallet.get_phoenix_balance(addr).await?; + let balance = wallet.get_phoenix_balance(addr_idx).await?; Ok(RunResult::PhoenixBalance(balance, spendable)) } Command::MoonlightBalance { addr } => { - let addr = match addr { + let addr_idx = match addr { Some(addr) => wallet.claim_as_address(addr)?, - None => wallet.default_address(), + None => 0, }; Ok(RunResult::MoonlightBalance( - wallet.get_moonlight_balance(addr).await?, + wallet.get_moonlight_balance(addr_idx).await?, )) } Command::Addresses { new } => { @@ -501,11 +501,23 @@ impl Command { std::process::exit(0); } - let addr = wallet.new_address().clone(); + let phoenix_addr = wallet.new_phoenix_address().clone(); wallet.save()?; - Ok(RunResult::Address(Box::new(addr))) + Ok(RunResult::Address(Box::new(phoenix_addr))) } else { - Ok(RunResult::Addresses(wallet.addresses().clone())) + let phoenix_addresses = wallet + .addresses() + .iter() + .enumerate() + .map(|(index, (phoenix_pk, _bls_pk))| { + Address::Phoenix { + index: Some(index as u8), + addr: *phoenix_pk, + } + }) + .collect(); + + Ok(RunResult::Addresses(phoenix_addresses)) } } Command::PhoenixTransfer { @@ -516,14 +528,16 @@ impl Command { gas_price, } => { wallet.sync().await?; - let sender = match sndr { + let sender_idx = match sndr { Some(addr) => wallet.claim_as_address(addr)?, - None => wallet.default_address(), + None => 0, }; let gas = Gas::new(gas_limit).with_price(gas_price); + let receiver = rcvr.try_phoenix_pk()?; + let tx = wallet - .phoenix_transfer(sender, &rcvr, None, amt, gas) + .phoenix_transfer(sender_idx, receiver, None, amt, gas) .await?; Ok(RunResult::Tx(tx.hash())) } @@ -536,14 +550,22 @@ impl Command { gas_price, } => { wallet.sync().await?; - let sender = match sndr { + let sender_idx = match sndr { Some(addr) => wallet.claim_as_address(addr)?, - None => wallet.default_address(), + None => 0, }; let gas = Gas::new(gas_limit).with_price(gas_price); + let receiver = rcvr.try_phoenix_pk()?; + let tx = wallet - .phoenix_transfer(sender, &rcvr, Some(memo), amt, gas) + .phoenix_transfer( + sender_idx, + receiver, + Some(memo), + amt, + gas, + ) .await?; Ok(RunResult::Tx(tx.hash())) } @@ -555,13 +577,15 @@ impl Command { gas_price, } => { let gas = Gas::new(gas_limit).with_price(gas_price); - let sender = match sndr { + let sender_idx = match sndr { Some(addr) => wallet.claim_as_address(addr)?, - None => wallet.default_address(), + None => 0, }; + let receiver = rcvr.try_bls_pk()?; + let tx = wallet - .moonlight_transfer(sender, &rcvr, None, amt, gas) + .moonlight_transfer(sender_idx, receiver, None, amt, gas) .await?; Ok(RunResult::Tx(tx.hash())) @@ -575,13 +599,21 @@ impl Command { gas_price, } => { let gas = Gas::new(gas_limit).with_price(gas_price); - let sender = match sndr { + let sender_idx = match sndr { Some(addr) => wallet.claim_as_address(addr)?, - None => wallet.default_address(), + None => 0, }; + let receiver = rcvr.try_bls_pk()?; + let tx = wallet - .moonlight_transfer(sender, &rcvr, Some(memo), amt, gas) + .moonlight_transfer( + sender_idx, + receiver, + Some(memo), + amt, + gas, + ) .await?; Ok(RunResult::Tx(tx.hash())) @@ -594,21 +626,21 @@ impl Command { } => { wallet.sync().await?; let gas = Gas::new(gas_limit).with_price(gas_price); - let addr = match addr { + let addr_idx = match addr { Some(addr) => wallet.claim_as_address(addr)?, - None => wallet.default_address(), + None => 0, }; - let tx = wallet.phoenix_stake(addr, amt, gas).await?; + let tx = wallet.phoenix_stake(addr_idx, amt, gas).await?; Ok(RunResult::Tx(tx.hash())) } Command::StakeInfo { addr, reward } => { - let addr = match addr { + let addr_idx = match addr { Some(addr) => wallet.claim_as_address(addr)?, - None => wallet.default_address(), + None => 0, }; let si = wallet - .stake_info(addr.index()?) + .stake_info(addr_idx) .await? .ok_or(Error::NotStaked)?; @@ -620,14 +652,14 @@ impl Command { gas_price, } => { wallet.sync().await?; - let addr = match addr { + let addr_idx = match addr { Some(addr) => wallet.claim_as_address(addr)?, - None => wallet.default_address(), + None => 0, }; let gas = Gas::new(gas_limit).with_price(gas_price); - let tx = wallet.phoenix_unstake(addr, gas).await?; + let tx = wallet.phoenix_unstake(addr_idx, gas).await?; Ok(RunResult::Tx(tx.hash())) } Command::PhoenixWithdraw { @@ -636,20 +668,20 @@ impl Command { gas_price, } => { wallet.sync().await?; - let addr = match addr { + let addr_idx = match addr { Some(addr) => wallet.claim_as_address(addr)?, - None => wallet.default_address(), + None => 0, }; let gas = Gas::new(gas_limit).with_price(gas_price); - let tx = wallet.phoenix_stake_withdraw(addr, gas).await?; + let tx = wallet.phoenix_stake_withdraw(addr_idx, gas).await?; Ok(RunResult::Tx(tx.hash())) } Command::Export { addr, dir, name } => { - let addr = match addr { + let addr_idx = match addr { Some(addr) => wallet.claim_as_address(addr)?, - None => wallet.default_address(), + None => 0, }; let pwd = prompt::request_auth( @@ -658,18 +690,18 @@ impl Command { wallet.get_file_version()?, )?; - let (pub_key, key_pair) = - wallet.export_provisioner_keys(addr, &dir, name, &pwd)?; + let (pub_key, key_pair) = wallet + .export_provisioner_keys(addr_idx, &dir, name, &pwd)?; Ok(RunResult::ExportedKeys(pub_key, key_pair)) } Command::PhoenixHistory { addr } => { wallet.sync().await?; - let addr = match addr { + let addr_idx = match addr { Some(addr) => wallet.claim_as_address(addr)?, - None => wallet.default_address(), + None => 0, }; - let notes = wallet.get_all_notes(addr).await?; + let notes = wallet.get_all_notes(addr_idx).await?; let transactions = history::transaction_from_notes(settings, notes).await?; @@ -683,14 +715,15 @@ impl Command { amt, } => { wallet.sync().await?; - let addr = match addr { + let addr_idx = match addr { Some(addr) => wallet.claim_as_address(addr)?, - None => wallet.default_address(), + None => 0, }; let gas = Gas::new(gas_limit).with_price(gas_price); - let tx = wallet.phoenix_to_moonlight(addr, amt, gas).await?; + let tx = + wallet.phoenix_to_moonlight(addr_idx, amt, gas).await?; Ok(RunResult::Tx(tx.hash())) } Command::MoonlightToPhoenix { @@ -700,14 +733,15 @@ impl Command { gas_price, } => { wallet.sync().await?; - let addr = match addr { + let addr_idx = match addr { Some(addr) => wallet.claim_as_address(addr)?, - None => wallet.default_address(), + None => 0, }; let gas = Gas::new(gas_limit).with_price(gas_price); - let tx = wallet.moonlight_to_phoenix(addr, amt, gas).await?; + let tx = + wallet.moonlight_to_phoenix(addr_idx, amt, gas).await?; Ok(RunResult::Tx(tx.hash())) } Command::MoonlightStake { @@ -716,14 +750,14 @@ impl Command { gas_limit, gas_price, } => { - let addr = match addr { + let addr_idx = match addr { Some(addr) => wallet.claim_as_address(addr)?, - None => wallet.default_address(), + None => 0, }; let gas = Gas::new(gas_limit).with_price(gas_price); - let tx = wallet.moonlight_stake(addr, amt, gas).await?; + let tx = wallet.moonlight_stake(addr_idx, amt, gas).await?; Ok(RunResult::Tx(tx.hash())) } Command::MoonlightUnstake { @@ -731,14 +765,14 @@ impl Command { gas_limit, gas_price, } => { - let addr = match addr { + let addr_idx = match addr { Some(addr) => wallet.claim_as_address(addr)?, - None => wallet.default_address(), + None => 0, }; let gas = Gas::new(gas_limit).with_price(gas_price); - let tx = wallet.moonlight_unstake(addr, gas).await?; + let tx = wallet.moonlight_unstake(addr_idx, gas).await?; Ok(RunResult::Tx(tx.hash())) } Command::MoonlightWithdraw { @@ -746,14 +780,14 @@ impl Command { gas_limit, gas_price, } => { - let addr = match addr { + let addr_idx = match addr { Some(addr) => wallet.claim_as_address(addr)?, - None => wallet.default_address(), + None => 0, }; let gas = Gas::new(gas_limit).with_price(gas_price); - let tx = wallet.moonlight_stake_withdraw(addr, gas).await?; + let tx = wallet.moonlight_stake_withdraw(addr_idx, gas).await?; Ok(RunResult::Tx(tx.hash())) } @@ -765,9 +799,9 @@ impl Command { gas_limit, gas_price, } => { - let addr = match addr { + let addr_idx = match addr { Some(addr) => wallet.claim_as_address(addr)?, - None => wallet.default_address(), + None => 0, }; let gas = Gas::new(gas_limit).with_price(gas_price); @@ -780,7 +814,7 @@ impl Command { .map_err(|_| Error::Rkyv)?; let tx = wallet - .phoenix_execute(addr, Dusk::from(0), gas, call.into()) + .phoenix_execute(addr_idx, Dusk::from(0), gas, call.into()) .await?; Ok(RunResult::Tx(tx.hash())) @@ -793,9 +827,9 @@ impl Command { gas_limit, gas_price, } => { - let addr = match addr { + let addr_idx = match addr { Some(addr) => wallet.claim_as_address(addr)?, - None => wallet.default_address(), + None => 0, }; let gas = Gas::new(gas_limit).with_price(gas_price); @@ -809,8 +843,7 @@ impl Command { let tx = wallet .moonlight_execute( - addr, - None, + addr_idx, Dusk::from(0), Dusk::from(0), gas, @@ -827,9 +860,9 @@ impl Command { gas_limit, gas_price, } => { - let addr = match addr { + let addr_idx = match addr { Some(addr) => wallet.claim_as_address(addr)?, - None => wallet.default_address(), + None => 0, }; let gas = Gas::new(gas_limit).with_price(gas_price); @@ -841,8 +874,9 @@ impl Command { let code = std::fs::read(code) .map_err(|_| Error::InvalidWasmContractPath)?; - let tx = - wallet.phoenix_deploy(addr, code, init_args, gas).await?; + let tx = wallet + .phoenix_deploy(addr_idx, code, init_args, gas) + .await?; Ok(RunResult::Tx(tx.hash())) } @@ -853,9 +887,9 @@ impl Command { gas_limit, gas_price, } => { - let addr = match addr { + let addr_idx = match addr { Some(addr) => wallet.claim_as_address(addr)?, - None => wallet.default_address(), + None => 0, }; let gas = Gas::new(gas_limit).with_price(gas_price); @@ -867,8 +901,9 @@ impl Command { let code = std::fs::read(code) .map_err(|_| Error::InvalidWasmContractPath)?; - let tx = - wallet.moonlight_deploy(addr, code, init_args, gas).await?; + let tx = wallet + .moonlight_deploy(addr_idx, code, init_args, gas) + .await?; Ok(RunResult::Tx(tx.hash())) } diff --git a/rusk-wallet/src/bin/interactive.rs b/rusk-wallet/src/bin/interactive.rs index c3d0e8e52..8de6fd590 100644 --- a/rusk-wallet/src/bin/interactive.rs +++ b/rusk-wallet/src/bin/interactive.rs @@ -39,7 +39,7 @@ pub(crate) async fn run_loop( std::process::exit(0); } - let addr = wallet.new_address().clone(); + let addr = wallet.new_phoenix_address().clone(); let file_version = wallet.get_file_version()?; let password = &settings.password; @@ -66,11 +66,14 @@ pub(crate) async fn run_loop( AddrSelect::Exit => std::process::exit(0), }; - let index = addr.index()?; - - let moonlight = Address::Bls { - index: Some(index), - addr: wallet.bls_public_key(addr.index()?), + let addr_idx = addr.index()?; + let phoenix_addr = Address::Phoenix { + index: Some(addr_idx), + addr: *wallet.phoenix_pk(addr_idx)?, + }; + let moonlight_addr = Address::Bls { + index: Some(addr_idx), + addr: *wallet.bls_pk(addr_idx)?, }; let is_synced = wallet.is_synced().await?; @@ -78,9 +81,8 @@ pub(crate) async fn run_loop( loop { // get balance for this address prompt::hide_cursor()?; - let moonlight_bal = - wallet.get_moonlight_balance(&moonlight).await?; - let phoenix_bal = wallet.get_phoenix_balance(&addr).await?; + let moonlight_bal = wallet.get_moonlight_balance(addr_idx).await?; + let phoenix_bal = wallet.get_phoenix_balance(addr_idx).await?; let phoenix_spendable = phoenix_bal.spendable.into(); let phoenix_total: Dusk = phoenix_bal.value.into(); @@ -95,7 +97,7 @@ pub(crate) async fn run_loop( "Moonlight Balance", ); } - println!("{0: <20} {moonlight}", "Moonlight Address"); + println!("{0: <20} {moonlight_addr}", "Moonlight Address"); println!(); if is_synced { @@ -105,7 +107,7 @@ pub(crate) async fn run_loop( ); println!("{0: <20} - Total: {phoenix_total}", "",); } - println!("{0: <20} {addr}", "Phoenix Address"); + println!("{0: <20} {phoenix_addr}", "Phoenix Address"); println!(); // request operation to perform @@ -174,9 +176,27 @@ enum AddrSelect { fn menu_addr(wallet: &Wallet) -> anyhow::Result { let mut address_menu = Menu::title("Addresses"); for addr in wallet.addresses() { - let preview = addr.preview(); + // build a phoenix address from the public-key in the address list + let phoenix_addr = Address::Phoenix { + index: None, + addr: addr.0, + }; + let phoenix_preview = phoenix_addr.preview(); + + // build a bls address from the public-key in the address list + let bls_addr = Address::Bls { + index: None, + addr: addr.1, + }; + let bls_preview = bls_addr.preview(); + + // add both addresses to the select menu + address_menu = address_menu.add( + AddrSelect::Address(Box::new(phoenix_addr.clone())), + phoenix_preview, + ); address_menu = address_menu - .add(AddrSelect::Address(Box::new(addr.clone())), preview); + .add(AddrSelect::Address(Box::new(bls_addr.clone())), bls_preview); } let remaining_addresses = diff --git a/rusk-wallet/src/clients.rs b/rusk-wallet/src/clients.rs index 1c13018b3..506db35fa 100644 --- a/rusk-wallet/src/clients.rs +++ b/rusk-wallet/src/clients.rs @@ -8,7 +8,7 @@ mod sync; use dusk_bytes::Serializable; use execution_core::{ - signatures::bls::PublicKey as AccountPublicKey, + signatures::bls::PublicKey as BlsPublicKey, transfer::{ moonlight::AccountData, phoenix::{Note, NoteLeaf, Prove}, @@ -244,7 +244,7 @@ impl State { pub(crate) async fn fetch_account( &self, - pk: &AccountPublicKey, + pk: &BlsPublicKey, ) -> Result { let status = self.status; status("Fetching account-data..."); @@ -283,7 +283,7 @@ impl State { /// Queries the node for the amount staked by a key. pub(crate) async fn fetch_stake( &self, - pk: &AccountPublicKey, + pk: &BlsPublicKey, ) -> Result, Error> { let status = self.status; status("Fetching stake..."); diff --git a/rusk-wallet/src/lib.rs b/rusk-wallet/src/lib.rs index d33eeb3ef..d245afcfc 100644 --- a/rusk-wallet/src/lib.rs +++ b/rusk-wallet/src/lib.rs @@ -38,7 +38,6 @@ pub use wallet::{Address, DecodedNote, SecureWalletFile, Wallet, WalletPath}; use execution_core::{ dusk, from_dusk, - signatures::bls::PublicKey as AccountPublicKey, stake::StakeData, transfer::phoenix::{ ArchivedNoteLeaf, Note, NoteOpening, PublicKey as PhoenixPublicKey, diff --git a/rusk-wallet/src/wallet.rs b/rusk-wallet/src/wallet.rs index ce74ebff1..a60f4489c 100644 --- a/rusk-wallet/src/wallet.rs +++ b/rusk-wallet/src/wallet.rs @@ -70,7 +70,8 @@ use gas::Gas; /// able to perform common operations such as checking balance, transfernig /// funds, or staking Dusk. pub struct Wallet { - addresses: Vec
, + // change this to `Vec<(Address, Address)>` + addresses: Vec<(PhoenixPublicKey, BlsPublicKey)>, state: Option, store: LocalStore, file: Option, @@ -82,30 +83,6 @@ impl Wallet { pub fn file(&self) -> &Option { &self.file } - - /// Returns Phoenix key pair for a given address - /// - /// # Errors - /// - /// - If the Address provided is not a Phoenix address - /// - If the address is not owned - pub fn phoenix_keys( - &self, - addr: &Address, - ) -> Result<(PhoenixPublicKey, PhoenixSecretKey), Error> { - // make sure we own the address - if !addr.is_owned() { - return Err(Error::Unauthorized); - } - - let index = addr.index()?; - - // retrieve keys - let sk = self.phoenix_secret_key(index); - let pk = addr.pk()?; - - Ok((*pk, sk)) - } } impl Wallet { @@ -123,19 +100,19 @@ impl Wallet { // derive the mnemonic seed let seed = Seed::new(&mnemonic, ""); // Takes the mnemonic seed as bytes - let bytes = seed.as_bytes().try_into().unwrap(); + let seed_bytes = seed.as_bytes().try_into().unwrap(); - // Generate the default address - let address = Address::Phoenix { - index: Some(0), - addr: derive_phoenix_pk(&bytes, 0), - }; + // Generate the default address at index 0 + let addresses = vec![( + derive_phoenix_pk(&seed_bytes, 0), + derive_bls_pk(&seed_bytes, 0), + )]; // return new wallet instance Ok(Wallet { - addresses: vec![address], + addresses, state: None, - store: LocalStore::from(bytes), + store: LocalStore::from(seed_bytes), file: None, file_version: None, }) @@ -165,14 +142,13 @@ impl Wallet { // return early if its legacy if let DatFileVersion::Legacy = file_version { - let address = Address::Phoenix { - index: Some(0), - addr: derive_phoenix_pk(&seed, 0), - }; + // Generate the default address at index 0 + let addresses = + vec![(derive_phoenix_pk(&seed, 0), derive_bls_pk(&seed, 0))]; // return the store return Ok(Self { - addresses: vec![address], + addresses, store: LocalStore::from(seed), state: None, file: Some(file), @@ -181,10 +157,7 @@ impl Wallet { } let addresses: Vec<_> = (0..address_count) - .map(|i| Address::Phoenix { - index: Some(i), - addr: derive_phoenix_pk(&seed, i), - }) + .map(|i| (derive_phoenix_pk(&seed, i), derive_bls_pk(&seed, i))) .collect(); // create and return @@ -316,17 +289,10 @@ impl Wallet { /// Fetches the notes from the state. pub async fn get_all_notes( &self, - addr: &Address, + addr_idx: u8, ) -> Result, Error> { - if !addr.is_owned() { - return Err(Error::Unauthorized); - } - - let seed = self.store.get_seed(); - - let index = addr.index()?; - let vk = derive_phoenix_vk(seed, index); - let pk = addr.pk()?; + let vk = self.derive_phoenix_vk(addr_idx); + let pk = self.phoenix_pk(addr_idx)?; let live_notes = self.state()?.fetch_notes(pk)?; let spent_notes = self.state()?.cache().spent_notes(pk)?; @@ -358,21 +324,14 @@ impl Wallet { /// Obtain balance information for a given address pub async fn get_phoenix_balance( &self, - addr: &Address, + addr_idx: u8, ) -> Result { let state = self.state()?; - // make sure we own this address - if !addr.is_owned() { - return Err(Error::Unauthorized); - } - - let index = addr.index()?; - let notes = state.fetch_notes(addr.pk()?)?; - let seed = self.store.get_seed(); + let notes = state.fetch_notes(self.phoenix_pk(addr_idx)?)?; Ok(phoenix_balance( - &derive_phoenix_vk(seed, index), + &self.derive_phoenix_vk(addr_idx), notes.iter(), )) } @@ -380,80 +339,122 @@ impl Wallet { /// Get Moonlight account balance pub async fn get_moonlight_balance( &self, - addr: &Address, + addr_idx: u8, ) -> Result { - let pk = addr.apk()?; + let pk = self.bls_pk(addr_idx)?; let state = self.state()?; let account = state.fetch_account(pk).await?; Ok(Dusk::from(account.balance)) } - /// Creates a new public address. - /// The addresses generated are deterministic across sessions. - pub fn new_address(&mut self) -> &Address { + /// Pushes a new entry to the internal address vector and returns its index. + fn push_new_address(&mut self) -> u8 { let seed = self.store.get_seed(); - let len = self.addresses.len(); - let pk = derive_phoenix_pk(seed, len as u8); - let addr = Address::Phoenix { - index: Some(len as u8), - addr: pk, - }; + let index = self.addresses.len() as u8; + let addr = + (derive_phoenix_pk(&seed, index), derive_bls_pk(&seed, index)); self.addresses.push(addr); - self.addresses.last().unwrap() + + index } - /// Default public address for this wallet - pub fn default_address(&self) -> &Address { - &self.addresses[0] + /// Creates a new public phoenix address. + /// The addresses generated are deterministic across sessions. + pub fn new_phoenix_address(&mut self) -> Address { + let index = self.push_new_address(); + + Address::Phoenix { + index: Some(index), + addr: *self + .phoenix_pk(index) + .expect("There to be a key at the index"), + } + } + + /// Creates a new public bls address. + /// The addresses generated are deterministic across sessions. + pub fn new_bls_address(&mut self) -> Address { + let index = self.push_new_address(); + + Address::Bls { + index: Some(index), + addr: *self.bls_pk(index).expect("There to be a key at the index"), + } + } + + /// Default phoenix public key for this wallet + pub fn default_phoenix_pk(&self) -> &PhoenixPublicKey { + &self.addresses[0].0 + } + + /// Default bls public key for this wallet + pub fn default_bls_pk(&self) -> &BlsPublicKey { + &self.addresses[0].1 } /// Addresses that have been generated by the user - pub fn addresses(&self) -> &Vec
{ + pub fn addresses(&self) -> &Vec<(PhoenixPublicKey, BlsPublicKey)> { &self.addresses } /// Returns the Phoenix secret-key for a given index - pub(crate) fn phoenix_secret_key(&self, index: u8) -> PhoenixSecretKey { + pub(crate) fn derive_phoenix_sk(&self, index: u8) -> PhoenixSecretKey { let seed = self.store.get_seed(); derive_phoenix_sk(seed, index) } - /// Returns the Phoenix public-key for a given index - pub fn phoenix_public_key(&self, index: u8) -> PhoenixPublicKey { + /// Returns the Phoenix secret-key for a given index + pub(crate) fn derive_phoenix_vk(&self, index: u8) -> PhoenixViewKey { let seed = self.store.get_seed(); - derive_phoenix_pk(seed, index) + derive_phoenix_vk(seed, index) + } + + /// Returns the Phoenix public-key for a given index. + /// + /// # Errors + /// This will error if the wallet doesn't have addresses stored for the + /// given index. + pub fn phoenix_pk(&self, index: u8) -> Result<&PhoenixPublicKey, Error> { + let index = usize::from(index); + if index >= self.addresses.len() { + return Err(Error::AddressNotOwned); + } + + Ok(&self.addresses()[index].0) } /// Returns the BLS secret-key for a given index - pub(crate) fn bls_secret_key(&self, index: u8) -> BlsSecretKey { + pub(crate) fn derive_bls_sk(&self, index: u8) -> BlsSecretKey { let seed = self.store.get_seed(); derive_bls_sk(seed, index) } /// Returns the BLS public-key for a given index - pub fn bls_public_key(&self, index: u8) -> BlsPublicKey { - let seed = self.store.get_seed(); - derive_bls_pk(seed, index) + /// + /// # Errors + /// This will error if the wallet doesn't have addresses stored for the + /// given index. + pub fn bls_pk(&self, index: u8) -> Result<&BlsPublicKey, Error> { + let index = usize::from(index); + if index >= self.addresses.len() { + return Err(Error::AddressNotOwned); + } + + Ok(&self.addresses()[index].1) } - /// Creates a generic Moonlight transaction. + /// Creates a generic moonlight execution, paying gas with Moonlight tokens. #[allow(clippy::too_many_arguments)] pub async fn moonlight_execute( &self, - sender_addr: &Address, - receiver: Option, + sender_idx: u8, transfer_value: Dusk, deposit: Dusk, gas: Gas, exec: Option>, ) -> Result { - // make sure we own the sender address - if !sender_addr.is_owned() { - return Err(Error::Unauthorized); - } - // check gas limits if !gas.is_enough() { return Err(Error::NotEnoughGas); @@ -462,9 +463,8 @@ impl Wallet { let state = self.state()?; let deposit = *deposit; - let sender_index = sender_addr.index()?; - let mut sender_sk = self.bls_secret_key(sender_index); - let sender = self.bls_public_key(sender_index); + let mut sender_sk = self.derive_bls_sk(sender_idx); + let sender = self.bls_pk(sender_idx)?; let account = state.fetch_account(&sender).await?; @@ -476,7 +476,7 @@ impl Wallet { let tx = moonlight( &sender_sk, - receiver, + None, *transfer_value, deposit, gas.limit, @@ -494,16 +494,11 @@ impl Wallet { /// Executes a generic contract call, paying gas with phoenix notes pub async fn phoenix_execute( &self, - sender: &Address, + sender_idx: u8, deposit: Dusk, gas: Gas, data: TransactionData, ) -> Result { - // make sure we own the sender address - if !sender.is_owned() { - return Err(Error::Unauthorized); - } - // check gas limits if !gas.is_enough() { return Err(Error::NotEnoughGas); @@ -513,13 +508,13 @@ impl Wallet { let deposit = *deposit; let mut rng = StdRng::from_entropy(); - let sender_index = sender.index()?; - let mut sender_sk = self.phoenix_secret_key(sender_index); - // in a contract execution, the sender and receiver are the same - let receiver_pk = sender.pk()?; + let mut sender_sk = self.derive_phoenix_sk(sender_idx); + // in a contract execution or deployment, the sender and receiver are + // the same + let receiver_pk = self.phoenix_pk(sender_idx)?; let inputs = state - .inputs(sender_index, deposit + gas.limit * gas.price) + .inputs(sender_idx, deposit + gas.limit * gas.price) .await? .into_iter() .map(|(a, b, _)| (a, b)) @@ -531,7 +526,7 @@ impl Wallet { let tx = phoenix( &mut rng, &sender_sk, - sender.pk()?, + self.phoenix_pk(sender_idx)?, receiver_pk, inputs, root, @@ -553,16 +548,12 @@ impl Wallet { /// Transfers funds between Phoenix addresses pub async fn phoenix_transfer( &self, - sender: &Address, - rcvr: &Address, + sender_idx: u8, + receiver_pk: &PhoenixPublicKey, memo: Option, amt: Dusk, gas: Gas, ) -> Result { - // make sure we own the sender address - if !sender.is_owned() { - return Err(Error::Unauthorized); - } // make sure amount is positive if amt == 0 && memo.is_none() { return Err(Error::AmountIsZero); @@ -575,15 +566,13 @@ impl Wallet { let state = self.state()?; let mut rng = StdRng::from_entropy(); - let sender_index = sender.index()?; let amt = *amt; - let mut sender_sk = self.phoenix_secret_key(sender_index); - let change_pk = sender.pk()?; - let reciever_pk = rcvr.pk()?; + let mut sender_sk = self.derive_phoenix_sk(sender_idx); + let change_pk = self.phoenix_pk(sender_idx)?; let inputs = state - .inputs(sender_index, amt + gas.limit * gas.price) + .inputs(sender_idx, amt + gas.limit * gas.price) .await? .into_iter() .map(|(a, b, _)| (a, b)) @@ -596,7 +585,7 @@ impl Wallet { &mut rng, &sender_sk, change_pk, - reciever_pk, + receiver_pk, inputs, root, amt, @@ -617,16 +606,12 @@ impl Wallet { /// Transfer through Moonlight pub async fn moonlight_transfer( &self, - sender: &Address, - rcvr: &Address, + sender_idx: u8, + rcvr: &BlsPublicKey, memo: Option, amt: Dusk, gas: Gas, ) -> Result { - // make sure we own the sender address - if !sender.is_owned() { - return Err(Error::Unauthorized); - } // make sure amount is positive if amt == 0 && memo.is_none() { return Err(Error::AmountIsZero); @@ -636,11 +621,8 @@ impl Wallet { return Err(Error::NotEnoughGas); } - let sender = sender.index()?; - - let mut sender_sk = self.bls_secret_key(sender); - let apk = rcvr.apk()?; - let sender_pk = self.bls_public_key(sender); + let mut sender_sk = self.derive_bls_sk(sender_idx); + let sender_pk = self.bls_pk(sender_idx)?; let amt = *amt; let state = self.state()?; @@ -649,7 +631,7 @@ impl Wallet { let tx = moonlight( &sender_sk, - Some(*apk), + Some(*rcvr), amt, 0, gas.limit, @@ -667,14 +649,10 @@ impl Wallet { /// Stakes Dusk using Phoenix notes pub async fn phoenix_stake( &self, - addr: &Address, + addr_idx: u8, amt: Dusk, gas: Gas, ) -> Result { - // make sure we own the staking address - if !addr.is_owned() { - return Err(Error::Unauthorized); - } // make sure amount is positive if amt == 0 { return Err(Error::AmountIsZero); @@ -688,19 +666,18 @@ impl Wallet { let mut rng = StdRng::from_entropy(); let amt = *amt; - let sender_index = addr.index()?; - let mut sender_sk = self.phoenix_secret_key(sender_index); - let mut stake_sk = self.bls_secret_key(sender_index); + let mut sender_sk = self.derive_phoenix_sk(addr_idx); + let mut stake_sk = self.derive_bls_sk(addr_idx); let nonce = state - .fetch_stake(&AccountPublicKey::from(&stake_sk)) + .fetch_stake(&BlsPublicKey::from(&stake_sk)) .await? .map(|s| s.nonce) .unwrap_or(0) + 1; let inputs = state - .inputs(sender_index, amt + gas.limit * gas.price) + .inputs(addr_idx, amt + gas.limit * gas.price) .await? .into_iter() .map(|(a, b, _)| (a, b)) @@ -720,17 +697,13 @@ impl Wallet { state.prove_and_propagate(stake).await } - /// Stake via Moonlight + /// Stake via Moonlight, using the moonlight public key to stake. pub async fn moonlight_stake( &self, - addr: &Address, + addr_idx: u8, amt: Dusk, gas: Gas, ) -> Result { - // make sure we own the staking address - if !addr.is_owned() { - return Err(Error::Unauthorized); - } // make sure amount is positive if amt == 0 { return Err(Error::AmountIsZero); @@ -742,14 +715,18 @@ impl Wallet { let state = self.state()?; let amt = *amt; - let sender_index = addr.index()?; - let mut stake_sk = self.bls_secret_key(sender_index); - let pk = self.bls_public_key(sender_index); + let mut stake_sk = self.derive_bls_sk(addr_idx); + let stake_pk = self.bls_pk(addr_idx)?; let chain_id = state.fetch_chain_id().await?; - let moonlight_current_nonce = state.fetch_account(&pk).await?.nonce + 1; + let moonlight_current_nonce = + state.fetch_account(&stake_pk).await?.nonce + 1; - let nonce = - state.fetch_stake(&pk).await?.map(|s| s.nonce).unwrap_or(0) + 1; + let nonce = state + .fetch_stake(&stake_pk) + .await? + .map(|s| s.nonce) + .unwrap_or(0) + + 1; let stake = moonlight_stake( &stake_sk, @@ -772,32 +749,24 @@ impl Wallet { &self, addr_idx: u8, ) -> Result, Error> { - self.state()? - .fetch_stake(&self.bls_public_key(addr_idx)) - .await + self.state()?.fetch_stake(self.bls_pk(addr_idx)?).await } /// Unstakes Dusk into Phoenix notes pub async fn phoenix_unstake( &self, - addr: &Address, + addr_idx: u8, gas: Gas, ) -> Result { - // make sure we own the staking address - if !addr.is_owned() { - return Err(Error::Unauthorized); - } - let mut rng = StdRng::from_entropy(); - let index = addr.index()?; let state = self.state()?; - let mut sender_sk = self.phoenix_secret_key(index); - let mut stake_sk = self.bls_secret_key(index); + let mut sender_sk = self.derive_phoenix_sk(addr_idx); + let mut stake_sk = self.derive_bls_sk(addr_idx); let unstake_value = state - .fetch_stake(&AccountPublicKey::from(&stake_sk)) + .fetch_stake(&BlsPublicKey::from(&stake_sk)) .await? .and_then(|s| s.amount) .map(|s| s.total_funds()) @@ -807,7 +776,7 @@ impl Wallet { return Err(Error::NotStaked); } - let inputs = state.inputs(index, gas.limit * gas.price).await?; + let inputs = state.inputs(addr_idx, gas.limit * gas.price).await?; let root = state.fetch_root().await?; let chain_id = state.fetch_chain_id().await?; @@ -831,23 +800,18 @@ impl Wallet { state.prove_and_propagate(unstake).await } - /// Unstakes Dusk through Moonlight + /// Unstakes Dusk through Moonlight, using the same key for the + /// Moonlight-account and Staking-account. pub async fn moonlight_unstake( &self, - addr: &Address, + addr_idx: u8, gas: Gas, ) -> Result { - // make sure we own the staking address - if !addr.is_owned() { - return Err(Error::Unauthorized); - } - let mut rng = StdRng::from_entropy(); - let index = addr.index()?; let state = self.state()?; - let mut stake_sk = self.bls_secret_key(index); + let mut stake_sk = self.derive_bls_sk(addr_idx); - let pk = addr.apk()?; + let pk = self.bls_pk(addr_idx)?; let chain_id = state.fetch_chain_id().await?; let account_nonce = state.fetch_account(pk).await?.nonce + 1; @@ -882,28 +846,22 @@ impl Wallet { /// Withdraw accumulated staking reward for a given address to Phoenix pub async fn phoenix_stake_withdraw( &self, - sender_addr: &Address, + sender_idx: u8, gas: Gas, ) -> Result { let state = self.state()?; - // make sure we own the staking address - if !sender_addr.is_owned() { - return Err(Error::Unauthorized); - } - let mut rng = StdRng::from_entropy(); - let sender_index = sender_addr.index()?; - let mut sender_sk = self.phoenix_secret_key(sender_index); - let mut stake_sk = self.bls_secret_key(sender_index); + let mut sender_sk = self.derive_phoenix_sk(sender_idx); + let mut stake_sk = self.derive_bls_sk(sender_idx); - let inputs = state.inputs(sender_index, gas.limit * gas.price).await?; + let inputs = state.inputs(sender_idx, gas.limit * gas.price).await?; let root = state.fetch_root().await?; let chain_id = state.fetch_chain_id().await?; let reward_amount = state - .fetch_stake(&AccountPublicKey::from(&stake_sk)) + .fetch_stake(&BlsPublicKey::from(&stake_sk)) .await? .map(|s| s.reward) .unwrap_or(0); @@ -930,31 +888,37 @@ impl Wallet { /// Convert balance from Phoenix to Moonlight pub async fn phoenix_to_moonlight( &self, - sender_addr: &Address, + addr_idx: u8, amt: Dusk, gas: Gas, ) -> Result { let mut rng = StdRng::from_entropy(); let state = self.state()?; - let sender_index = sender_addr.index()?; let amt = *amt; - let inputs = state - .inputs(sender_index, amt + gas.limit * gas.price) - .await?; + let inputs = + state.inputs(addr_idx, amt + gas.limit * gas.price).await?; let root = state.fetch_root().await?; let chain_id = state.fetch_chain_id().await?; - let mut sender_sk = self.phoenix_secret_key(sender_index); - let mut stake_sk = self.bls_secret_key(sender_index); + let mut phoenix_sk = self.derive_phoenix_sk(addr_idx); + let mut moonlight_sk = self.derive_bls_sk(addr_idx); let convert = phoenix_to_moonlight( - &mut rng, &sender_sk, &stake_sk, inputs, root, amt, gas.limit, - gas.price, chain_id, &Prover, + &mut rng, + &phoenix_sk, + &moonlight_sk, + inputs, + root, + amt, + gas.limit, + gas.price, + chain_id, + &Prover, )?; - sender_sk.zeroize(); - stake_sk.zeroize(); + phoenix_sk.zeroize(); + moonlight_sk.zeroize(); state.prove_and_propagate(convert).await } @@ -962,29 +926,34 @@ impl Wallet { /// Convert balance from Moonlight to Phoenix pub async fn moonlight_to_phoenix( &self, - sender_addr: &Address, + addr_idx: u8, amt: Dusk, gas: Gas, ) -> Result { let mut rng = StdRng::from_entropy(); let state = self.state()?; - let sender_index = sender_addr.index()?; - let pk = self.bls_public_key(sender_index); + let moonlight_pk = self.bls_pk(addr_idx)?; - let nonce = state.fetch_account(&pk).await?.nonce + 1; + let nonce = state.fetch_account(&moonlight_pk).await?.nonce + 1; let chain_id = state.fetch_chain_id().await?; - let mut sender_sk = self.phoenix_secret_key(sender_index); - let mut stake_sk = self.bls_secret_key(sender_index); + let mut phoenix_sk = self.derive_phoenix_sk(addr_idx); + let mut moonlight_sk = self.derive_bls_sk(addr_idx); let convert = moonlight_to_phoenix( - &mut rng, &stake_sk, &sender_sk, *amt, gas.limit, gas.price, nonce, + &mut rng, + &moonlight_sk, + &phoenix_sk, + *amt, + gas.limit, + gas.price, + nonce, chain_id, )?; - sender_sk.zeroize(); - stake_sk.zeroize(); + phoenix_sk.zeroize(); + moonlight_sk.zeroize(); state.prove_and_propagate(convert).await } @@ -992,20 +961,20 @@ impl Wallet { /// Withdraw accumulated staking reward for a given address to Moonlight pub async fn moonlight_stake_withdraw( &self, - sender: &Address, + sender_idx: u8, gas: Gas, ) -> Result { let mut rng = StdRng::from_entropy(); let state = self.state()?; - let sender_index = sender.index()?; - let pk = self.bls_public_key(sender_index); + + let pk = self.bls_pk(sender_idx)?; let nonce = state.fetch_account(&pk).await?.nonce + 1; let chain_id = state.fetch_chain_id().await?; let stake_info = state.fetch_stake(&pk).await?; let reward = stake_info.map(|s| s.reward).ok_or(Error::NoReward)?; let reward = Dusk::from(reward); - let mut sender_sk = self.bls_secret_key(sender_index); + let mut sender_sk = self.derive_bls_sk(sender_idx); let withdraw = moonlight_stake_reward( &mut rng, &sender_sk, &sender_sk, *reward, gas.limit, gas.price, @@ -1020,18 +989,18 @@ impl Wallet { /// Deploy a contract using Moonlight pub async fn moonlight_deploy( &self, - sender: &Address, + sender_idx: u8, bytes_code: Vec, init_args: Vec, gas: Gas, ) -> Result { let state = self.state()?; - let sender_index = sender.index()?; - let pk = sender.apk()?; + + let pk = self.bls_pk(sender_idx)?; let nonce = state.fetch_account(pk).await?.nonce + 1; let chain_id = state.fetch_chain_id().await?; - let mut sender_sk = self.bls_secret_key(sender_index); + let mut sender_sk = self.derive_bls_sk(sender_idx); let deploy = moonlight_deployment( &sender_sk, bytes_code, pk, init_args, gas.limit, gas.price, nonce, @@ -1046,26 +1015,25 @@ impl Wallet { /// Deploy a contract using Phoenix pub async fn phoenix_deploy( &self, - sender: &Address, + sender_idx: u8, bytes_code: Vec, init_args: Vec, gas: Gas, ) -> Result { let mut rng = StdRng::from_entropy(); let state = self.state()?; - let sender_index = sender.index()?; let chain_id = state.fetch_chain_id().await?; let root = state.fetch_root().await?; - let inputs = state.inputs(sender_index, gas.limit * gas.price).await?; + let inputs = state.inputs(sender_idx, gas.limit * gas.price).await?; - let mut sender_sk = self.phoenix_secret_key(sender_index); - let apk = self.bls_public_key(sender_index); + let mut sender_sk = self.derive_phoenix_sk(sender_idx); + let owner_pk = self.bls_pk(sender_idx)?; let deploy = phoenix_deployment( - &mut rng, &sender_sk, inputs, root, bytes_code, &apk, init_args, 0, - gas.limit, gas.price, chain_id, &Prover, + &mut rng, &sender_sk, inputs, root, bytes_code, &owner_pk, + init_args, 0, gas.limit, gas.price, chain_id, &Prover, )?; sender_sk.zeroize(); @@ -1076,24 +1044,23 @@ impl Wallet { /// Returns BLS key-pair for provisioner nodes pub fn provisioner_keys( &self, - addr: &Address, + index: u8, ) -> Result<(BlsPublicKey, BlsSecretKey), Error> { - // make sure we own the staking address - if !addr.is_owned() { + let pk = *self.bls_pk(index)?; + let sk = self.derive_bls_sk(index); + + // make sure our internal addresses are not corrupted + if pk != BlsPublicKey::from(&sk) { return Err(Error::Unauthorized); } - let index = addr.index()?; - let sk = self.bls_secret_key(index); - let pk = self.bls_public_key(index); - Ok((pk, sk)) } /// Export BLS key-pair for provisioners in node-compatible format pub fn export_provisioner_keys( &self, - addr: &Address, + addr_idx: u8, dir: &Path, filename: Option, pwd: &[u8], @@ -1104,11 +1071,11 @@ impl Wallet { } // get our keys for this address - let keys = self.provisioner_keys(addr)?; + let keys = self.provisioner_keys(addr_idx)?; // set up the path let mut path = PathBuf::from(dir); - path.push(filename.unwrap_or(addr.to_string())); + path.push(filename.unwrap_or(addr_idx.to_string())); // export public key to disk let bytes = keys.0.to_bytes(); @@ -1132,11 +1099,21 @@ impl Wallet { } /// Obtain the owned `Address` for a given address - pub fn claim_as_address(&self, addr: Address) -> Result<&Address, Error> { - self.addresses() - .iter() - .find(|&a| a == &addr) - .ok_or(Error::AddressNotOwned) + pub fn claim_as_address(&self, addr: Address) -> Result { + let addr_index = addr.index()?; + + let is_owned = match addr { + Address::Phoenix { + index: _, + addr: phoenix_pk, + } => phoenix_pk == *self.phoenix_pk(addr_index)?, + Address::Bls { + index: _, + addr: bls_pk, + } => bls_pk == *self.bls_pk(addr_index)?, + }; + + is_owned.then(|| addr_index).ok_or(Error::AddressNotOwned) } /// Return the dat file version from memory or by reading the file @@ -1226,24 +1203,33 @@ mod tests { } } + fn default_phoenix_address(wallet: &Wallet) -> Address { + Address::Phoenix { + index: Some(0), + addr: *wallet + .phoenix_pk(0) + .expect("There to be a key at the index"), + } + } + #[test] fn wallet_basics() -> Result<(), Box> { // create a wallet from a mnemonic phrase let mut wallet: Wallet = Wallet::new("uphold stove tennis fire menu three quick apple close guilt poem garlic volcano giggle comic")?; // check address generation - let default_addr = wallet.default_address().clone(); - let other_addr = wallet.new_address(); + let default_addr = default_phoenix_address(&wallet); + let other_addr = wallet.new_phoenix_address(); assert!(format!("{}", default_addr).eq(TEST_ADDR)); - assert_ne!(&default_addr, other_addr); + assert_ne!(default_addr, other_addr); assert_eq!(wallet.addresses.len(), 2); // create another wallet with different mnemonic let wallet: Wallet = Wallet::new("demise monitor elegant cradle squeeze cheap parrot venture stereo humor scout denial action receive flat")?; // check addresses are different - let addr = wallet.default_address(); + let addr = default_phoenix_address(&wallet); assert!(format!("{}", addr).ne(TEST_ADDR)); // attempt to create a wallet from an invalid mnemonic @@ -1272,9 +1258,9 @@ mod tests { // load from file and check let loaded_wallet = Wallet::from_file(file)?; - let original_addr = wallet.default_address(); - let loaded_addr = loaded_wallet.default_address(); - assert!(original_addr.eq(loaded_addr)); + let original_addr = default_phoenix_address(&wallet); + let loaded_addr = default_phoenix_address(&loaded_wallet); + assert!(original_addr.eq(&loaded_addr)); Ok(()) } diff --git a/rusk-wallet/src/wallet/address.rs b/rusk-wallet/src/wallet/address.rs index 755f95bea..e12b728c9 100644 --- a/rusk-wallet/src/wallet/address.rs +++ b/rusk-wallet/src/wallet/address.rs @@ -13,7 +13,7 @@ use crate::Error; use dusk_bytes::{DeserializableSlice, Error as BytesError, Serializable}; /// Address for which to perform transactions with -/// it may be owned by the user or not, if the address is a reciever +/// it may be owned by the user or not, if the address is a receiver /// then the index field will be none #[derive(Clone, Eq)] #[allow(missing_docs)] @@ -26,18 +26,17 @@ pub enum Address { /// A BLS address for Moonlight account Bls { index: Option, - addr: AccountPublicKey, + addr: BlsPublicKey, }, } /// A public address within Dusk impl Address { - /// Returns true if the current user owns this address - pub fn is_owned(&self) -> bool { - self.index().is_ok() - } - - pub(crate) fn pk(&self) -> Result<&PhoenixPublicKey, Error> { + /// Returns the phoenix-key of the Address if there is any. + /// + /// # Errors + /// If the address carries a bls-key. + pub fn try_phoenix_pk(&self) -> Result<&PhoenixPublicKey, Error> { if let Self::Phoenix { addr, .. } = self { Ok(addr) } else { @@ -45,7 +44,11 @@ impl Address { } } - pub(crate) fn apk(&self) -> Result<&AccountPublicKey, Error> { + /// Returns the bls-key of the Address if there is any. + /// + /// # Errors + /// If the address carries a phoenix-key. + pub fn try_bls_pk(&self) -> Result<&BlsPublicKey, Error> { if let Self::Bls { addr, .. } = self { Ok(addr) } else { @@ -95,12 +98,12 @@ impl Address { pub fn try_from_str_bls(s: &str) -> Result { let bytes = bs58::decode(s).into_vec()?; - let apk = AccountPublicKey::from_reader(&mut &bytes[..]) + let bls_bk = BlsPublicKey::from_reader(&mut &bytes[..]) .map_err(|_| Error::BadAddress)?; let addr = Self::Bls { index: None, - addr: apk, + addr: bls_bk, }; Ok(addr) @@ -120,11 +123,11 @@ impl Address { /// Create an address instance from `BlsPublicKey` bytes. pub fn try_from_bytes_bls( - bytes: &[u8; AccountPublicKey::SIZE], + bytes: &[u8; BlsPublicKey::SIZE], ) -> Result { let addr = Self::Bls { index: None, - addr: AccountPublicKey::from_bytes(bytes)?, + addr: BlsPublicKey::from_bytes(bytes)?, }; Ok(addr) From 36a1ccb936875d5fef64c5d402f5f77152071089 Mon Sep 17 00:00:00 2001 From: moana Date: Thu, 3 Oct 2024 20:08:47 +0200 Subject: [PATCH 2/2] rusk-wallet: WIP tests pass but wallet crashes --- rusk-wallet/src/bin/command.rs | 42 +++++++++++++++--------------- rusk-wallet/src/bin/interactive.rs | 3 ++- rusk-wallet/src/wallet.rs | 30 ++++++++++----------- 3 files changed, 38 insertions(+), 37 deletions(-) diff --git a/rusk-wallet/src/bin/command.rs b/rusk-wallet/src/bin/command.rs index fcffc3690..4a86610ab 100644 --- a/rusk-wallet/src/bin/command.rs +++ b/rusk-wallet/src/bin/command.rs @@ -475,7 +475,7 @@ impl Command { } let addr_idx = match addr { - Some(addr) => wallet.claim_as_address(addr)?, + Some(addr) => wallet.claim_as_address(&addr)?, None => 0, }; @@ -484,7 +484,7 @@ impl Command { } Command::MoonlightBalance { addr } => { let addr_idx = match addr { - Some(addr) => wallet.claim_as_address(addr)?, + Some(addr) => wallet.claim_as_address(&addr)?, None => 0, }; @@ -529,7 +529,7 @@ impl Command { } => { wallet.sync().await?; let sender_idx = match sndr { - Some(addr) => wallet.claim_as_address(addr)?, + Some(addr) => wallet.claim_as_address(&addr)?, None => 0, }; let gas = Gas::new(gas_limit).with_price(gas_price); @@ -551,7 +551,7 @@ impl Command { } => { wallet.sync().await?; let sender_idx = match sndr { - Some(addr) => wallet.claim_as_address(addr)?, + Some(addr) => wallet.claim_as_address(&addr)?, None => 0, }; let gas = Gas::new(gas_limit).with_price(gas_price); @@ -578,7 +578,7 @@ impl Command { } => { let gas = Gas::new(gas_limit).with_price(gas_price); let sender_idx = match sndr { - Some(addr) => wallet.claim_as_address(addr)?, + Some(addr) => wallet.claim_as_address(&addr)?, None => 0, }; @@ -600,7 +600,7 @@ impl Command { } => { let gas = Gas::new(gas_limit).with_price(gas_price); let sender_idx = match sndr { - Some(addr) => wallet.claim_as_address(addr)?, + Some(addr) => wallet.claim_as_address(&addr)?, None => 0, }; @@ -627,7 +627,7 @@ impl Command { wallet.sync().await?; let gas = Gas::new(gas_limit).with_price(gas_price); let addr_idx = match addr { - Some(addr) => wallet.claim_as_address(addr)?, + Some(addr) => wallet.claim_as_address(&addr)?, None => 0, }; @@ -636,7 +636,7 @@ impl Command { } Command::StakeInfo { addr, reward } => { let addr_idx = match addr { - Some(addr) => wallet.claim_as_address(addr)?, + Some(addr) => wallet.claim_as_address(&addr)?, None => 0, }; let si = wallet @@ -653,7 +653,7 @@ impl Command { } => { wallet.sync().await?; let addr_idx = match addr { - Some(addr) => wallet.claim_as_address(addr)?, + Some(addr) => wallet.claim_as_address(&addr)?, None => 0, }; @@ -669,7 +669,7 @@ impl Command { } => { wallet.sync().await?; let addr_idx = match addr { - Some(addr) => wallet.claim_as_address(addr)?, + Some(addr) => wallet.claim_as_address(&addr)?, None => 0, }; @@ -680,7 +680,7 @@ impl Command { } Command::Export { addr, dir, name } => { let addr_idx = match addr { - Some(addr) => wallet.claim_as_address(addr)?, + Some(addr) => wallet.claim_as_address(&addr)?, None => 0, }; @@ -698,7 +698,7 @@ impl Command { Command::PhoenixHistory { addr } => { wallet.sync().await?; let addr_idx = match addr { - Some(addr) => wallet.claim_as_address(addr)?, + Some(addr) => wallet.claim_as_address(&addr)?, None => 0, }; let notes = wallet.get_all_notes(addr_idx).await?; @@ -716,7 +716,7 @@ impl Command { } => { wallet.sync().await?; let addr_idx = match addr { - Some(addr) => wallet.claim_as_address(addr)?, + Some(addr) => wallet.claim_as_address(&addr)?, None => 0, }; @@ -734,7 +734,7 @@ impl Command { } => { wallet.sync().await?; let addr_idx = match addr { - Some(addr) => wallet.claim_as_address(addr)?, + Some(addr) => wallet.claim_as_address(&addr)?, None => 0, }; @@ -751,7 +751,7 @@ impl Command { gas_price, } => { let addr_idx = match addr { - Some(addr) => wallet.claim_as_address(addr)?, + Some(addr) => wallet.claim_as_address(&addr)?, None => 0, }; @@ -766,7 +766,7 @@ impl Command { gas_price, } => { let addr_idx = match addr { - Some(addr) => wallet.claim_as_address(addr)?, + Some(addr) => wallet.claim_as_address(&addr)?, None => 0, }; @@ -781,7 +781,7 @@ impl Command { gas_price, } => { let addr_idx = match addr { - Some(addr) => wallet.claim_as_address(addr)?, + Some(addr) => wallet.claim_as_address(&addr)?, None => 0, }; @@ -800,7 +800,7 @@ impl Command { gas_price, } => { let addr_idx = match addr { - Some(addr) => wallet.claim_as_address(addr)?, + Some(addr) => wallet.claim_as_address(&addr)?, None => 0, }; @@ -828,7 +828,7 @@ impl Command { gas_price, } => { let addr_idx = match addr { - Some(addr) => wallet.claim_as_address(addr)?, + Some(addr) => wallet.claim_as_address(&addr)?, None => 0, }; @@ -861,7 +861,7 @@ impl Command { gas_price, } => { let addr_idx = match addr { - Some(addr) => wallet.claim_as_address(addr)?, + Some(addr) => wallet.claim_as_address(&addr)?, None => 0, }; @@ -888,7 +888,7 @@ impl Command { gas_price, } => { let addr_idx = match addr { - Some(addr) => wallet.claim_as_address(addr)?, + Some(addr) => wallet.claim_as_address(&addr)?, None => 0, }; diff --git a/rusk-wallet/src/bin/interactive.rs b/rusk-wallet/src/bin/interactive.rs index 8de6fd590..43ba18c2a 100644 --- a/rusk-wallet/src/bin/interactive.rs +++ b/rusk-wallet/src/bin/interactive.rs @@ -66,7 +66,8 @@ pub(crate) async fn run_loop( AddrSelect::Exit => std::process::exit(0), }; - let addr_idx = addr.index()?; + // let addr_idx = addr.index()?; + let addr_idx = wallet.claim_as_address(&addr)?; let phoenix_addr = Address::Phoenix { index: Some(addr_idx), addr: *wallet.phoenix_pk(addr_idx)?, diff --git a/rusk-wallet/src/wallet.rs b/rusk-wallet/src/wallet.rs index a60f4489c..4284aa27e 100644 --- a/rusk-wallet/src/wallet.rs +++ b/rusk-wallet/src/wallet.rs @@ -1051,7 +1051,7 @@ impl Wallet { // make sure our internal addresses are not corrupted if pk != BlsPublicKey::from(&sk) { - return Err(Error::Unauthorized); + return Err(Error::AddressNotOwned); } Ok((pk, sk)) @@ -1099,21 +1099,21 @@ impl Wallet { } /// Obtain the owned `Address` for a given address - pub fn claim_as_address(&self, addr: Address) -> Result { - let addr_index = addr.index()?; - - let is_owned = match addr { - Address::Phoenix { - index: _, - addr: phoenix_pk, - } => phoenix_pk == *self.phoenix_pk(addr_index)?, - Address::Bls { - index: _, - addr: bls_pk, - } => bls_pk == *self.bls_pk(addr_index)?, - }; + pub fn claim_as_address(&self, addr: &Address) -> Result { + // check if the key is stored in our addresses, return its index if + // found + for (index, (phoenix_pk, bls_pk)) in self.addresses().iter().enumerate() + { + if match addr { + Address::Phoenix { index: _, addr } => addr == phoenix_pk, + Address::Bls { index: _, addr } => addr == bls_pk, + } { + return Ok(index as u8); + } + } - is_owned.then(|| addr_index).ok_or(Error::AddressNotOwned) + // return an error otherwise + return Err(Error::AddressNotOwned); } /// Return the dat file version from memory or by reading the file