diff --git a/applications/minotari_console_wallet/src/grpc/wallet_grpc_server.rs b/applications/minotari_console_wallet/src/grpc/wallet_grpc_server.rs index 6870f5c62e..428fa94c27 100644 --- a/applications/minotari_console_wallet/src/grpc/wallet_grpc_server.rs +++ b/applications/minotari_console_wallet/src/grpc/wallet_grpc_server.rs @@ -230,7 +230,7 @@ impl wallet_server::Wallet for WalletGrpcServer { async fn get_address(&self, _: Request) -> Result, Status> { let address = self .wallet - .get_wallet_address() + .get_wallet_interactive_address() .await .map_err(|e| Status::internal(format!("{:?}", e)))?; Ok(Response::new(GetAddressResponse { @@ -662,7 +662,7 @@ impl wallet_server::Wallet for WalletGrpcServer { .map_err(|err| Status::unknown(err.to_string()))?; let wallet_address = self .wallet - .get_wallet_address() + .get_wallet_interactive_address() .await .map_err(|e| Status::internal(format!("{:?}", e)))?; let transactions = transactions diff --git a/applications/minotari_console_wallet/src/ui/app.rs b/applications/minotari_console_wallet/src/ui/app.rs index 634d1c19a0..98d5550c42 100644 --- a/applications/minotari_console_wallet/src/ui/app.rs +++ b/applications/minotari_console_wallet/src/ui/app.rs @@ -20,7 +20,7 @@ // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE // USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -use minotari_wallet::{util::wallet_identity::WalletIdentity, WalletConfig, WalletSqlite}; +use minotari_wallet::{error::WalletError, util::wallet_identity::WalletIdentity, WalletConfig, WalletSqlite}; use tari_common::exit_codes::ExitError; use tari_comms::peer_manager::Peer; use tokio::runtime::Handle; @@ -79,8 +79,19 @@ impl App { base_node_config: PeerConfig, notifier: Notifier, ) -> Result { - let wallet_address = wallet.get_wallet_address().await?; - let wallet_id = WalletIdentity::new(wallet.comms.node_identity(), wallet_address); + let wallet_address_interactive = wallet + .get_wallet_interactive_address() + .await + .map_err(WalletError::KeyManagerServiceError)?; + let wallet_address_one_sided = wallet + .get_wallet_one_sided_address() + .await + .map_err(WalletError::KeyManagerServiceError)?; + let wallet_id = WalletIdentity::new( + wallet.comms.node_identity(), + wallet_address_interactive, + wallet_address_one_sided, + ); let app_state = AppState::new( &wallet_id, wallet, diff --git a/applications/minotari_console_wallet/src/ui/components/receive_tab.rs b/applications/minotari_console_wallet/src/ui/components/receive_tab.rs index 388b98f516..10617063d7 100644 --- a/applications/minotari_console_wallet/src/ui/components/receive_tab.rs +++ b/applications/minotari_console_wallet/src/ui/components/receive_tab.rs @@ -29,7 +29,7 @@ impl ReceiveTab { let chunks = Layout::default() .direction(Direction::Vertical) - .constraints([Constraint::Length(6), Constraint::Length(23)].as_ref()) + .constraints([Constraint::Length(8), Constraint::Length(23)].as_ref()) .margin(1) .split(area); @@ -46,6 +46,8 @@ impl ReceiveTab { Constraint::Length(1), Constraint::Length(1), Constraint::Length(1), + Constraint::Length(1), + Constraint::Length(1), ] .as_ref(), ) @@ -57,54 +59,76 @@ impl ReceiveTab { .title(Span::styled("Connection Details", Style::default().fg(Color::White))); f.render_widget(block, chunks[0]); - const ITEM_01: &str = "Tari Address: "; - const ITEM_02: &str = "Node ID: "; - const ITEM_03: &str = "Network Address: "; - const ITEM_04: &str = "Emoji ID: "; + const ITEM_01: &str = "Tari Address interactive: "; + const ITEM_02: &str = "Tari Address one-sided: "; + const ITEM_03: &str = "Node ID: "; + const ITEM_04: &str = "Network Address: "; + const ITEM_05: &str = "Interactive emoji address: "; + const ITEM_06: &str = "One-sided emoji address: "; // Tari address - let tari_address_text = Spans::from(vec![ + let tari_address_interactive_text = Spans::from(vec![ Span::styled(ITEM_01, Style::default().fg(Color::Magenta)), Span::styled( - app_state.get_identity().tari_address.clone(), + app_state.get_identity().tari_address_interactive.to_base58(), Style::default().fg(Color::White), ), ]); - let paragraph = Paragraph::new(tari_address_text).block(Block::default()); + let paragraph = Paragraph::new(tari_address_interactive_text).block(Block::default()); f.render_widget(paragraph, details_chunks[0]); + let tari_address_one_sided_text = Spans::from(vec![ + Span::styled(ITEM_02, Style::default().fg(Color::Magenta)), + Span::styled( + app_state.get_identity().tari_address_one_sided.to_base58(), + Style::default().fg(Color::White), + ), + ]); + let paragraph = Paragraph::new(tari_address_one_sided_text).block(Block::default()); + f.render_widget(paragraph, details_chunks[1]); + // NodeId let node_id_text = Spans::from(vec![ - Span::styled(ITEM_02, Style::default().fg(Color::Magenta)), + Span::styled(ITEM_03, Style::default().fg(Color::Magenta)), Span::styled( app_state.get_identity().node_id.clone(), Style::default().fg(Color::White), ), ]); let paragraph = Paragraph::new(node_id_text).block(Block::default()); - f.render_widget(paragraph, details_chunks[1]); + f.render_widget(paragraph, details_chunks[2]); // Public Address let public_address_text = Spans::from(vec![ - Span::styled(ITEM_03, Style::default().fg(Color::Magenta)), + Span::styled(ITEM_04, Style::default().fg(Color::Magenta)), Span::styled( app_state.get_identity().network_address.clone(), Style::default().fg(Color::White), ), ]); let paragraph = Paragraph::new(public_address_text).block(Block::default()); - f.render_widget(paragraph, details_chunks[2]); + f.render_widget(paragraph, details_chunks[3]); // Emoji ID let emoji_id_text = Spans::from(vec![ - Span::styled(ITEM_04, Style::default().fg(Color::Magenta)), + Span::styled(ITEM_05, Style::default().fg(Color::Magenta)), Span::styled( - app_state.get_identity().emoji_id.clone(), + app_state.get_identity().tari_address_interactive.to_emoji_string(), Style::default().fg(Color::White), ), ]); let paragraph = Paragraph::new(emoji_id_text).block(Block::default()); - f.render_widget(paragraph, details_chunks[3]); + f.render_widget(paragraph, details_chunks[4]); + + let emoji_id_text = Spans::from(vec![ + Span::styled(ITEM_06, Style::default().fg(Color::Magenta)), + Span::styled( + app_state.get_identity().tari_address_one_sided.to_emoji_string(), + Style::default().fg(Color::White), + ), + ]); + let paragraph = Paragraph::new(emoji_id_text).block(Block::default()); + f.render_widget(paragraph, details_chunks[5]); } } diff --git a/applications/minotari_console_wallet/src/ui/state/app_state.rs b/applications/minotari_console_wallet/src/ui/state/app_state.rs index 2a51b76e8d..13cb4d1298 100644 --- a/applications/minotari_console_wallet/src/ui/state/app_state.rs +++ b/applications/minotari_console_wallet/src/ui/state/app_state.rs @@ -897,11 +897,10 @@ impl AppStateInner { pub async fn refresh_network_id(&mut self) -> Result<(), UiError> { let wallet_id = self.wallet.get_wallet_id().await?; - let eid = wallet_id.address.to_emoji_string(); let qr_link = format!( "tari://{}/transactions/send?tariAddress={}", wallet_id.network(), - wallet_id.address.to_base58() + wallet_id.address_interactive.to_base58() ); let code = QrCode::new(qr_link).unwrap(); let image = code @@ -913,7 +912,8 @@ impl AppStateInner { .skip(1) .fold("".to_string(), |acc, l| format!("{}{}\n", acc, l)); let identity = MyIdentity { - tari_address: wallet_id.address.to_base58(), + tari_address_interactive: wallet_id.address_interactive.clone(), + tari_address_one_sided: wallet_id.address_one_sided.clone(), network_address: wallet_id .node_identity .public_addresses() @@ -921,7 +921,6 @@ impl AppStateInner { .map(|a| a.to_string()) .collect::>() .join(", "), - emoji_id: eid, qr_code: image, node_id: wallet_id.node_identity.node_id().to_string(), }; @@ -1234,11 +1233,10 @@ pub struct EventListItem { impl AppStateData { pub fn new(wallet_identity: &WalletIdentity, base_node_selected: Peer, base_node_config: PeerConfig) -> Self { - let eid = wallet_identity.address.to_emoji_string(); let qr_link = format!( "tari://{}/transactions/send?tariAddress={}", wallet_identity.network(), - wallet_identity.address.to_base58() + wallet_identity.address_interactive.to_base58() ); let code = QrCode::new(qr_link).unwrap(); let image = code @@ -1251,7 +1249,8 @@ impl AppStateData { .fold("".to_string(), |acc, l| format!("{}{}\n", acc, l)); let identity = MyIdentity { - tari_address: wallet_identity.address.to_base58(), + tari_address_interactive: wallet_identity.address_interactive.clone(), + tari_address_one_sided: wallet_identity.address_one_sided.clone(), network_address: wallet_identity .node_identity .public_addresses() @@ -1259,7 +1258,6 @@ impl AppStateData { .map(|a| a.to_string()) .collect::>() .join(", "), - emoji_id: eid, qr_code: image, node_id: wallet_identity.node_identity.node_id().to_string(), }; @@ -1309,9 +1307,9 @@ impl AppStateData { #[derive(Clone)] pub struct MyIdentity { - pub tari_address: String, + pub tari_address_interactive: TariAddress, + pub tari_address_one_sided: TariAddress, pub network_address: String, - pub emoji_id: String, pub qr_code: String, pub node_id: String, } diff --git a/base_layer/common_types/src/lib.rs b/base_layer/common_types/src/lib.rs index f1cccdc01b..d77413e2af 100644 --- a/base_layer/common_types/src/lib.rs +++ b/base_layer/common_types/src/lib.rs @@ -20,6 +20,9 @@ // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE // USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// This is the string used to derive the comms/spend key of the wallet +pub const WALLET_COMMS_AND_SPEND_KEY_BRANCH: &str = "comms"; + pub mod burnt_proof; pub mod chain_metadata; pub mod dammsum; diff --git a/base_layer/common_types/src/wallet_types.rs b/base_layer/common_types/src/wallet_types.rs index c79c38ddbc..af69f9eb9f 100644 --- a/base_layer/common_types/src/wallet_types.rs +++ b/base_layer/common_types/src/wallet_types.rs @@ -32,6 +32,7 @@ use ledger_transport::APDUCommand; use minotari_ledger_wallet_comms::ledger_wallet::{Command, Instruction}; use serde::{Deserialize, Serialize}; use tari_common::configuration::Network; +use tari_crypto::keys::PublicKey as PublicKeyTrait; use crate::types::{PrivateKey, PublicKey}; @@ -40,6 +41,7 @@ pub enum WalletType { #[default] Software, Ledger(LedgerWallet), + Imported(ImportedWallet), } impl Display for WalletType { @@ -47,10 +49,26 @@ impl Display for WalletType { match self { WalletType::Software => write!(f, "Software"), WalletType::Ledger(ledger_wallet) => write!(f, "Ledger({ledger_wallet})"), + WalletType::Imported(imported_wallet) => write!(f, "Imported({imported_wallet})"), } } } +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct ImportedWallet { + pub public_spend_key: PublicKey, + pub private_spend_key: Option, + pub view_key: PrivateKey, +} + +impl Display for ImportedWallet { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + write!(f, "public spend key {}", self.public_spend_key)?; + write!(f, "public view key{}", PublicKey::from_secret_key(&self.view_key))?; + Ok(()) + } +} + #[derive(Debug, Clone, Serialize, Deserialize)] pub struct LedgerWallet { account: u64, diff --git a/base_layer/core/src/transactions/key_manager/inner.rs b/base_layer/core/src/transactions/key_manager/inner.rs index a8d48a37ea..bbfc55efb3 100644 --- a/base_layer/core/src/transactions/key_manager/inner.rs +++ b/base_layer/core/src/transactions/key_manager/inner.rs @@ -62,7 +62,7 @@ use tari_key_manager::{ }, }; use tari_script::CheckSigSchnorrSignature; -use tari_utilities::{hex::Hex, ByteArray}; +use tari_utilities::ByteArray; use tokio::sync::RwLock; const LOG_TARGET: &str = "c::bn::key_manager::key_manager_service"; @@ -187,12 +187,6 @@ where TBackend: KeyManagerBackend + 'static Ok((key_id, public_key)) } - pub async fn create_key_pair(&mut self, branch: &str) -> Result<(TariKeyId, PublicKey), KeyManagerServiceError> { - self.add_key_manager_branch(branch)?; - let (key_id, public_key) = self.get_next_key(branch).await?; - Ok((key_id, public_key)) - } - pub async fn get_static_key(&self, branch: &str) -> Result { match self.key_managers.get(branch) { None => Err(KeyManagerServiceError::UnknownKeyBranch), @@ -260,23 +254,7 @@ where TBackend: KeyManagerBackend + 'static Ok(km.derive_public_key(*index)?.key) }, KeyId::Derived { branch, label, index } => { - let public_alpha = match &self.wallet_type { - WalletType::Software => { - let km = self - .key_managers - .get(&TransactionKeyManagerBranch::Alpha.get_branch_key()) - .ok_or(KeyManagerServiceError::UnknownKeyBranch)? - .read() - .await; - - km.derive_public_key(0)?.key - }, - WalletType::Ledger(ledger) => { - ledger.public_alpha.clone().ok_or(KeyManagerServiceError::LedgerError( - "Key manager set to use ledger, ledger alpha public key missing".to_string(), - ))? - }, - }; + let public_alpha = self.get_spend_key().await?.1; let km = self .key_managers .get(branch) @@ -300,20 +278,143 @@ where TBackend: KeyManagerBackend + 'static } } - fn get_domain_hasher( - label: &str, - ) -> Result, KeyManagerTransactionsHashDomain>, KeyManagerServiceError> { - let tx_label = label.parse::().map_err(|e| { - KeyManagerServiceError::UnknownError(format!("Could not retrieve label for derived key: {}", e)) - })?; - match tx_label { - TransactionKeyManagerLabel::ScriptKey => Ok(DomainSeparatedHasher::< - Blake2b, - KeyManagerTransactionsHashDomain, - >::new_with_label("script key")), + pub(crate) async fn get_private_key(&self, key_id: &TariKeyId) -> Result { + match key_id { + KeyId::Managed { branch, index } => { + match &self.wallet_type { + WalletType::Software => {}, + WalletType::Ledger(wallet) => { + if &TransactionKeyManagerBranch::DataEncryption.get_branch_key() == branch { + return wallet + .view_key + .clone() + .ok_or(KeyManagerServiceError::LedgerViewKeyInaccessible); + } + + // If we're trying to access any of the private keys, just say no bueno + if &TransactionKeyManagerBranch::Spend.get_branch_key() == branch || + &TransactionKeyManagerBranch::SenderOffset.get_branch_key() == branch + { + return Err(KeyManagerServiceError::LedgerPrivateKeyInaccessible); + } + }, + WalletType::Imported(wallet) => { + if &TransactionKeyManagerBranch::DataEncryption.get_branch_key() == branch { + return Ok(wallet.view_key.clone()); + } + + // If we're trying to access any of the private keys, just say no bueno + if &TransactionKeyManagerBranch::Spend.get_branch_key() == branch { + return wallet + .private_spend_key + .clone() + .ok_or(KeyManagerServiceError::ImportedPrivateKeyInaccessible); + } + }, + } + + let km = self + .key_managers + .get(branch) + .ok_or(KeyManagerServiceError::UnknownKeyBranch)? + .read() + .await; + let key = km.get_private_key(*index)?; + Ok(key) + }, + KeyId::Derived { branch, label, index } => match &self.wallet_type { + WalletType::Ledger(_) => Err(KeyManagerServiceError::LedgerPrivateKeyInaccessible), + WalletType::Software => { + let km = self + .key_managers + .get(&TransactionKeyManagerBranch::Spend.get_branch_key()) + .ok_or(KeyManagerServiceError::UnknownKeyBranch)? + .read() + .await; + let private_alpha = km.get_private_key(0)?; + let km = self + .key_managers + .get(branch) + .ok_or(KeyManagerServiceError::UnknownKeyBranch)? + .read() + .await; + let branch_key = km.get_private_key(*index)?; + let hasher = Self::get_domain_hasher(label)?; + let hasher = hasher.chain(branch_key.as_bytes()).finalize(); + let private_key = PrivateKey::from_uniform_bytes(hasher.as_ref()).map_err(|_| { + KeyManagerServiceError::UnknownError(format!("Invalid private key for {}", label)) + })?; + let private_key = private_key + private_alpha; + Ok(private_key) + }, + WalletType::Imported(imported) => { + let private_alpha = imported + .private_spend_key + .clone() + .ok_or(KeyManagerServiceError::ImportedPrivateKeyInaccessible)?; + + let km = self + .key_managers + .get(branch) + .ok_or(KeyManagerServiceError::UnknownKeyBranch)? + .read() + .await; + let branch_key = km.get_private_key(*index)?; + let hasher = Self::get_domain_hasher(label)?; + let hasher = hasher.chain(branch_key.as_bytes()).finalize(); + let private_key = PrivateKey::from_uniform_bytes(hasher.as_ref()).map_err(|_| { + KeyManagerServiceError::UnknownError(format!("Invalid private key for {}", label)) + })?; + let private_key = private_key + private_alpha; + Ok(private_key) + }, + }, + KeyId::Imported { key } => { + let pvt_key = self.db.get_imported_key(key)?; + Ok(pvt_key) + }, + KeyId::Zero => Ok(PrivateKey::default()), } } + pub async fn get_view_key(&self) -> Result<(TariKeyId, PublicKey), KeyManagerServiceError> { + let key_id = KeyId::Managed { + branch: TransactionKeyManagerBranch::DataEncryption.get_branch_key(), + index: 0, + }; + let key = PublicKey::from_secret_key(&self.get_private_view_key().await?); + Ok((key_id, key)) + } + + pub async fn get_spend_key(&self) -> Result<(TariKeyId, PublicKey), KeyManagerServiceError> { + let key_id = KeyId::Managed { + branch: TransactionKeyManagerBranch::Spend.get_branch_key(), + index: 0, + }; + + let key = match &self.wallet_type { + WalletType::Software => { + let private_key = self.get_private_key(&key_id).await?; + PublicKey::from_secret_key(&private_key) + }, + WalletType::Ledger(ledger) => ledger.public_alpha.clone().ok_or(KeyManagerServiceError::LedgerError( + "Key manager set to use ledger, ledger alpha public key missing".to_string(), + ))?, + WalletType::Imported(imported) => imported.public_spend_key.clone(), + }; + Ok((key_id, key)) + } + + pub async fn get_comms_key(&self) -> Result<(TariKeyId, PublicKey), KeyManagerServiceError> { + let key_id = KeyId::Managed { + branch: TransactionKeyManagerBranch::Spend.get_branch_key(), + index: 0, + }; + let private_key = self.get_private_comms_key().await?; + let key = PublicKey::from_secret_key(&private_key); + Ok((key_id, key)) + } + pub async fn get_next_spend_and_script_key_ids( &self, ) -> Result<(TariKeyId, PublicKey, TariKeyId, PublicKey), KeyManagerServiceError> { @@ -332,6 +433,52 @@ where TBackend: KeyManagerBackend + 'static Ok((spend_key_id, spend_public_key, script_key_id, script_public_key)) } + pub async fn import_key(&self, private_key: PrivateKey) -> Result { + let public_key = PublicKey::from_secret_key(&private_key); + self.db.insert_imported_key(public_key.clone(), private_key)?; + let key_id = KeyId::Imported { key: public_key }; + Ok(key_id) + } + + async fn get_private_view_key(&self) -> Result { + match &self.wallet_type { + WalletType::Software => { + self.get_private_key(&TariKeyId::Managed { + branch: TransactionKeyManagerBranch::DataEncryption.get_branch_key(), + index: 0, + }) + .await + }, + WalletType::Ledger(ledger) => ledger + .view_key + .clone() + .ok_or(KeyManagerServiceError::LedgerViewKeyInaccessible), + WalletType::Imported(imported) => Ok(imported.view_key.clone()), + } + } + + async fn get_private_comms_key(&self) -> Result { + self.get_private_key(&TariKeyId::Managed { + branch: TransactionKeyManagerBranch::Spend.get_branch_key(), + index: 0, + }) + .await + } + + fn get_domain_hasher( + label: &str, + ) -> Result, KeyManagerTransactionsHashDomain>, KeyManagerServiceError> { + let tx_label = label.parse::().map_err(|e| { + KeyManagerServiceError::UnknownError(format!("Could not retrieve label for derived key: {}", e)) + })?; + match tx_label { + TransactionKeyManagerLabel::ScriptKey => Ok(DomainSeparatedHasher::< + Blake2b, + KeyManagerTransactionsHashDomain, + >::new_with_label("script key")), + } + } + /// Calculates a script key id from the spend key id, if a public key is provided, it will only return a result of /// the public keys match pub async fn find_script_key_id_from_spend_key_id( @@ -445,81 +592,6 @@ where TBackend: KeyManagerBackend + 'static Ok(()) } - pub async fn import_key(&self, private_key: PrivateKey) -> Result { - let public_key = PublicKey::from_secret_key(&private_key); - let hex_key = public_key.to_hex(); - self.db.insert_imported_key(public_key.clone(), private_key)?; - trace!(target: LOG_TARGET, "Imported key {}", hex_key); - let key_id = KeyId::Imported { key: public_key }; - Ok(key_id) - } - - pub(crate) async fn get_private_key(&self, key_id: &TariKeyId) -> Result { - match key_id { - KeyId::Managed { branch, index } => { - if let WalletType::Ledger(wallet) = &self.wallet_type { - // In the event we're asking for the view key, and we use a ledger, reference the stored key - if &TransactionKeyManagerBranch::DataEncryption.get_branch_key() == branch { - return wallet - .view_key - .clone() - .ok_or(KeyManagerServiceError::LedgerViewKeyInaccessible); - } - - // If we're trying to access any of the private keys, just say no bueno - if &TransactionKeyManagerBranch::Alpha.get_branch_key() == branch || - &TransactionKeyManagerBranch::SenderOffsetLedger.get_branch_key() == branch - { - debug!(target: LOG_TARGET, "Attempted to access private key for branch {branch:?}"); - return Err(KeyManagerServiceError::LedgerPrivateKeyInaccessible); - } - }; - - let km = self - .key_managers - .get(branch) - .ok_or(KeyManagerServiceError::UnknownKeyBranch)? - .read() - .await; - let key = km.get_private_key(*index)?; - Ok(key) - }, - KeyId::Derived { branch, label, index } => match &self.wallet_type { - WalletType::Ledger(_) => Err(KeyManagerServiceError::LedgerPrivateKeyInaccessible), - WalletType::Software => { - let km = self - .key_managers - .get(&TransactionKeyManagerBranch::Alpha.get_branch_key()) - .ok_or(KeyManagerServiceError::UnknownKeyBranch)? - .read() - .await; - - let private_alpha = km.get_private_key(0)?; - - let km = self - .key_managers - .get(branch) - .ok_or(KeyManagerServiceError::UnknownKeyBranch)? - .read() - .await; - let branch_key = km.get_private_key(*index)?; - let hasher = Self::get_domain_hasher(label)?; - let hasher = hasher.chain(branch_key.as_bytes()).finalize(); - let private_key = PrivateKey::from_uniform_bytes(hasher.as_ref()).map_err(|_| { - KeyManagerServiceError::UnknownError(format!("Invalid private key for {}", label)) - })?; - let private_key = private_key + private_alpha; - Ok(private_key) - }, - }, - KeyId::Imported { key } => { - let pvt_key = self.db.get_imported_key(key)?; - Ok(pvt_key) - }, - KeyId::Zero => Ok(PrivateKey::default()), - } - } - // ----------------------------------------------------------------------------------------------------------------- // General crypto section // ----------------------------------------------------------------------------------------------------------------- @@ -903,7 +975,7 @@ where TBackend: KeyManagerBackend + 'static label: _, index, } => match &self.wallet_type { - WalletType::Software => { + WalletType::Software | WalletType::Imported(_) => { total_script_private_key = total_script_private_key + self.get_private_key(script_key_id).await?; }, @@ -924,7 +996,7 @@ where TBackend: KeyManagerBackend + 'static } match &self.wallet_type { - WalletType::Software => { + WalletType::Software | WalletType::Imported(_) => { let mut total_sender_offset_private_key = PrivateKey::default(); for sender_offset_key_id in sender_offset_key_ids { total_sender_offset_private_key = @@ -1278,14 +1350,6 @@ where TBackend: KeyManagerBackend + 'static // Encrypted data section (transactions > transaction_components > encrypted_data) // ----------------------------------------------------------------------------------------------------------------- - async fn get_view_key(&self) -> Result { - self.get_private_key(&TariKeyId::Managed { - branch: TransactionKeyManagerBranch::DataEncryption.get_branch_key(), - index: 0, - }) - .await - } - pub async fn encrypt_data_for_recovery( &self, spend_key_id: &TariKeyId, @@ -1296,7 +1360,7 @@ where TBackend: KeyManagerBackend + 'static let recovery_key = if let Some(key_id) = custom_recovery_key_id { self.get_private_key(key_id).await? } else { - self.get_view_key().await? + self.get_private_view_key().await? }; let value_key = value.into(); let commitment = self.get_commitment(spend_key_id, &value_key).await?; @@ -1313,7 +1377,7 @@ where TBackend: KeyManagerBackend + 'static let recovery_key = if let Some(key_id) = custom_recovery_key_id { self.get_private_key(key_id).await? } else { - self.get_view_key().await? + self.get_private_view_key().await? }; let (value, private_key, payment_id) = EncryptedData::decrypt_data(&recovery_key, output.commitment(), output.encrypted_data())?; diff --git a/base_layer/core/src/transactions/key_manager/interface.rs b/base_layer/core/src/transactions/key_manager/interface.rs index 0d9ca012c5..ac998082c7 100644 --- a/base_layer/core/src/transactions/key_manager/interface.rs +++ b/base_layer/core/src/transactions/key_manager/interface.rs @@ -25,7 +25,10 @@ use std::str::FromStr; use blake2::Blake2b; use digest::consts::U64; use strum_macros::EnumIter; -use tari_common_types::types::{ComAndPubSignature, Commitment, PrivateKey, PublicKey, RangeProof, Signature}; +use tari_common_types::{ + types::{ComAndPubSignature, Commitment, PrivateKey, PublicKey, RangeProof, Signature}, + WALLET_COMMS_AND_SPEND_KEY_BRANCH, +}; use tari_comms::types::CommsDHKE; use tari_crypto::{hashing::DomainSeparatedHash, ristretto::RistrettoComSig}; use tari_key_manager::key_manager_service::{KeyId, KeyManagerInterface, KeyManagerServiceError}; @@ -58,13 +61,13 @@ pub enum TxoStage { #[derive(Clone, Copy, EnumIter)] pub enum TransactionKeyManagerBranch { DataEncryption = 0x00, - Alpha = 0x01, - MetadataEphemeralNonce = 0x02, - CommitmentMask = 0x03, - Nonce = 0x04, - KernelNonce = 0x05, - SenderOffset = 0x06, - SenderOffsetLedger = 0x07, + MetadataEphemeralNonce = 0x01, + CommitmentMask = 0x02, + Nonce = 0x03, + KernelNonce = 0x04, + SenderOffset = 0x05, + SenderOffsetLedger = 0x06, + Spend = 0x07, } impl TransactionKeyManagerBranch { @@ -73,26 +76,26 @@ impl TransactionKeyManagerBranch { pub fn get_branch_key(self) -> String { match self { TransactionKeyManagerBranch::DataEncryption => "data encryption".to_string(), - TransactionKeyManagerBranch::Alpha => "alpha".to_string(), TransactionKeyManagerBranch::CommitmentMask => "commitment mask".to_string(), TransactionKeyManagerBranch::Nonce => "nonce".to_string(), TransactionKeyManagerBranch::MetadataEphemeralNonce => "metadata ephemeral nonce".to_string(), TransactionKeyManagerBranch::KernelNonce => "kernel nonce".to_string(), TransactionKeyManagerBranch::SenderOffset => "sender offset".to_string(), TransactionKeyManagerBranch::SenderOffsetLedger => "sender offset ledger".to_string(), + TransactionKeyManagerBranch::Spend => WALLET_COMMS_AND_SPEND_KEY_BRANCH.to_string(), } } pub fn from_key(key: &str) -> Self { match key { "data encryption" => TransactionKeyManagerBranch::DataEncryption, - "alpha" => TransactionKeyManagerBranch::Alpha, "commitment mask" => TransactionKeyManagerBranch::CommitmentMask, "metadata ephemeral nonce" => TransactionKeyManagerBranch::MetadataEphemeralNonce, "kernel nonce" => TransactionKeyManagerBranch::KernelNonce, "sender offset" => TransactionKeyManagerBranch::SenderOffset, "sender offset ledger" => TransactionKeyManagerBranch::SenderOffsetLedger, "nonce" => TransactionKeyManagerBranch::Nonce, + WALLET_COMMS_AND_SPEND_KEY_BRANCH => TransactionKeyManagerBranch::Spend, _ => TransactionKeyManagerBranch::Nonce, } } @@ -144,7 +147,11 @@ pub trait TransactionKeyManagerInterface: KeyManagerInterface { value: u64, ) -> Result; - async fn get_view_key_id(&self) -> Result; + async fn get_view_key(&self) -> Result<(TariKeyId, PublicKey), KeyManagerServiceError>; + + async fn get_spend_key(&self) -> Result<(TariKeyId, PublicKey), KeyManagerServiceError>; + + async fn get_comms_key(&self) -> Result<(TariKeyId, PublicKey), KeyManagerServiceError>; async fn get_next_spend_and_script_key_ids( &self, @@ -307,11 +314,6 @@ pub trait TransactionKeyManagerInterface: KeyManagerInterface { amount: &PrivateKey, claim_public_key: &PublicKey, ) -> Result; - - async fn create_key_pair + Send>( - &self, - branch: T, - ) -> Result<(TariKeyId, PublicKey), KeyManagerServiceError>; } #[async_trait::async_trait] diff --git a/base_layer/core/src/transactions/key_manager/wrapper.rs b/base_layer/core/src/transactions/key_manager/wrapper.rs index 8e7a8b959d..1a7c026044 100644 --- a/base_layer/core/src/transactions/key_manager/wrapper.rs +++ b/base_layer/core/src/transactions/key_manager/wrapper.rs @@ -46,7 +46,6 @@ use crate::transactions::{ key_manager::{ interface::{SecretTransactionKeyManagerInterface, TxoStage}, TariKeyId, - TransactionKeyManagerBranch, TransactionKeyManagerInner, TransactionKeyManagerInterface, }, @@ -202,9 +201,16 @@ where TBackend: KeyManagerBackend + 'static .await } - async fn get_view_key_id(&self) -> Result { - self.get_static_key(TransactionKeyManagerBranch::DataEncryption.get_branch_key()) - .await + async fn get_view_key(&self) -> Result<(TariKeyId, PublicKey), KeyManagerServiceError> { + self.transaction_key_manager_inner.read().await.get_view_key().await + } + + async fn get_spend_key(&self) -> Result<(TariKeyId, PublicKey), KeyManagerServiceError> { + self.transaction_key_manager_inner.read().await.get_spend_key().await + } + + async fn get_comms_key(&self) -> Result<(TariKeyId, PublicKey), KeyManagerServiceError> { + self.transaction_key_manager_inner.read().await.get_comms_key().await } async fn get_next_spend_and_script_key_ids( @@ -536,17 +542,6 @@ where TBackend: KeyManagerBackend + 'static .generate_burn_proof(spending_key, amount, claim_public_key) .await } - - async fn create_key_pair + Send>( - &self, - branch: T, - ) -> Result<(TariKeyId, PublicKey), KeyManagerServiceError> { - self.transaction_key_manager_inner - .write() - .await - .create_key_pair(&branch.into()) - .await - } } #[async_trait::async_trait] diff --git a/base_layer/key_manager/src/key_manager_service/error.rs b/base_layer/key_manager/src/key_manager_service/error.rs index 43c3196e80..57cbd817a0 100644 --- a/base_layer/key_manager/src/key_manager_service/error.rs +++ b/base_layer/key_manager/src/key_manager_service/error.rs @@ -57,6 +57,8 @@ pub enum KeyManagerServiceError { LedgerViewKeyInaccessible, #[error("Tari Key Manager storage error: `{0}`")] StorageError(#[from] StorageError), + #[error("The imported private key cannot be accessed or read")] + ImportedPrivateKeyInaccessible, } impl From for KeyManagerServiceError { diff --git a/base_layer/key_manager/src/key_manager_service/interface.rs b/base_layer/key_manager/src/key_manager_service/interface.rs index 807885da98..b66a518d39 100644 --- a/base_layer/key_manager/src/key_manager_service/interface.rs +++ b/base_layer/key_manager/src/key_manager_service/interface.rs @@ -26,6 +26,7 @@ use std::{fmt, str::FromStr}; use serde::{Deserialize, Serialize}; use strum_macros::EnumIter; +use tari_common_types::WALLET_COMMS_AND_SPEND_KEY_BRANCH; use tari_crypto::keys::{PublicKey, SecretKey}; use tari_utilities::{hex::Hex, ByteArray}; @@ -42,7 +43,7 @@ impl KeyManagerBranch { /// recovery. pub fn get_branch_key(self) -> String { match self { - KeyManagerBranch::Comms => "comms".to_string(), + KeyManagerBranch::Comms => WALLET_COMMS_AND_SPEND_KEY_BRANCH.to_string(), } } } diff --git a/base_layer/key_manager/src/key_manager_service/service.rs b/base_layer/key_manager/src/key_manager_service/service.rs index 560ee2d556..352b6e3351 100644 --- a/base_layer/key_manager/src/key_manager_service/service.rs +++ b/base_layer/key_manager/src/key_manager_service/service.rs @@ -31,7 +31,7 @@ use tari_crypto::{ hashing::DomainSeparatedHasher, keys::{PublicKey, SecretKey}, }; -use tari_utilities::{hex::Hex, ByteArray}; +use tari_utilities::ByteArray; use crate::{ cipher_seed::CipherSeed, @@ -217,9 +217,7 @@ where pub async fn import_key(&self, private_key: PK::K) -> Result, KeyManagerServiceError> { let public_key = PK::from_secret_key(&private_key); - let hex_key = public_key.to_hex(); self.db.insert_imported_key(public_key.clone(), private_key)?; - trace!(target: LOG_TARGET, "Imported key {}", hex_key); let key_id = KeyId::Imported { key: public_key }; Ok(key_id) } diff --git a/base_layer/wallet/src/output_manager_service/mod.rs b/base_layer/wallet/src/output_manager_service/mod.rs index f441c48588..c748236356 100644 --- a/base_layer/wallet/src/output_manager_service/mod.rs +++ b/base_layer/wallet/src/output_manager_service/mod.rs @@ -33,11 +33,10 @@ pub mod service; pub mod storage; mod tasks; -use std::{marker::PhantomData, sync::Arc}; +use std::marker::PhantomData; use futures::future; use log::*; -use tari_comms::NodeIdentity; use tari_core::{ consensus::NetworkConsensus, transactions::{ @@ -77,7 +76,6 @@ where T: OutputManagerBackend backend: Option, factories: CryptoFactories, network: NetworkConsensus, - node_identity: Arc, phantom: PhantomData, } @@ -89,14 +87,12 @@ where T: OutputManagerBackend + 'static backend: T, factories: CryptoFactories, network: NetworkConsensus, - node_identity: Arc, ) -> Self { Self { config, backend: Some(backend), factories, network, - node_identity, phantom: PhantomData, } } @@ -123,8 +119,6 @@ where let factories = self.factories.clone(); let config = self.config.clone(); let constants = self.network.create_consensus_constants().pop().unwrap(); - let node_identity = self.node_identity.clone(); - let network = self.network.as_network(); context.spawn_when_ready(move |handles| async move { let base_node_service_handle = handles.expect_handle::(); let connectivity = handles.expect_handle::(); @@ -140,8 +134,6 @@ where handles.get_shutdown_signal(), base_node_service_handle, connectivity, - node_identity, - network, key_manager, ) .await diff --git a/base_layer/wallet/src/output_manager_service/resources.rs b/base_layer/wallet/src/output_manager_service/resources.rs index 104588f742..8f55251e9e 100644 --- a/base_layer/wallet/src/output_manager_service/resources.rs +++ b/base_layer/wallet/src/output_manager_service/resources.rs @@ -23,13 +23,10 @@ use tari_core::{consensus::ConsensusConstants, transactions::CryptoFactories}; use tari_shutdown::ShutdownSignal; -use crate::{ - output_manager_service::{ - config::OutputManagerServiceConfig, - handle::OutputManagerEventSender, - storage::database::OutputManagerDatabase, - }, - util::wallet_identity::WalletIdentity, +use crate::output_manager_service::{ + config::OutputManagerServiceConfig, + handle::OutputManagerEventSender, + storage::database::OutputManagerDatabase, }; /// This struct is a collection of the common resources that a async task in the service requires. @@ -43,5 +40,4 @@ pub(crate) struct OutputManagerResources, - network: Network, key_manager: TKeyManagerInterface, ) -> Result { - let view_key = key_manager.get_view_key_id().await?; - let view_key = key_manager.get_public_key_at_key_id(&view_key).await?; - let tari_address = - TariAddress::new_dual_address_with_default_features(view_key, node_identity.public_key().clone(), network); - let wallet_identity = WalletIdentity::new(node_identity.clone(), tari_address); let resources = OutputManagerResources { config, db, @@ -167,7 +158,6 @@ where key_manager, consensus_constants, shutdown_signal, - wallet_identity, }; Ok(Self { @@ -180,13 +170,6 @@ where } pub async fn start(mut self) -> Result<(), OutputManagerError> { - // we need to ensure the wallet identity secret key is stored in the key manager - let _key_id = self - .resources - .key_manager - .import_key(self.resources.wallet_identity.node_identity.secret_key().clone()) - .await?; - let request_stream = self .request_stream .take() @@ -1250,12 +1233,9 @@ where let self_signature = self .resources .key_manager - .sign_script_message(&self.resources.wallet_identity.wallet_node_key_id, &script_challange) + .sign_script_message(&self.resources.key_manager.get_spend_key().await?.0, &script_challange) .await?; - script_input_shares.insert( - self.resources.wallet_identity.address.public_spend_key().clone(), - self_signature, - ); + script_input_shares.insert(self.resources.key_manager.get_spend_key().await?.1, self_signature); // the order here is important, we need to add the signatures in the same order as public keys where // added to the script originally @@ -1263,7 +1243,7 @@ where if let Some(signature) = script_input_shares.get(&key) { script_signatures.push(StackItem::Signature(signature.clone())); // our own key should not be added yet, it will be added with the script signing - if &key != self.resources.wallet_identity.address.public_spend_key() { + if key != self.resources.key_manager.get_spend_key().await?.1 { aggregated_script_public_key_shares = aggregated_script_public_key_shares + key; } } @@ -1276,7 +1256,7 @@ where output.features, output.script, ExecutionStack::new(script_signatures), - self.resources.wallet_identity.wallet_node_key_id.clone(), // Only of the master wallet + self.resources.key_manager.get_spend_key().await?.0, // Only of the master wallet output.sender_offset_public_key, output.metadata_signature, 0, @@ -1435,7 +1415,7 @@ where .await? .with_input_data(ExecutionStack::default()) // Just a placeholder in the wallet .with_sender_offset_public_key(sender_offset_public_key) - .with_script_key(self.resources.wallet_identity.wallet_node_key_id.clone()) + .with_script_key(self.resources.key_manager.get_spend_key().await?.0) .with_minimum_value_promise(minimum_value_promise) .sign_partial_as_sender_and_receiver( &self.resources.key_manager, @@ -2477,7 +2457,7 @@ where .resources .key_manager .get_diffie_hellman_shared_secret( - &self.resources.key_manager.get_view_key_id().await?, + &self.resources.key_manager.get_view_key().await?.0, &output.sender_offset_public_key, ) .await?; @@ -2494,7 +2474,7 @@ where output.features, output.script, inputs!(pre_image), - self.resources.wallet_identity.wallet_node_key_id.clone(), + self.resources.key_manager.get_spend_key().await?.0, output.sender_offset_public_key, output.metadata_signature, // Although the technically the script does have a script lock higher than 0, this does not apply @@ -2689,9 +2669,8 @@ where )); } - let wallet_sk = self.resources.wallet_identity.wallet_node_key_id.clone(); - let wallet_pk = self.resources.key_manager.get_public_key_at_key_id(&wallet_sk).await?; - let wallet_view_key = self.resources.key_manager.get_view_key_id().await?; + let (wallet_sk, wallet_pk) = self.resources.key_manager.get_spend_key().await?; + let (wallet_view_key, _) = self.resources.key_manager.get_view_key().await?; let mut scanned_outputs = vec![]; diff --git a/base_layer/wallet/src/transaction_service/protocols/transaction_receive_protocol.rs b/base_layer/wallet/src/transaction_service/protocols/transaction_receive_protocol.rs index 9515d32fca..5d812ed128 100644 --- a/base_layer/wallet/src/transaction_service/protocols/transaction_receive_protocol.rs +++ b/base_layer/wallet/src/transaction_service/protocols/transaction_receive_protocol.rs @@ -435,7 +435,7 @@ where let completed_transaction = CompletedTransaction::new( self.id, self.source_address.clone(), - self.resources.wallet_identity.address.clone(), + self.resources.tari_address.clone(), inbound_tx.amount, finalized_transaction .body diff --git a/base_layer/wallet/src/transaction_service/protocols/transaction_send_protocol.rs b/base_layer/wallet/src/transaction_service/protocols/transaction_send_protocol.rs index a0174d009a..467918c0e1 100644 --- a/base_layer/wallet/src/transaction_service/protocols/transaction_send_protocol.rs +++ b/base_layer/wallet/src/transaction_service/protocols/transaction_send_protocol.rs @@ -593,7 +593,7 @@ where let completed_transaction = CompletedTransaction::new( tx_id, - self.resources.wallet_identity.address.clone(), + self.resources.tari_address.clone(), outbound_tx.destination_address, outbound_tx.amount, outbound_tx.fee, diff --git a/base_layer/wallet/src/transaction_service/service.rs b/base_layer/wallet/src/transaction_service/service.rs index 2e640b6dc0..181bf5f666 100644 --- a/base_layer/wallet/src/transaction_service/service.rs +++ b/base_layer/wallet/src/transaction_service/service.rs @@ -84,7 +84,6 @@ use tari_crypto::{ use tari_key_manager::key_manager_service::KeyId; use tari_p2p::domain_message::DomainMessage; use tari_script::{ - inputs, push_pubkey_script, script, slice_to_boxed_message, @@ -142,7 +141,7 @@ use crate::{ }, utc::utc_duration_since, }, - util::{wallet_identity::WalletIdentity, watch::Watch}, + util::watch::Watch, utxo_scanner_service::RECOVERY_KEY, OperationId, }; @@ -260,11 +259,9 @@ where ) -> Result { // Collect the resources that all protocols will need so that they can be neatly cloned as the protocols are // spawned. - let view_key = core_key_manager_service.get_view_key_id().await?; - let view_key = core_key_manager_service.get_public_key_at_key_id(&view_key).await?; + let (_view_key_id, view_key) = core_key_manager_service.get_view_key().await?; let tari_address = TariAddress::new_dual_address_with_default_features(view_key, node_identity.public_key().clone(), network); - let wallet_identity = WalletIdentity::new(node_identity.clone(), tari_address); let resources = TransactionServiceResources { db: db.clone(), output_manager_service, @@ -272,7 +269,8 @@ where outbound_message_service, connectivity, event_publisher: event_publisher.clone(), - wallet_identity, + tari_address, + node_identity: node_identity.clone(), factories, config: config.clone(), shutdown_signal, @@ -313,13 +311,6 @@ where #[allow(clippy::too_many_lines)] pub async fn start(mut self) -> Result<(), TransactionServiceError> { - // we need to ensure the wallet identity secret key is stored in the key manager - let _key_id = self - .resources - .transaction_key_manager_service - .import_key(self.resources.wallet_identity.node_identity.secret_key().clone()) - .await?; - let request_stream = self .request_stream .take() @@ -432,7 +423,7 @@ where } Err(e) => { warn!(target: LOG_TARGET, "Failed to handle incoming Transaction message: {} for NodeID: {}, Trace: {}", - e, self.resources.wallet_identity.node_identity.node_id().short_str(), msg.dht_header.message_tag); + e, self.resources.node_identity.node_id().short_str(), msg.dht_header.message_tag); let _size = self.event_publisher.send(Arc::new(TransactionEvent::Error(format!("Error handling \ Transaction Sender message: {:?}", e).to_string()))); } @@ -455,12 +446,12 @@ where Err(TransactionServiceError::TransactionDoesNotExistError) => { trace!(target: LOG_TARGET, "Unable to handle incoming Transaction Reply message from NodeId: \ {} due to Transaction not existing. This usually means the message was a repeated message \ - from Store and Forward, Trace: {}", self.resources.wallet_identity.node_identity.node_id().short_str(), + from Store and Forward, Trace: {}", self.resources.node_identity.node_id().short_str(), msg.dht_header.message_tag); }, Err(e) => { warn!(target: LOG_TARGET, "Failed to handle incoming Transaction Reply message: {} \ - for NodeId: {}, Trace: {}", e, self.resources.wallet_identity.node_identity.node_id().short_str(), + for NodeId: {}, Trace: {}", e, self.resources.node_identity.node_id().short_str(), msg.dht_header.message_tag); let _size = self.event_publisher.send(Arc::new(TransactionEvent::Error("Error handling \ Transaction Recipient Reply message".to_string()))); @@ -491,12 +482,12 @@ where Err(TransactionServiceError::TransactionDoesNotExistError) => { trace!(target: LOG_TARGET, "Unable to handle incoming Finalized Transaction message from NodeId: \ {} due to Transaction not existing. This usually means the message was a repeated message \ - from Store and Forward, Trace: {}", self.resources.wallet_identity.node_identity.node_id().short_str(), + from Store and Forward, Trace: {}", self.resources.node_identity.node_id().short_str(), msg.dht_header.message_tag); }, Err(e) => { warn!(target: LOG_TARGET, "Failed to handle incoming Transaction Finalized message: {} \ - for NodeID: {}, Trace: {}", e , self.resources.wallet_identity.node_identity.node_id().short_str(), + for NodeID: {}, Trace: {}", e , self.resources.node_identity.node_id().short_str(), msg.dht_header.message_tag.as_value()); let _size = self.event_publisher.send(Arc::new(TransactionEvent::Error("Error handling Transaction \ Finalized message".to_string(),))); @@ -516,7 +507,7 @@ where trace!(target: LOG_TARGET, "Handling Base Node Response, Trace: {}", msg.dht_header.message_tag); let _result = self.handle_base_node_response(inner_msg).await.map_err(|e| { warn!(target: LOG_TARGET, "Error handling base node service response from {}: {:?} for \ - NodeID: {}, Trace: {}", origin_public_key, e, self.resources.wallet_identity.node_identity.node_id().short_str(), + NodeID: {}, Trace: {}", origin_public_key, e, self.resources.node_identity.node_id().short_str(), msg.dht_header.message_tag.as_value()); e }); @@ -1086,7 +1077,7 @@ where reply_channel: oneshot::Sender>, ) -> Result<(), TransactionServiceError> { let tx_id = TxId::new_random(); - if destination.network() != self.resources.wallet_identity.address.network() { + if destination.network() != self.resources.tari_address.network() { let _result = reply_channel .send(Err(TransactionServiceError::InvalidNetwork)) .inspect_err(|_| { @@ -1095,7 +1086,7 @@ where return Err(TransactionServiceError::InvalidNetwork); } // If we're paying ourselves, let's complete and submit the transaction immediately - if self.resources.wallet_identity.address.comms_public_key() == destination.comms_public_key() { + if &self.resources.transaction_key_manager_service.get_comms_key().await?.1 == destination.comms_public_key() { debug!( target: LOG_TARGET, "Received transaction with spend-to-self transaction" @@ -1116,8 +1107,8 @@ where transaction_broadcast_join_handles, CompletedTransaction::new( tx_id, - self.resources.wallet_identity.address.clone(), - self.resources.wallet_identity.address.clone(), + self.resources.tari_address.clone(), + self.resources.tari_address.clone(), amount, fee, transaction, @@ -1355,8 +1346,8 @@ where transaction_broadcast_join_handles, CompletedTransaction::new( tx_id, - self.resources.wallet_identity.address.clone(), - self.resources.wallet_identity.address.clone(), + self.resources.tari_address.clone(), + self.resources.tari_address.clone(), amount, fee, tx.clone(), @@ -1450,7 +1441,7 @@ where )) => { let completed_tx = CompletedTransaction::new( tx_id, - self.resources.wallet_identity.address.clone(), + self.resources.tari_address.clone(), recipient_address, amount, fee, @@ -1595,7 +1586,7 @@ where HashSha256 PushHash(Box::new(hash)) Equal IfThen PushPubKey(Box::new(destination.public_spend_key().clone())) Else - CheckHeightVerify(height) PushPubKey(Box::new(self.resources.wallet_identity.node_identity.public_key().clone())) + CheckHeightVerify(height) PushPubKey(Box::new(self.resources.node_identity.public_key().clone())) EndIf ); @@ -1709,7 +1700,7 @@ where .with_input_data(ExecutionStack::default()) .with_covenant(covenant) .with_sender_offset_public_key(sender_offset_public_key) - .with_script_key(self.resources.wallet_identity.wallet_node_key_id.clone()) + .with_script_key(self.resources.transaction_key_manager_service.get_spend_key().await?.0) .with_minimum_value_promise(minimum_value_promise) .sign_as_sender_and_receiver( &self.resources.transaction_key_manager_service, @@ -1772,7 +1763,7 @@ where transaction_broadcast_join_handles, CompletedTransaction::new( tx_id, - self.resources.wallet_identity.address.clone(), + self.resources.tari_address.clone(), destination, amount, fee, @@ -1948,11 +1939,9 @@ where payment_id.clone(), ) .await? - .with_input_data(inputs!(PublicKey::from_secret_key( - self.resources.wallet_identity.node_identity.secret_key() - ))) + .with_input_data(Default::default()) .with_sender_offset_public_key(sender_offset_public_key) - .with_script_key(self.resources.wallet_identity.wallet_node_key_id.clone()) + .with_script_key(KeyId::Zero) .with_minimum_value_promise(minimum_value_promise) .sign_as_sender_and_receiver( &self.resources.transaction_key_manager_service, @@ -2009,7 +1998,7 @@ where transaction_broadcast_join_handles, CompletedTransaction::new( tx_id, - self.resources.wallet_identity.address.clone(), + self.resources.tari_address.clone(), dest_address, amount, fee, @@ -2046,15 +2035,9 @@ where JoinHandle>>, >, ) -> Result { - if destination.network() != self.resources.wallet_identity.address.network() { + if destination.network() != self.resources.tari_address.network() { return Err(TransactionServiceError::InvalidNetwork); } - if self.resources.wallet_identity.node_identity.public_key() == destination.comms_public_key() { - warn!(target: LOG_TARGET, "One-sided spend-to-self transactions not supported"); - return Err(TransactionServiceError::OneSidedTransactionError( - "One-sided spend-to-self transactions not supported".to_string(), - )); - } let dest_pubkey = destination.public_spend_key().clone(); self.send_one_sided_or_stealth( destination, @@ -2137,7 +2120,7 @@ where .get_next_spend_and_script_key_ids() .await?; - let recovery_key_id = self.resources.transaction_key_manager_service.get_view_key_id().await?; + let recovery_key_id = self.resources.transaction_key_manager_service.get_view_key().await?.0; let recovery_key_id = match claim_public_key { Some(ref claim_public_key) => { @@ -2186,9 +2169,7 @@ where PaymentId::Empty, ) .await? - .with_input_data(inputs!(PublicKey::from_secret_key( - self.resources.wallet_identity.node_identity.secret_key() - ))) + .with_input_data(Default::default()) .with_sender_offset_public_key( sender_message .single() @@ -2199,7 +2180,7 @@ where .sender_offset_public_key .clone(), ) - .with_script_key(self.resources.wallet_identity.wallet_node_key_id.clone()) + .with_script_key(KeyId::Zero) .with_minimum_value_promise( sender_message .single() @@ -2274,7 +2255,7 @@ where transaction_broadcast_join_handles, CompletedTransaction::new( tx_id, - self.resources.wallet_identity.address.clone(), + self.resources.tari_address.clone(), TariAddress::default(), amount, fee, @@ -2319,7 +2300,7 @@ where let output_features = OutputFeatures::for_validator_node_registration(validator_node_public_key, validator_node_signature); self.send_transaction( - self.resources.wallet_identity.address.clone(), + self.resources.tari_address.clone(), amount, selection_criteria, output_features, @@ -2348,7 +2329,7 @@ where reply_channel: oneshot::Sender>, ) -> Result<(), TransactionServiceError> { self.send_transaction( - self.resources.wallet_identity.address.clone(), + self.resources.tari_address.clone(), 0.into(), selection_criteria, OutputFeatures::for_template_registration(template_registration), @@ -2380,7 +2361,7 @@ where JoinHandle>>, >, ) -> Result { - if destination.network() != self.resources.wallet_identity.address.network() { + if destination.network() != self.resources.tari_address.network() { return Err(TransactionServiceError::InvalidNetwork); } @@ -2862,7 +2843,7 @@ where // interactive and its the same network let source_address = TariAddress::new_single_address( source_pubkey, - self.resources.wallet_identity.network(), + self.resources.tari_address.network(), TariAddressFeatures::INTERACTIVE, ); let protocol = TransactionReceiveProtocol::new( @@ -2922,7 +2903,7 @@ where // but we know its interactive, so make the view key 0, and the spend key the source public key. let source_address = TariAddress::new_single_address( source_pubkey, - self.resources.wallet_identity.address.network(), + self.resources.tari_address.network(), TariAddressFeatures::INTERACTIVE, ); let sender = match self.finalized_transaction_senders.get_mut(&tx_id) { @@ -3390,7 +3371,7 @@ where tx_id, value, source_address, - self.resources.wallet_identity.address.clone(), + self.resources.tari_address.clone(), message, import_status.clone(), current_height, @@ -3489,8 +3470,8 @@ where transaction_broadcast_join_handles, CompletedTransaction::new( tx_id, - self.resources.wallet_identity.address.clone(), - self.resources.wallet_identity.address.clone(), + self.resources.tari_address.clone(), + self.resources.tari_address.clone(), amount, fee, tx, @@ -3531,7 +3512,8 @@ pub struct TransactionServiceResources, pub consensus_manager: ConsensusManager, pub factories: CryptoFactories, pub config: TransactionServiceConfig, diff --git a/base_layer/wallet/src/util/wallet_identity.rs b/base_layer/wallet/src/util/wallet_identity.rs index f545a9caaf..00fe954fed 100644 --- a/base_layer/wallet/src/util/wallet_identity.rs +++ b/base_layer/wallet/src/util/wallet_identity.rs @@ -30,32 +30,39 @@ use tari_core::transactions::key_manager::TariKeyId; #[derive(Clone, Debug)] pub struct WalletIdentity { pub node_identity: Arc, - pub address: TariAddress, + pub address_interactive: TariAddress, + pub address_one_sided: TariAddress, pub wallet_node_key_id: TariKeyId, } impl WalletIdentity { - pub fn new(node_identity: Arc, address: TariAddress) -> Self { + pub fn new( + node_identity: Arc, + address_interactive: TariAddress, + address_one_sided: TariAddress, + ) -> Self { let wallet_node_key_id = TariKeyId::Imported { key: node_identity.public_key().clone(), }; WalletIdentity { node_identity, - address, + address_interactive, + address_one_sided, wallet_node_key_id, } } pub fn network(&self) -> Network { - self.address.network() + self.address_interactive.network() } } impl Display for WalletIdentity { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { writeln!(f, "{}", self.node_identity)?; - writeln!(f, "Tari Address: {}", self.address)?; - writeln!(f, "Network: {:?}", self.address.network())?; + writeln!(f, "Tari Address interactive: {}", self.address_interactive)?; + writeln!(f, "Tari Address one-sided: {}", self.address_one_sided)?; + writeln!(f, "Network: {:?}", self.address_interactive.network())?; Ok(()) } } diff --git a/base_layer/wallet/src/utxo_scanner_service/initializer.rs b/base_layer/wallet/src/utxo_scanner_service/initializer.rs index 5eb1f76de4..22a465135b 100644 --- a/base_layer/wallet/src/utxo_scanner_service/initializer.rs +++ b/base_layer/wallet/src/utxo_scanner_service/initializer.rs @@ -20,12 +20,13 @@ // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE // USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -use std::{marker::PhantomData, sync::Arc}; +use std::marker::PhantomData; use futures::future; use log::*; use tari_common::configuration::Network; -use tari_comms::{connectivity::ConnectivityRequester, NodeIdentity}; +use tari_common_types::tari_address::{TariAddress, TariAddressFeatures}; +use tari_comms::connectivity::ConnectivityRequester; use tari_core::transactions::{key_manager::TransactionKeyManagerInterface, CryptoFactories}; use tari_service_framework::{async_trait, ServiceInitializationError, ServiceInitializer, ServiceInitializerContext}; use tokio::sync::broadcast; @@ -49,7 +50,6 @@ const LOG_TARGET: &str = "wallet::utxo_scanner_service::initializer"; pub struct UtxoScannerServiceInitializer { backend: Option>, factories: CryptoFactories, - node_identity: Arc, network: Network, phantom: PhantomData, } @@ -57,16 +57,10 @@ pub struct UtxoScannerServiceInitializer { impl UtxoScannerServiceInitializer where T: WalletBackend + 'static { - pub fn new( - backend: WalletDatabase, - factories: CryptoFactories, - node_identity: Arc, - network: Network, - ) -> Self { + pub fn new(backend: WalletDatabase, factories: CryptoFactories, network: Network) -> Self { Self { backend: Some(backend), factories, - node_identity, network, phantom: PhantomData, } @@ -100,7 +94,6 @@ where .take() .expect("Cannot start Utxo scanner service without setting a storage backend"); let factories = self.factories.clone(); - let node_identity = self.node_identity.clone(); let network = self.network; context.spawn_when_ready(move |handles| async move { @@ -111,19 +104,32 @@ where let base_node_service_handle = handles.expect_handle::(); let key_manager = handles.expect_handle::(); + let (_view_key_id, view_key) = key_manager + .get_view_key() + .await + .expect("Could not initialize UTXO scanner Service"); + let (_spend_key_id, spend_key) = key_manager + .get_spend_key() + .await + .expect("Could not initialize UTXO scanner Service"); + let one_sided_tari_address = TariAddress::new_dual_address( + view_key, + spend_key, + network, + TariAddressFeatures::create_one_sided_only(), + ); + let scanning_service = UtxoScannerService::::builder() .with_peers(vec![]) .with_retry_limit(2) .with_mode(UtxoScannerMode::Scanning) - .build_with_resources( + .build_with_resources::( backend, comms_connectivity, wallet_connectivity.clone(), output_manager_service, transaction_service, - key_manager, - node_identity, - network, + one_sided_tari_address, factories, handles.get_shutdown_signal(), event_sender, @@ -132,7 +138,6 @@ where recovery_message_watch_receiver, ) .await - .expect("Could not initialize UTXO scanner Service") .run(); futures::pin_mut!(scanning_service); diff --git a/base_layer/wallet/src/utxo_scanner_service/service.rs b/base_layer/wallet/src/utxo_scanner_service/service.rs index e70c168884..4bfc99d0fe 100644 --- a/base_layer/wallet/src/utxo_scanner_service/service.rs +++ b/base_layer/wallet/src/utxo_scanner_service/service.rs @@ -23,7 +23,7 @@ use chrono::NaiveDateTime; use futures::FutureExt; use log::*; -use tari_common_types::types::HashOutput; +use tari_common_types::{tari_address::TariAddress, types::HashOutput}; use tari_comms::{connectivity::ConnectivityRequester, peer_manager::Peer, types::CommsPublicKey}; use tari_core::transactions::{tari_amount::MicroMinotari, CryptoFactories}; use tari_shutdown::{Shutdown, ShutdownSignal}; @@ -39,7 +39,6 @@ use crate::{ output_manager_service::handle::OutputManagerHandle, storage::database::{WalletBackend, WalletDatabase}, transaction_service::handle::TransactionServiceHandle, - util::wallet_identity::WalletIdentity, utxo_scanner_service::{ handle::UtxoScannerEvent, utxo_scanner_task::UtxoScannerTask, @@ -194,7 +193,7 @@ pub struct UtxoScannerResources { pub current_base_node_watcher: watch::Receiver>, pub output_manager_service: OutputManagerHandle, pub transaction_service: TransactionServiceHandle, - pub wallet_identity: WalletIdentity, + pub one_sided_tari_address: TariAddress, pub factories: CryptoFactories, pub recovery_message: String, pub one_sided_payment_message: String, diff --git a/base_layer/wallet/src/utxo_scanner_service/utxo_scanner_task.rs b/base_layer/wallet/src/utxo_scanner_service/utxo_scanner_task.rs index 38db666018..606cc25f82 100644 --- a/base_layer/wallet/src/utxo_scanner_service/utxo_scanner_task.rs +++ b/base_layer/wallet/src/utxo_scanner_service/utxo_scanner_task.rs @@ -636,7 +636,7 @@ where for (wo, message, import_status, tx_id, to) in utxos { let source_address = if wo.features.is_coinbase() { // It's a coinbase, so we know we mined it (we do mining with cold wallets). - self.resources.wallet_identity.address.clone() + self.resources.one_sided_tari_address.clone() } else { // Because we do not know the source public key we are making it the default key of zeroes to make it // clear this value is a placeholder. diff --git a/base_layer/wallet/src/utxo_scanner_service/uxto_scanner_service_builder.rs b/base_layer/wallet/src/utxo_scanner_service/uxto_scanner_service_builder.rs index 7ee066b428..c249a38b25 100644 --- a/base_layer/wallet/src/utxo_scanner_service/uxto_scanner_service_builder.rs +++ b/base_layer/wallet/src/utxo_scanner_service/uxto_scanner_service_builder.rs @@ -20,13 +20,10 @@ // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE // USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -use std::sync::Arc; - -use tari_common::configuration::Network; use tari_common_types::tari_address::TariAddress; -use tari_comms::{connectivity::ConnectivityRequester, types::CommsPublicKey, NodeIdentity}; +use tari_comms::{connectivity::ConnectivityRequester, types::CommsPublicKey}; use tari_core::transactions::{key_manager::TransactionKeyManagerInterface, CryptoFactories}; -use tari_key_manager::key_manager_service::{KeyManagerInterface, KeyManagerServiceError}; +use tari_key_manager::key_manager_service::KeyManagerServiceError; use tari_shutdown::ShutdownSignal; use tokio::sync::{broadcast, watch}; @@ -39,7 +36,6 @@ use crate::{ sqlite_db::wallet::WalletSqliteDatabase, }, transaction_service::handle::TransactionServiceHandle, - util::wallet_identity::WalletIdentity, utxo_scanner_service::{ handle::UtxoScannerEvent, service::{UtxoScannerResources, UtxoScannerService}, @@ -108,17 +104,7 @@ impl UtxoScannerServiceBuilder { wallet: &WalletSqlite, shutdown_signal: ShutdownSignal, ) -> Result, KeyManagerServiceError> { - let view_key_id = wallet.key_manager_service.get_view_key_id().await?; - let view_key = wallet - .key_manager_service - .get_public_key_at_key_id(&view_key_id) - .await?; - let tari_address = TariAddress::new_dual_address_with_default_features( - view_key, - wallet.comms.node_identity().public_key().clone(), - wallet.network.as_network(), - ); - let wallet_identity = WalletIdentity::new(wallet.comms.node_identity(), tari_address); + let one_sided_tari_address = wallet.get_wallet_one_sided_address().await?; let resources = UtxoScannerResources { db: wallet.db.clone(), comms_connectivity: wallet.comms.connectivity(), @@ -126,7 +112,7 @@ impl UtxoScannerServiceBuilder { current_base_node_watcher: wallet.wallet_connectivity.get_current_base_node_watcher(), output_manager_service: wallet.output_manager_service.clone(), transaction_service: wallet.transaction_service.clone(), - wallet_identity, + one_sided_tari_address, factories: wallet.factories.clone(), recovery_message: self.recovery_message.clone(), one_sided_payment_message: self.one_sided_message.clone(), @@ -158,21 +144,14 @@ impl UtxoScannerServiceBuilder { wallet_connectivity: TWalletConnectivity, output_manager_service: OutputManagerHandle, transaction_service: TransactionServiceHandle, - key_manager: TKeyManagerInterface, - node_identity: Arc, - network: Network, + one_sided_tari_address: TariAddress, factories: CryptoFactories, shutdown_signal: ShutdownSignal, event_sender: broadcast::Sender, base_node_service: BaseNodeServiceHandle, one_sided_message_watch: watch::Receiver, recovery_message_watch: watch::Receiver, - ) -> Result, KeyManagerServiceError> { - let view_key_id = key_manager.get_view_key_id().await?; - let view_key = key_manager.get_public_key_at_key_id(&view_key_id).await?; - let tari_address = - TariAddress::new_dual_address_with_default_features(view_key, node_identity.public_key().clone(), network); - let wallet_identity = WalletIdentity::new(node_identity.clone(), tari_address); + ) -> UtxoScannerService { let resources = UtxoScannerResources { db, comms_connectivity, @@ -180,13 +159,13 @@ impl UtxoScannerServiceBuilder { wallet_connectivity, output_manager_service, transaction_service, - wallet_identity, + one_sided_tari_address, factories, recovery_message: self.recovery_message.clone(), one_sided_payment_message: self.one_sided_message.clone(), }; - Ok(UtxoScannerService::new( + UtxoScannerService::new( self.peers.drain(..).collect(), self.retry_limit, self.mode.clone().unwrap_or_default(), @@ -196,6 +175,6 @@ impl UtxoScannerServiceBuilder { base_node_service, one_sided_message_watch, recovery_message_watch, - )) + ) } } diff --git a/base_layer/wallet/src/wallet.rs b/base_layer/wallet/src/wallet.rs index f69fab4415..cd11fe7abd 100644 --- a/base_layer/wallet/src/wallet.rs +++ b/base_layer/wallet/src/wallet.rs @@ -29,7 +29,7 @@ use log::*; use rand::rngs::OsRng; use tari_common::configuration::bootstrap::ApplicationType; use tari_common_types::{ - tari_address::TariAddress, + tari_address::{TariAddress, TariAddressFeatures}, transaction::{ImportStatus, TxId}, types::{ComAndPubSignature, Commitment, PrivateKey, PublicKey, RangeProof, SignatureWithDomain}, wallet_types::WalletType, @@ -64,7 +64,7 @@ use tari_crypto::{hash_domain, signatures::SchnorrSignatureError}; use tari_key_manager::{ cipher_seed::CipherSeed, key_manager::KeyManager, - key_manager_service::{storage::database::KeyManagerBackend, KeyDigest, KeyManagerBranch}, + key_manager_service::{storage::database::KeyManagerBackend, KeyDigest, KeyManagerBranch, KeyManagerServiceError}, mnemonic::{Mnemonic, MnemonicLanguage}, SeedWords, }; @@ -137,6 +137,7 @@ pub struct Wallet { pub db: WalletDatabase, pub output_db: OutputManagerDatabase, pub factories: CryptoFactories, + wallet_type: WalletType, _u: PhantomData, _v: PhantomData, _w: PhantomData, @@ -201,13 +202,12 @@ where output_manager_backend.clone(), factories.clone(), config.network.into(), - node_identity.clone(), )) .add_initializer(TransactionKeyManagerInitializer::new( key_manager_backend, master_seed, factories.clone(), - wallet_type, + wallet_type.clone(), )) .add_initializer(TransactionServiceInitializer::::new( config.transaction_service_config, @@ -242,7 +242,6 @@ where .add_initializer(UtxoScannerServiceInitializer::::new( wallet_database.clone(), factories.clone(), - node_identity.clone(), config.network, )); @@ -357,6 +356,7 @@ where db: wallet_database, output_db: output_manager_database, factories, + wallet_type, _u: PhantomData, _v: PhantomData, _w: PhantomData, @@ -476,25 +476,40 @@ where } } - pub async fn get_wallet_address(&self) -> Result { - let view_key_id = self.key_manager_service.get_view_key_id().await?; - let view_key = self.key_manager_service.get_public_key_at_key_id(&view_key_id).await?; - Ok(TariAddress::new_dual_address_with_default_features( - view_key.clone(), - self.comms.node_identity().public_key().clone(), + pub async fn get_wallet_interactive_address(&self) -> Result { + let (_view_key_id, view_key) = self.key_manager_service.get_view_key().await?; + let (_comms_key_id, comms_key) = self.key_manager_service.get_comms_key().await?; + let features = match self.wallet_type { + WalletType::Software => TariAddressFeatures::default(), + WalletType::Ledger(_) | WalletType::Imported(_) => TariAddressFeatures::create_interactive_only(), + }; + Ok(TariAddress::new_dual_address( + view_key, + comms_key, self.network.as_network(), + features, )) } - pub async fn get_wallet_id(&self) -> Result { - let view_key_id = self.key_manager_service.get_view_key_id().await?; - let view_key = self.key_manager_service.get_public_key_at_key_id(&view_key_id).await?; - let address = TariAddress::new_dual_address_with_default_features( - view_key.clone(), - self.comms.node_identity().public_key().clone(), + pub async fn get_wallet_one_sided_address(&self) -> Result { + let (_view_key_id, view_key) = self.key_manager_service.get_view_key().await?; + let (_spend_key_id, spend_key) = self.key_manager_service.get_spend_key().await?; + Ok(TariAddress::new_dual_address( + view_key, + spend_key, self.network.as_network(), - ); - Ok(WalletIdentity::new(self.comms.node_identity(), address)) + TariAddressFeatures::create_one_sided_only(), + )) + } + + pub async fn get_wallet_id(&self) -> Result { + let address_interactive = self.get_wallet_interactive_address().await?; + let address_one_sided = self.get_wallet_one_sided_address().await?; + Ok(WalletIdentity::new( + self.comms.node_identity(), + address_interactive, + address_one_sided, + )) } pub fn get_software_updater(&self) -> Option { diff --git a/base_layer/wallet/tests/output_manager_service_tests/service.rs b/base_layer/wallet/tests/output_manager_service_tests/service.rs index 7bc4d4796c..f70482970e 100644 --- a/base_layer/wallet/tests/output_manager_service_tests/service.rs +++ b/base_layer/wallet/tests/output_manager_service_tests/service.rs @@ -42,7 +42,6 @@ use minotari_wallet::{ transaction_service::handle::TransactionServiceHandle, }; use rand::{rngs::OsRng, RngCore}; -use tari_common::configuration::Network; use tari_common_types::{ transaction::TxId, types::{ComAndPubSignature, FixedHash, PublicKey}, @@ -171,8 +170,6 @@ async fn setup_output_manager_service( shutdown.to_signal(), basenode_service_handle, wallet_connectivity_mock.clone(), - server_node_identity.clone(), - Network::LocalNet, key_manager.clone(), ) .await @@ -197,7 +194,6 @@ async fn setup_output_manager_service( pub async fn setup_oms_with_bn_state( backend: T, height: Option, - node_identity: Arc, ) -> ( OutputManagerHandle, Shutdown, @@ -237,8 +233,6 @@ pub async fn setup_oms_with_bn_state( shutdown.to_signal(), base_node_service_handle.clone(), connectivity, - node_identity.clone(), - Network::LocalNet, key_manager.clone(), ) .await @@ -388,12 +382,10 @@ async fn fee_estimate() { #[tokio::test] async fn test_utxo_selection_no_chain_metadata() { let (connection, _tempdir) = get_temp_sqlite_database_connection(); - let server_node_identity = build_node_identity(PeerFeatures::COMMUNICATION_NODE); let backend = OutputManagerSqliteDatabase::new(connection.clone()); // no chain metadata - let (mut oms, _shutdown, _, _, _, key_manager) = - setup_oms_with_bn_state(backend.clone(), None, server_node_identity).await; + let (mut oms, _shutdown, _, _, _, key_manager) = setup_oms_with_bn_state(backend.clone(), None).await; let fee_calc = Fee::new(*create_consensus_constants(0).transaction_weight_params()); // no utxos - not enough funds @@ -521,11 +513,9 @@ async fn test_utxo_selection_no_chain_metadata() { async fn test_utxo_selection_with_chain_metadata() { let (connection, _tempdir) = get_temp_sqlite_database_connection(); - let server_node_identity = build_node_identity(PeerFeatures::COMMUNICATION_NODE); // setup with chain metadata at a height of 6 let backend = OutputManagerSqliteDatabase::new(connection); - let (mut oms, _shutdown, _, _, _, key_manager) = - setup_oms_with_bn_state(backend.clone(), Some(6), server_node_identity).await; + let (mut oms, _shutdown, _, _, _, key_manager) = setup_oms_with_bn_state(backend.clone(), Some(6)).await; let fee_calc = Fee::new(*create_consensus_constants(0).transaction_weight_params()); // no utxos - not enough funds @@ -673,12 +663,9 @@ async fn test_utxo_selection_with_chain_metadata() { async fn test_utxo_selection_with_tx_priority() { let (connection, _tempdir) = get_temp_sqlite_database_connection(); - let server_node_identity = build_node_identity(PeerFeatures::COMMUNICATION_NODE); - // setup with chain metadata at a height of 6 let backend = OutputManagerSqliteDatabase::new(connection); - let (mut oms, _shutdown, _, _, _, key_manager) = - setup_oms_with_bn_state(backend.clone(), Some(6), server_node_identity).await; + let (mut oms, _shutdown, _, _, _, key_manager) = setup_oms_with_bn_state(backend.clone(), Some(6)).await; let amount = MicroMinotari::from(2000); let fee_per_gram = MicroMinotari::from(2); diff --git a/base_layer/wallet/tests/transaction_service_tests/service.rs b/base_layer/wallet/tests/transaction_service_tests/service.rs index ed55d1720b..fc6cca5e24 100644 --- a/base_layer/wallet/tests/transaction_service_tests/service.rs +++ b/base_layer/wallet/tests/transaction_service_tests/service.rs @@ -71,7 +71,6 @@ use minotari_wallet::{ }, transaction_service::{ config::TransactionServiceConfig, - error::TransactionServiceError, handle::{TransactionEvent, TransactionSendStatus, TransactionServiceHandle}, service::TransactionService, storage::{ @@ -90,7 +89,7 @@ use tari_common_types::{ tari_address::TariAddress, transaction::{ImportStatus, TransactionDirection, TransactionStatus, TxId}, types::{FixedHash, PrivateKey, PublicKey, Signature}, - wallet_types::WalletType, + wallet_types::{ImportedWallet, WalletType}, }; use tari_comms::{ message::EnvelopeBody, @@ -228,7 +227,11 @@ async fn setup_transaction_service>( let key_ga = Key::from_slice(&key); let db_cipher = XChaCha20Poly1305::new(key_ga); let kms_backend = KeyManagerSqliteDatabase::init(connection, db_cipher); - + let wallet_type = WalletType::Imported(ImportedWallet { + public_spend_key: PublicKey::from_secret_key(node_identity.secret_key()), + private_spend_key: Some(node_identity.secret_key().clone()), + view_key: SK::random(&mut OsRng), + }); let handles = StackBuilder::new(shutdown_signal) .add_initializer(RegisterHandle::new(dht)) .add_initializer(RegisterHandle::new(comms.connectivity())) @@ -240,13 +243,12 @@ async fn setup_transaction_service>( oms_backend.clone(), factories.clone(), Network::LocalNet.into(), - node_identity.clone(), )) .add_initializer(TransactionKeyManagerInitializer::>::new( kms_backend, cipher, factories.clone(), - WalletType::default(), + wallet_type, )) .add_initializer(TransactionServiceInitializer::<_, _, MemoryDbKeyManager>::new( TransactionServiceConfig { @@ -393,8 +395,6 @@ async fn setup_transaction_service_no_comms( shutdown.to_signal(), base_node_service_handle.clone(), wallet_connectivity_service_mock.clone(), - node_identity.clone(), - Network::LocalNet, key_manager.clone(), ) .await @@ -1765,11 +1765,7 @@ async fn recover_one_sided_transaction() { let message = "".to_string(); let value = 10000.into(); let mut alice_ts_clone = alice_ts.clone(); - let bob_view_key_id = bob_key_manager_handle.get_view_key_id().await.unwrap(); - let bob_view_key = bob_key_manager_handle - .get_public_key_at_key_id(&bob_view_key_id) - .await - .unwrap(); + let bob_view_key = bob_key_manager_handle.get_view_key().await.unwrap().1; let bob_address = TariAddress::new_dual_address_with_default_features( bob_view_key, bob_node_identity.public_key().clone(), @@ -1874,11 +1870,7 @@ async fn recover_stealth_one_sided_transaction() { ) .await; - let bob_view_key_id = bob_key_manager_handle.get_view_key_id().await.unwrap(); - let bob_view_key = bob_key_manager_handle - .get_public_key_at_key_id(&bob_view_key_id) - .await - .unwrap(); + let bob_view_key = bob_key_manager_handle.get_view_key().await.unwrap().1; let initial_wallet_value = 25000.into(); let uo1 = make_input( @@ -2008,12 +2000,7 @@ async fn test_htlc_send_and_claim() { let message = "".to_string(); let value = 10000.into(); let bob_pubkey = bob_ts_interface.base_node_identity.public_key().clone(); - let bob_view_key_id = bob_ts_interface.key_manager_handle.get_view_key_id().await.unwrap(); - let bob_view_key = bob_ts_interface - .key_manager_handle - .get_public_key_at_key_id(&bob_view_key_id) - .await - .unwrap(); + let bob_view_key = bob_ts_interface.key_manager_handle.get_view_key().await.unwrap().1; let bob_address = TariAddress::new_dual_address_with_default_features(bob_view_key, bob_pubkey.clone(), network); let (tx_id, pre_image, output) = alice_ts .send_sha_atomic_swap_transaction( @@ -2078,89 +2065,6 @@ async fn test_htlc_send_and_claim() { ); } -#[tokio::test] -async fn send_one_sided_transaction_to_self() { - let network = Network::LocalNet; - let consensus_manager = ConsensusManager::builder(network).build().unwrap(); - let factories = CryptoFactories::default(); - // Alice's parameters - let alice_node_identity = Arc::new(NodeIdentity::random( - &mut OsRng, - get_next_memory_address(), - PeerFeatures::COMMUNICATION_NODE, - )); - - let base_node_identity = Arc::new(NodeIdentity::random( - &mut OsRng, - get_next_memory_address(), - PeerFeatures::COMMUNICATION_NODE, - )); - - log::info!( - "manage_single_transaction: Alice: '{}', Base: '{}'", - alice_node_identity.node_id().short_str(), - base_node_identity.node_id().short_str() - ); - - let temp_dir = tempdir().unwrap(); - let database_path = temp_dir.path().to_str().unwrap().to_string(); - - let alice_connection = make_wallet_database_memory_connection(); - - let shutdown = Shutdown::new(); - let (alice_ts, alice_oms, _alice_comms, _alice_connectivity, key_manager_handle, alice_db) = - setup_transaction_service( - alice_node_identity.clone(), - vec![], - consensus_manager, - factories.clone(), - alice_connection, - database_path, - Duration::from_secs(0), - shutdown.to_signal(), - ) - .await; - - let initial_wallet_value = 2500.into(); - let uo1 = make_input( - &mut OsRng, - initial_wallet_value, - &OutputFeatures::default(), - &key_manager_handle, - ) - .await; - let mut alice_oms_clone = alice_oms; - alice_oms_clone.add_output(uo1.clone(), None).await.unwrap(); - alice_db - .mark_outputs_as_unspent(vec![(uo1.hash(&key_manager_handle).await.unwrap(), true)]) - .unwrap(); - - let message = "SEE IF YOU CAN CATCH THIS ONE..... SIDED TX!".to_string(); - let value = 1000.into(); - let mut alice_ts_clone = alice_ts; - let alice_address = - TariAddress::new_single_address_with_interactive_only(alice_node_identity.public_key().clone(), network); - match alice_ts_clone - .send_one_sided_transaction( - alice_address, - value, - UtxoSelectionCriteria::default(), - OutputFeatures::default(), - 20.into(), - message.clone(), - PaymentId::Empty, - ) - .await - { - Err(TransactionServiceError::OneSidedTransactionError(e)) => { - assert_eq!(e.as_str(), "One-sided spend-to-self transactions not supported"); - }, - _ => { - panic!("Expected: OneSidedTransactionError(\"One-sided spend-to-self transactions not supported\")"); - }, - }; -} - #[tokio::test(flavor = "multi_thread", worker_threads = 3)] async fn manage_multiple_transactions() { let network = Network::LocalNet; @@ -4318,12 +4222,7 @@ async fn test_restarting_transaction_protocols() { }; let tx = bob_stp.get_transaction().unwrap().clone(); - let bob_view_key_id = bob_ts_interface.key_manager_handle.get_view_key_id().await.unwrap(); - let bob_view_key = bob_ts_interface - .key_manager_handle - .get_public_key_at_key_id(&bob_view_key_id) - .await - .unwrap(); + let bob_view_key = bob_ts_interface.key_manager_handle.get_view_key().await.unwrap().1; let bob_address = TariAddress::new_dual_address_with_default_features(bob_view_key, bob_identity.public_key().clone(), network); let inbound_tx = InboundTransaction { @@ -4346,12 +4245,7 @@ async fn test_restarting_transaction_protocols() { Box::new(inbound_tx), ))) .unwrap(); - let alice_view_key_id = alice_ts_interface.key_manager_handle.get_view_key_id().await.unwrap(); - let alice_view_key = alice_ts_interface - .key_manager_handle - .get_public_key_at_key_id(&alice_view_key_id) - .await - .unwrap(); + let alice_view_key = alice_ts_interface.key_manager_handle.get_view_key().await.unwrap().1; let alice_address = TariAddress::new_dual_address_with_default_features( alice_view_key, alice_identity.public_key().clone(), diff --git a/base_layer/wallet/tests/transaction_service_tests/transaction_protocols.rs b/base_layer/wallet/tests/transaction_service_tests/transaction_protocols.rs index c9332e9a8e..99d784f5c7 100644 --- a/base_layer/wallet/tests/transaction_service_tests/transaction_protocols.rs +++ b/base_layer/wallet/tests/transaction_service_tests/transaction_protocols.rs @@ -47,7 +47,7 @@ use minotari_wallet::{ sqlite_db::TransactionServiceSqliteDatabase, }, }, - util::{wallet_identity::WalletIdentity, watch::Watch}, + util::watch::Watch, }; use rand::{rngs::OsRng, RngCore}; use tari_common::configuration::Network; @@ -86,7 +86,6 @@ use tari_core::{ }, txn_schema, }; -use tari_key_manager::key_manager_service::KeyManagerInterface; use tari_service_framework::{reply_channel, reply_channel::Receiver}; use tari_shutdown::Shutdown; use tari_test_utils::random; @@ -159,17 +158,12 @@ pub async fn setup() -> ( let shutdown = Shutdown::new(); let network = Network::LocalNet; let consensus_manager = ConsensusManager::builder(network).build().unwrap(); - let view_key = core_key_manager_service_handle.get_view_key_id().await.unwrap(); - let view_key = core_key_manager_service_handle - .get_public_key_at_key_id(&view_key) - .await - .unwrap(); + let view_key = core_key_manager_service_handle.get_view_key().await.unwrap().1; let tari_address = TariAddress::new_dual_address_with_default_features( view_key, client_node_identity.public_key().clone(), network, ); - let wallet_identity = WalletIdentity::new(client_node_identity.clone(), tari_address); let resources = TransactionServiceResources { db, output_manager_service: output_manager_service_handle, @@ -177,7 +171,8 @@ pub async fn setup() -> ( outbound_message_service: outbound_message_requester, connectivity: wallet_connectivity.clone(), event_publisher: ts_event_publisher, - wallet_identity, + tari_address, + node_identity: client_node_identity.clone(), consensus_manager, factories: CryptoFactories::default(), config: TransactionServiceConfig { diff --git a/base_layer/wallet/tests/utxo_scanner/mod.rs b/base_layer/wallet/tests/utxo_scanner/mod.rs index a8aff63a25..14428fbbe5 100644 --- a/base_layer/wallet/tests/utxo_scanner/mod.rs +++ b/base_layer/wallet/tests/utxo_scanner/mod.rs @@ -61,7 +61,7 @@ use tari_core::{ blocks::BlockHeader, proto::base_node::{ChainMetadata, TipInfoResponse}, transactions::{ - key_manager::{create_memory_db_key_manager, MemoryDbKeyManager}, + key_manager::{create_memory_db_key_manager, MemoryDbKeyManager, TransactionKeyManagerInterface}, tari_amount::MicroMinotari, transaction_components::{OutputFeatures, WalletOutput}, CryptoFactories, @@ -193,16 +193,20 @@ async fn setup( scanner_service_builder.with_recovery_message(message); } + let (_view_key_id, view_key) = key_manager.get_view_key().await.unwrap(); + let tari_address = TariAddress::new_dual_address_with_default_features( + view_key, + node_identity.public_key().clone(), + Network::default(), + ); let scanner_service = scanner_service_builder - .build_with_resources( + .build_with_resources::( wallet_db.clone(), comms_connectivity, wallet_connectivity_mock, oms_handle, ts_handle, - key_manager, - node_identity.clone(), - Network::default(), + tari_address, factories, shutdown.to_signal(), event_sender, @@ -210,8 +214,7 @@ async fn setup( one_sided_message_watch_receiver, recovery_message_watch_receiver, ) - .await - .unwrap(); + .await; UtxoScannerTestInterface { scanner_service: Some(scanner_service), diff --git a/base_layer/wallet_ffi/src/error.rs b/base_layer/wallet_ffi/src/error.rs index 93f91a431e..4855faa85d 100644 --- a/base_layer/wallet_ffi/src/error.rs +++ b/base_layer/wallet_ffi/src/error.rs @@ -33,7 +33,10 @@ use tari_crypto::{ signatures::SchnorrSignatureError, tari_utilities::{hex::HexError, ByteArrayError}, }; -use tari_key_manager::error::{KeyManagerError, MnemonicError}; +use tari_key_manager::{ + error::{KeyManagerError, MnemonicError}, + key_manager_service::KeyManagerServiceError, +}; use thiserror::Error; const LOG_TARGET: &str = "wallet_ffi::error"; @@ -526,3 +529,13 @@ impl From for LibWalletError { } } } + +impl From for LibWalletError { + fn from(err: KeyManagerServiceError) -> Self { + error!(target: LOG_TARGET, "{}", format!("{:?}", err)); + Self { + code: 458, + message: format!("{:?}", err), + } + } +} diff --git a/base_layer/wallet_ffi/src/lib.rs b/base_layer/wallet_ffi/src/lib.rs index fe7fef795a..992ecafd4c 100644 --- a/base_layer/wallet_ffi/src/lib.rs +++ b/base_layer/wallet_ffi/src/lib.rs @@ -5945,7 +5945,7 @@ pub unsafe extern "C" fn wallet_create( match w { Ok(w) => { - let wallet_address = match runtime.block_on(async { w.get_wallet_address().await }) { + let wallet_address = match runtime.block_on(async { w.get_wallet_interactive_address().await }) { Ok(address) => address, Err(e) => { error = LibWalletError::from(e).code; @@ -7652,7 +7652,7 @@ pub unsafe extern "C" fn wallet_get_cancelled_transactions( return ptr::null_mut(); }, }; - let wallet_address = match runtime.block_on(async { (*wallet).wallet.get_wallet_address().await }) { + let wallet_address = match runtime.block_on(async { (*wallet).wallet.get_wallet_interactive_address().await }) { Ok(address) => address, Err(e) => { error = LibWalletError::from(e).code; @@ -7946,7 +7946,7 @@ pub unsafe extern "C" fn wallet_get_cancelled_transaction_by_id( return ptr::null_mut(); }, }; - let address = match runtime.block_on(async { (*wallet).wallet.get_wallet_address().await }) { + let address = match runtime.block_on(async { (*wallet).wallet.get_wallet_interactive_address().await }) { Ok(address) => address, Err(e) => { error = LibWalletError::from(e).code; @@ -8029,7 +8029,7 @@ pub unsafe extern "C" fn wallet_get_tari_address( return ptr::null_mut(); }, }; - let address = match runtime.block_on(async { (*wallet).wallet.get_wallet_address().await }) { + let address = match runtime.block_on(async { (*wallet).wallet.get_wallet_interactive_address().await }) { Ok(address) => address, Err(e) => { error = LibWalletError::from(e).code;