From f42a83882c8a824bf72c800c1018b4167c1a7d8c Mon Sep 17 00:00:00 2001 From: SW van Heerden Date: Tue, 25 Jun 2024 08:32:47 +0200 Subject: [PATCH] feat!: change tar address to use base58 and not hex (#6372) Description --- Remove hex display from tari address Use Base 58 encoding instead. Keeps the network and features human readable Motivation and Context --- reduces the display size from 134 chars, down to 92 How Has This Been Tested? --- unit tests and manual --- Cargo.lock | 12 +- .../minotari_app_utilities/src/utilities.rs | 2 +- .../src/grpc/wallet_grpc_server.rs | 4 +- .../src/notifier/mod.rs | 8 +- .../src/ui/state/app_state.rs | 41 ++-- .../src/ui/ui_contact.rs | 2 +- .../src/wallet_modes.rs | 4 +- .../minotari_merge_mining_proxy/src/config.rs | 2 +- applications/minotari_miner/src/config.rs | 2 +- .../src/grpc/base_node_grpc_server.rs | 4 +- .../chat_ffi/src/contacts_liveness_data.rs | 6 +- base_layer/chat_ffi/src/message.rs | 12 +- base_layer/common_types/Cargo.toml | 2 +- .../src/tari_address/dual_address.rs | 85 +++++++- .../common_types/src/tari_address/mod.rs | 186 +++++++++++++----- .../src/tari_address/single_address.rs | 79 +++++++- .../transaction_components/encrypted_data.rs | 26 ++- base_layer/wallet_ffi/src/error.rs | 4 +- base_layer/wallet_ffi/src/lib.rs | 6 +- base_layer/wallet_ffi/wallet.h | 4 +- integration_tests/src/ffi/callbacks.rs | 4 +- integration_tests/src/ffi/contact.rs | 2 +- integration_tests/src/ffi/ffi_import.rs | 2 +- integration_tests/src/ffi/wallet.rs | 12 +- integration_tests/src/ffi/wallet_address.rs | 4 +- integration_tests/src/merge_mining_proxy.rs | 2 +- integration_tests/src/miner.rs | 2 +- integration_tests/src/wallet_ffi.rs | 4 +- integration_tests/src/world.rs | 12 +- .../tests/steps/chat_ffi_steps.rs | 2 +- integration_tests/tests/steps/node_steps.rs | 32 +-- .../tests/steps/wallet_cli_steps.rs | 4 +- .../tests/steps/wallet_ffi_steps.rs | 4 +- 33 files changed, 421 insertions(+), 156 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5747d4ec64..4aa740ff81 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -506,6 +506,15 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "771fe0050b883fcc3ea2359b1a96bcfbc090b7116eae7c3c512c7a083fdf23d3" +[[package]] +name = "bs58" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf88ba1141d185c399bee5288d850d63b8369520c1eafc32a0430b5b6c287bf4" +dependencies = [ + "tinyvec", +] + [[package]] name = "bstr" version = "1.7.0" @@ -3649,7 +3658,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c580bfdd8803cce319b047d239559a22f809094aaea4ac13902a1fdcfcd4261" dependencies = [ "arrayref", - "bs58", + "bs58 0.4.0", "byteorder", "data-encoding", "multihash", @@ -5980,6 +5989,7 @@ dependencies = [ "bitflags 2.4.1", "blake2", "borsh", + "bs58 0.5.1", "chacha20poly1305", "digest 0.10.7", "ledger-transport 0.10.0 (git+https://github.com/Zondax/ledger-rs?rev=20e2a20)", diff --git a/applications/minotari_app_utilities/src/utilities.rs b/applications/minotari_app_utilities/src/utilities.rs index 0142b8c93c..e1e708bb25 100644 --- a/applications/minotari_app_utilities/src/utilities.rs +++ b/applications/minotari_app_utilities/src/utilities.rs @@ -120,7 +120,7 @@ impl FromStr for UniNodeId { Ok(Self::PublicKey(public_key)) } else if let Ok(node_id) = NodeId::from_hex(key) { Ok(Self::NodeId(node_id)) - } else if let Ok(tari_address) = TariAddress::from_hex(key) { + } else if let Ok(tari_address) = TariAddress::from_base58(key) { Ok(Self::TariAddress(tari_address)) } else { Err(UniIdError::UnknownIdType) 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 122be85828..6870f5c62e 100644 --- a/applications/minotari_console_wallet/src/grpc/wallet_grpc_server.rs +++ b/applications/minotari_console_wallet/src/grpc/wallet_grpc_server.rs @@ -335,7 +335,7 @@ impl wallet_server::Wallet for WalletGrpcServer { .into_inner() .recipient .ok_or_else(|| Status::internal("Request is malformed".to_string()))?; - let address = TariAddress::from_hex(&message.address) + let address = TariAddress::from_base58(&message.address) .map_err(|_| Status::internal("Destination address is malformed".to_string()))?; let mut transaction_service = self.get_transaction_service(); @@ -496,7 +496,7 @@ impl wallet_server::Wallet for WalletGrpcServer { .into_iter() .enumerate() .map(|(idx, dest)| -> Result<_, String> { - let address = TariAddress::from_hex(&dest.address) + let address = TariAddress::from_base58(&dest.address) .map_err(|_| format!("Destination address at index {} is malformed", idx))?; Ok(( dest.address, diff --git a/applications/minotari_console_wallet/src/notifier/mod.rs b/applications/minotari_console_wallet/src/notifier/mod.rs index 5f160970f0..a185efe1fe 100644 --- a/applications/minotari_console_wallet/src/notifier/mod.rs +++ b/applications/minotari_console_wallet/src/notifier/mod.rs @@ -310,8 +310,8 @@ fn args_from_complete(tx: &CompletedTransaction, event: &str, confirmations: Opt amount, tx.tx_id.to_string(), tx.message.clone(), - tx.source_address.to_hex(), - tx.destination_address.to_hex(), + tx.source_address.to_base58(), + tx.destination_address.to_base58(), status, excess, public_nonce, @@ -331,7 +331,7 @@ fn args_from_outbound(tx: &OutboundTransaction, event: &str) -> Vec { amount, tx.tx_id.to_string(), tx.message.clone(), - tx.destination_address.to_hex(), + tx.destination_address.to_base58(), status, "outbound".to_string(), ] @@ -347,7 +347,7 @@ fn args_from_inbound(tx: &InboundTransaction, event: &str) -> Vec { amount, tx.tx_id.to_string(), tx.message.clone(), - tx.source_address.to_hex(), + tx.source_address.to_base58(), status, "inbound".to_string(), ] 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 6dc75ca185..e38a810d91 100644 --- a/applications/minotari_console_wallet/src/ui/state/app_state.rs +++ b/applications/minotari_console_wallet/src/ui/state/app_state.rs @@ -23,6 +23,7 @@ use std::{ collections::{HashMap, VecDeque}, path::PathBuf, + str::FromStr, sync::Arc, time::{Duration, Instant}, }; @@ -61,7 +62,7 @@ use tari_core::transactions::{ weight::TransactionWeight, }; use tari_shutdown::ShutdownSignal; -use tari_utilities::hex::{from_hex, Hex}; +use tari_utilities::hex::Hex; use tokio::{ sync::{broadcast, watch, RwLock}, task, @@ -229,11 +230,7 @@ impl AppState { pub async fn upsert_contact(&mut self, alias: String, tari_emoji: String) -> Result<(), UiError> { let mut inner = self.inner.write().await; - let address = match TariAddress::from_emoji_string(&tari_emoji) { - Ok(address) => address, - Err(_) => TariAddress::from_bytes(&from_hex(&tari_emoji).map_err(|_| UiError::PublicKeyParseError)?) - .map_err(|_| UiError::PublicKeyParseError)?, - }; + let address = TariAddress::from_str(&tari_emoji).map_err(|_| UiError::PublicKeyParseError)?; let contact = Contact::new(alias, address, None, None, false); inner.wallet.contacts_service.upsert_contact(contact).await?; @@ -246,26 +243,22 @@ impl AppState { // Return alias or pub key if the contact is not in the list. pub fn get_alias(&self, address: &TariAddress) -> String { - let address_hex = address.to_hex(); + let address_string = address.to_base58(); match self .cached_data .contacts .iter() - .find(|&contact| contact.address.eq(&address_hex)) + .find(|&contact| contact.address.eq(&address_string)) { Some(contact) => contact.alias.clone(), - None => address_hex, + None => address_string, } } pub async fn delete_contact(&mut self, tari_emoji: String) -> Result<(), UiError> { let mut inner = self.inner.write().await; - let address = match TariAddress::from_emoji_string(&tari_emoji) { - Ok(address) => address, - Err(_) => TariAddress::from_bytes(&from_hex(&tari_emoji).map_err(|_| UiError::PublicKeyParseError)?) - .map_err(|_| UiError::PublicKeyParseError)?, - }; + let address = TariAddress::from_str(&tari_emoji).map_err(|_| UiError::PublicKeyParseError)?; inner.wallet.contacts_service.remove_contact(address).await?; @@ -301,11 +294,7 @@ impl AppState { result_tx: watch::Sender, ) -> Result<(), UiError> { let inner = self.inner.write().await; - let address = match TariAddress::from_emoji_string(&address) { - Ok(address) => address, - Err(_) => TariAddress::from_bytes(&from_hex(&address).map_err(|_| UiError::PublicKeyParseError)?) - .map_err(|_| UiError::PublicKeyParseError)?, - }; + let address = TariAddress::from_str(&address).map_err(|_| UiError::PublicKeyParseError)?; let output_features = OutputFeatures { ..Default::default() }; @@ -336,11 +325,7 @@ impl AppState { result_tx: watch::Sender, ) -> Result<(), UiError> { let inner = self.inner.write().await; - let address = match TariAddress::from_emoji_string(&address) { - Ok(address) => address, - Err(_) => TariAddress::from_bytes(&from_hex(&address).map_err(|_| UiError::PublicKeyParseError)?) - .map_err(|_| UiError::PublicKeyParseError)?, - }; + let address = TariAddress::from_str(&address).map_err(|_| UiError::PublicKeyParseError)?; let payment_id_u64: u64 = payment_id_hex .parse::() .map_err(|_| UiError::HexError("Could not convert payment_id to bytes".to_string()))?; @@ -912,7 +897,7 @@ impl AppStateInner { let qr_link = format!( "tari://{}/transactions/send?tariAddress={}", wallet_id.network(), - wallet_id.address.to_hex() + wallet_id.address.to_base58() ); let code = QrCode::new(qr_link).unwrap(); let image = code @@ -924,7 +909,7 @@ impl AppStateInner { .skip(1) .fold("".to_string(), |acc, l| format!("{}{}\n", acc, l)); let identity = MyIdentity { - tari_address: wallet_id.address.to_hex(), + tari_address: wallet_id.address.to_base58(), network_address: wallet_id .node_identity .public_addresses() @@ -1249,7 +1234,7 @@ impl AppStateData { let qr_link = format!( "tari://{}/transactions/send?tariAddress={}", wallet_identity.network(), - wallet_identity.address.to_hex() + wallet_identity.address.to_base58() ); let code = QrCode::new(qr_link).unwrap(); let image = code @@ -1262,7 +1247,7 @@ impl AppStateData { .fold("".to_string(), |acc, l| format!("{}{}\n", acc, l)); let identity = MyIdentity { - tari_address: wallet_identity.address.to_hex(), + tari_address: wallet_identity.address.to_base58(), network_address: wallet_identity .node_identity .public_addresses() diff --git a/applications/minotari_console_wallet/src/ui/ui_contact.rs b/applications/minotari_console_wallet/src/ui/ui_contact.rs index 9851816f8b..86d8b18b90 100644 --- a/applications/minotari_console_wallet/src/ui/ui_contact.rs +++ b/applications/minotari_console_wallet/src/ui/ui_contact.rs @@ -44,7 +44,7 @@ impl From for UiContact { fn from(c: Contact) -> Self { Self { alias: c.alias, - address: c.address.to_hex(), + address: c.address.to_base58(), emoji_id: c.address.to_emoji_string(), last_seen: match c.last_seen { Some(val) => DateTime::::from_naive_utc_and_offset(val, Local::now().offset().to_owned()) diff --git a/applications/minotari_console_wallet/src/wallet_modes.rs b/applications/minotari_console_wallet/src/wallet_modes.rs index 391796800d..91ad2c3086 100644 --- a/applications/minotari_console_wallet/src/wallet_modes.rs +++ b/applications/minotari_console_wallet/src/wallet_modes.rs @@ -491,7 +491,7 @@ mod test { discover-peer f6b2ca781342a3ebe30ee1643655c96f1d7c14f4d49f077695395de98ae73665 send-minotari --message Our_secret! 125T \ - 2603fed9cf87097105913096da423ae4e3096e44a172185742ce5bc00d27016cd81118 + f425UWsDp714RiN53c1G6ek57rfFnotB5NCMyrn4iDgbR8i2sXVHa4xSsedd66o9KmkRgErQnyDdCaAdNLzcKrj7eUb burn-minotari --message Ups_these_funds_will_be_burned! 100T @@ -499,7 +499,7 @@ mod test { make-it-rain --duration 100 --transactions-per-second 10 --start-amount 0.009200T --increase-amount 0T \ --start-time now --message Stressing_it_a_bit...!_(from_Feeling-a-bit-Generous) \ - 2603fed9cf87097105913096da423ae4e3096e44a172185742ce5bc00d27016cd81118 + f425UWsDp714RiN53c1G6ek57rfFnotB5NCMyrn4iDgbR8i2sXVHa4xSsedd66o9KmkRgErQnyDdCaAdNLzcKrj7eUb export-tx 123456789 --output-file pie.txt diff --git a/applications/minotari_merge_mining_proxy/src/config.rs b/applications/minotari_merge_mining_proxy/src/config.rs index 0f8db4b9a4..19502350c5 100644 --- a/applications/minotari_merge_mining_proxy/src/config.rs +++ b/applications/minotari_merge_mining_proxy/src/config.rs @@ -118,7 +118,7 @@ impl Default for MergeMiningProxyConfig { coinbase_extra: "tari_merge_mining_proxy".to_string(), network: Default::default(), config_dir: PathBuf::from("config/merge_mining_proxy"), - wallet_payment_address: TariAddress::default().to_hex(), + wallet_payment_address: TariAddress::default().to_base58(), stealth_payment: true, range_proof_type: RangeProofType::RevealedValue, } diff --git a/applications/minotari_miner/src/config.rs b/applications/minotari_miner/src/config.rs index 2c0412ae63..c125632d92 100644 --- a/applications/minotari_miner/src/config.rs +++ b/applications/minotari_miner/src/config.rs @@ -123,7 +123,7 @@ impl Default for MinerConfig { network: Default::default(), wait_timeout_on_error: 10, config_dir: PathBuf::from("config/miner"), - wallet_payment_address: TariAddress::default().to_hex(), + wallet_payment_address: TariAddress::default().to_base58(), stealth_payment: true, range_proof_type: RangeProofType::RevealedValue, } diff --git a/applications/minotari_node/src/grpc/base_node_grpc_server.rs b/applications/minotari_node/src/grpc/base_node_grpc_server.rs index 8426941889..74484f5652 100644 --- a/applications/minotari_node/src/grpc/base_node_grpc_server.rs +++ b/applications/minotari_node/src/grpc/base_node_grpc_server.rs @@ -838,7 +838,7 @@ impl tari_rpc::base_node_server::BaseNode for BaseNodeGrpcServer { let mut kernel_message = [0; 32]; let mut last_kernel = Default::default(); for coinbase in coinbases { - let address = TariAddress::from_hex(&coinbase.address) + let address = TariAddress::from_base58(&coinbase.address) .map_err(|e| obscure_error_if_true(report_error_flag, Status::internal(e.to_string())))?; let range_proof_type = if coinbase.revealed_value_proof { RangeProofType::RevealedValue @@ -1033,7 +1033,7 @@ impl tari_rpc::base_node_server::BaseNode for BaseNodeGrpcServer { let mut kernel_message = [0; 32]; let mut last_kernel = Default::default(); for coinbase in coinbases { - let address = TariAddress::from_hex(&coinbase.address) + let address = TariAddress::from_base58(&coinbase.address) .map_err(|e| obscure_error_if_true(report_error_flag, Status::internal(e.to_string())))?; let range_proof_type = if coinbase.revealed_value_proof { RangeProofType::RevealedValue diff --git a/base_layer/chat_ffi/src/contacts_liveness_data.rs b/base_layer/chat_ffi/src/contacts_liveness_data.rs index 18e0c55397..85b0be7093 100644 --- a/base_layer/chat_ffi/src/contacts_liveness_data.rs +++ b/base_layer/chat_ffi/src/contacts_liveness_data.rs @@ -156,8 +156,10 @@ mod test { #[test] fn test_reading_address() { - let address = - TariAddress::from_hex("2603fed9cf87097105913096da423ae4e3096e44a172185742ce5bc00d27016cd81118").unwrap(); + let address = TariAddress::from_base58( + "f425UWsDp714RiN53c1G6ek57rfFnotB5NCMyrn4iDgbR8i2sXVHa4xSsedd66o9KmkRgErQnyDdCaAdNLzcKrj7eUb", + ) + .unwrap(); let liveness = ContactsLivenessData::new( address.clone(), Default::default(), diff --git a/base_layer/chat_ffi/src/message.rs b/base_layer/chat_ffi/src/message.rs index a8bb1993e3..ea1ee64289 100644 --- a/base_layer/chat_ffi/src/message.rs +++ b/base_layer/chat_ffi/src/message.rs @@ -599,10 +599,14 @@ mod test { #[test] fn test_reading_message_address() { - let receiver_address = - TariAddress::from_hex("2602742c39084e62565e1416f9f97ff34bd91fc3ccd35bb7e6cf916cb757066c816966").unwrap(); - let sender_address = - TariAddress::from_hex("2602764460f2fff434446cab6e03a5ea2a4c1dc4984c1749a4af8371ceecd8da1d0c01").unwrap(); + let receiver_address = TariAddress::from_base58( + "f425UWsDp714RiN53c1G6ek57rfFnotB5NCMyrn4iDgbR8i2sXVHa4xSsedd66o9KmkRgErQnyDdCaAdNLzcKrj7eUb", + ) + .unwrap(); + let sender_address = TariAddress::from_base58( + "f425UWsDp714RiN53c1G6ek57rfFnotB5NCMyrn4iDgbR8i2sXVHa4xSsedd66o9KmkRgErQnyDdCaAdNLzcKrj7eUb", + ) + .unwrap(); let message = MessageBuilder::new() .receiver_address(receiver_address.clone()) .sender_address(sender_address.clone()) diff --git a/base_layer/common_types/Cargo.toml b/base_layer/common_types/Cargo.toml index 72762553ef..fb1a09d711 100644 --- a/base_layer/common_types/Cargo.toml +++ b/base_layer/common_types/Cargo.toml @@ -11,10 +11,10 @@ minotari_ledger_wallet_comms = { path = "../../applications/minotari_ledger_wall tari_crypto = { version = "0.20.1" } tari_utilities = { version = "0.7" } tari_common = { path = "../../common", version = "1.0.0-pre.14" } - chacha20poly1305 = "0.10.1" bitflags = { version = "2.4", features = ["serde"] } borsh = "1.2" +bs58 = "0.5.1" digest = "0.10" newtype-ops = "0.1" once_cell = "1.8.0" diff --git a/base_layer/common_types/src/tari_address/dual_address.rs b/base_layer/common_types/src/tari_address/dual_address.rs index 9b6ac9602b..db591aebbf 100644 --- a/base_layer/common_types/src/tari_address/dual_address.rs +++ b/base_layer/common_types/src/tari_address/dual_address.rs @@ -156,17 +156,50 @@ impl DualAddress { buf } - /// Construct Tari Address from hex - pub fn from_hex(hex_str: &str) -> Result { - let buf = from_hex(hex_str).map_err(|_| TariAddressError::CannotRecoverPublicKey)?; - Self::from_bytes(buf.as_slice()) + /// Construct Tari Address from Base58 + pub fn from_base58(hex_str: &str) -> Result { + // Due to the byte length, it can be encoded as 90 or 91 + if hex_str.len() != 90 && hex_str.len() != 91 { + return Err(TariAddressError::InvalidSize); + } + let (first, rest) = hex_str.split_at(2); + let (network, features) = first.split_at(1); + let mut result = bs58::decode(network) + .into_vec() + .map_err(|_| TariAddressError::CannotRecoverNetwork)?; + let mut features = bs58::decode(features) + .into_vec() + .map_err(|_| TariAddressError::CannotRecoverFeature)?; + let mut rest = bs58::decode(rest) + .into_vec() + .map_err(|_| TariAddressError::CannotRecoverPublicKey)?; + result.append(&mut features); + result.append(&mut rest); + Self::from_bytes(result.as_slice()) + } + + /// Convert Tari Address to Base58 string + pub fn to_base58(&self) -> String { + let bytes = self.to_bytes(); + let mut network = bs58::encode(&bytes[0..1]).into_string(); + let features = bs58::encode(&bytes[1..2].to_vec()).into_string(); + let rest = bs58::encode(&bytes[2..]).into_string(); + network.push_str(&features); + network.push_str(&rest); + network } - /// Convert Tari Address to hex string + /// Convert Tari dual Address to hex pub fn to_hex(&self) -> String { let buf = self.to_bytes(); buf.to_hex() } + + /// Creates Tari dual Address from hex + pub fn from_hex(hex_str: &str) -> Result { + let buf = from_hex(hex_str).map_err(|_| TariAddressError::CannotRecoverPublicKey)?; + DualAddress::from_bytes(buf.as_slice()) + } } #[cfg(test)] @@ -275,7 +308,9 @@ mod test { let address = DualAddress::new_with_default_features(view_key.clone(), spend_key.clone(), Network::Esmeralda); let buff = address.to_bytes(); + let base58 = address.to_base58(); let hex = address.to_hex(); + let emoji = address.to_emoji_string(); let address_buff = DualAddress::from_bytes(&buff).unwrap(); assert_eq!(address_buff.public_spend_key(), address.public_spend_key()); @@ -283,12 +318,24 @@ mod test { assert_eq!(address_buff.network(), address.network()); assert_eq!(address_buff.features(), address.features()); + let address_base58 = DualAddress::from_base58(&base58).unwrap(); + assert_eq!(address_base58.public_spend_key(), address.public_spend_key()); + assert_eq!(address_base58.public_view_key(), address.public_view_key()); + assert_eq!(address_base58.network(), address.network()); + assert_eq!(address_base58.features(), address.features()); + let address_hex = DualAddress::from_hex(&hex).unwrap(); assert_eq!(address_hex.public_spend_key(), address.public_spend_key()); assert_eq!(address_hex.public_view_key(), address.public_view_key()); assert_eq!(address_hex.network(), address.network()); assert_eq!(address_hex.features(), address.features()); + let address_emoji = DualAddress::from_emoji_string(&emoji).unwrap(); + assert_eq!(address_emoji.public_spend_key(), address.public_spend_key()); + assert_eq!(address_emoji.public_view_key(), address.public_view_key()); + assert_eq!(address_emoji.network(), address.network()); + assert_eq!(address_emoji.features(), address.features()); + let view_key = PublicKey::from_secret_key(&PrivateKey::random(&mut rng)); let spend_key = PublicKey::from_secret_key(&PrivateKey::random(&mut rng)); @@ -301,7 +348,9 @@ mod test { ); let buff = address.to_bytes(); + let base58 = address.to_base58(); let hex = address.to_hex(); + let emoji = address.to_emoji_string(); let address_buff = DualAddress::from_bytes(&buff).unwrap(); assert_eq!(address_buff.public_spend_key(), address.public_spend_key()); @@ -309,12 +358,24 @@ mod test { assert_eq!(address_buff.network(), address.network()); assert_eq!(address_buff.features(), address.features()); + let address_base58 = DualAddress::from_base58(&base58).unwrap(); + assert_eq!(address_base58.public_spend_key(), address.public_spend_key()); + assert_eq!(address_base58.public_view_key(), address.public_view_key()); + assert_eq!(address_base58.network(), address.network()); + assert_eq!(address_base58.features(), address.features()); + let address_hex = DualAddress::from_hex(&hex).unwrap(); assert_eq!(address_hex.public_spend_key(), address.public_spend_key()); assert_eq!(address_hex.public_view_key(), address.public_view_key()); assert_eq!(address_hex.network(), address.network()); assert_eq!(address_hex.features(), address.features()); + let address_emoji = DualAddress::from_emoji_string(&emoji).unwrap(); + assert_eq!(address_emoji.public_spend_key(), address.public_spend_key()); + assert_eq!(address_emoji.public_view_key(), address.public_view_key()); + assert_eq!(address_emoji.network(), address.network()); + assert_eq!(address_emoji.features(), address.features()); + let view_key = PublicKey::from_secret_key(&PrivateKey::random(&mut rng)); let spend_key = PublicKey::from_secret_key(&PrivateKey::random(&mut rng)); @@ -327,7 +388,9 @@ mod test { ); let buff = address.to_bytes(); + let base58 = address.to_base58(); let hex = address.to_hex(); + let emoji = address.to_emoji_string(); let address_buff = DualAddress::from_bytes(&buff).unwrap(); assert_eq!(address_buff.public_spend_key(), address.public_spend_key()); @@ -335,11 +398,23 @@ mod test { assert_eq!(address_buff.network(), address.network()); assert_eq!(address_buff.features(), address.features()); + let address_base58 = DualAddress::from_base58(&base58).unwrap(); + assert_eq!(address_base58.public_spend_key(), address.public_spend_key()); + assert_eq!(address_base58.public_view_key(), address.public_view_key()); + assert_eq!(address_base58.network(), address.network()); + assert_eq!(address_base58.features(), address.features()); + let address_hex = DualAddress::from_hex(&hex).unwrap(); assert_eq!(address_hex.public_spend_key(), address.public_spend_key()); assert_eq!(address_hex.public_view_key(), address.public_view_key()); assert_eq!(address_hex.network(), address.network()); assert_eq!(address_hex.features(), address.features()); + + let address_emoji = DualAddress::from_emoji_string(&emoji).unwrap(); + assert_eq!(address_emoji.public_spend_key(), address.public_spend_key()); + assert_eq!(address_emoji.public_view_key(), address.public_view_key()); + assert_eq!(address_emoji.network(), address.network()); + assert_eq!(address_emoji.features(), address.features()); } #[test] diff --git a/base_layer/common_types/src/tari_address/mod.rs b/base_layer/common_types/src/tari_address/mod.rs index 432045b6e1..42c88f964b 100644 --- a/base_layer/common_types/src/tari_address/mod.rs +++ b/base_layer/common_types/src/tari_address/mod.rs @@ -89,6 +89,10 @@ pub enum TariAddressError { InvalidEmoji, #[error("Cannot recover public key")] CannotRecoverPublicKey, + #[error("Cannot recover network")] + CannotRecoverNetwork, + #[error("Cannot recover feature")] + CannotRecoverFeature, #[error("Could not recover TariAddress from string")] InvalidAddressString, } @@ -214,16 +218,48 @@ impl TariAddress { } /// Construct Tari Address from hex - pub fn from_hex(hex_str: &str) -> Result { - let buf = from_hex(hex_str).map_err(|_| TariAddressError::CannotRecoverPublicKey)?; - TariAddress::from_bytes(buf.as_slice()) + pub fn from_base58(hex_str: &str) -> Result { + if hex_str.len() < 47 { + return Err(TariAddressError::InvalidSize); + } + let (first, rest) = hex_str.split_at(2); + let (network, features) = first.split_at(1); + let mut result = bs58::decode(network) + .into_vec() + .map_err(|_| TariAddressError::CannotRecoverNetwork)?; + let mut features = bs58::decode(features) + .into_vec() + .map_err(|_| TariAddressError::CannotRecoverFeature)?; + let mut rest = bs58::decode(rest) + .into_vec() + .map_err(|_| TariAddressError::CannotRecoverPublicKey)?; + result.append(&mut features); + result.append(&mut rest); + Self::from_bytes(result.as_slice()) } /// Convert Tari Address to bytes + pub fn to_base58(&self) -> String { + let bytes = self.to_vec(); + let mut network = bs58::encode(&bytes[0..1]).into_string(); + let features = bs58::encode(&bytes[1..2].to_vec()).into_string(); + let rest = bs58::encode(&bytes[2..]).into_string(); + network.push_str(&features); + network.push_str(&rest); + network + } + + /// Convert Tari Address to hex pub fn to_hex(&self) -> String { let buf = self.to_vec(); buf.to_hex() } + + /// Creates Tari Address from hex + pub fn from_hex(hex_str: &str) -> Result { + let buf = from_hex(hex_str).map_err(|_| TariAddressError::CannotRecoverPublicKey)?; + TariAddress::from_bytes(buf.as_slice()) + } } impl FromStr for TariAddress { @@ -232,6 +268,8 @@ impl FromStr for TariAddress { fn from_str(key: &str) -> Result { if let Ok(address) = TariAddress::from_emoji_string(&key.trim().replace('|', "")) { Ok(address) + } else if let Ok(address) = TariAddress::from_base58(key) { + Ok(address) } else if let Ok(address) = TariAddress::from_hex(key) { Ok(address) } else { @@ -438,7 +476,9 @@ mod test { let address = TariAddress::new_single_address_with_interactive_only(public_key.clone(), Network::Esmeralda); let buff = address.to_vec(); + let base58 = address.to_base58(); let hex = address.to_hex(); + let emoji = address.to_emoji_string(); let address_buff = TariAddress::from_bytes(&buff); assert_eq!(address_buff, Ok(address.clone())); @@ -448,11 +488,28 @@ mod test { assert_eq!(address_buff.network(), address.network()); assert_eq!(address_buff.features(), address.features()); + let address_base58 = TariAddress::from_base58(&base58).unwrap(); + assert_eq!(address_base58.public_spend_key(), address.public_spend_key()); + assert_eq!(address_base58.network(), address.network()); + assert_eq!(address_base58.features(), address.features()); + let address_hex = TariAddress::from_hex(&hex).unwrap(); assert_eq!(address_hex.public_spend_key(), address.public_spend_key()); assert_eq!(address_hex.network(), address.network()); assert_eq!(address_hex.features(), address.features()); + let address_emoji = TariAddress::from_emoji_string(&emoji).unwrap(); + assert_eq!(address_emoji.public_spend_key(), address.public_spend_key()); + assert_eq!(address_emoji.network(), address.network()); + assert_eq!(address_emoji.features(), address.features()); + + let address_base58_string = TariAddress::from_str(&base58).unwrap(); + assert_eq!(address_base58_string, address_base58); + let address_hex_string = TariAddress::from_str(&hex).unwrap(); + assert_eq!(address_hex_string, address_hex); + let address_emoji_string = TariAddress::from_str(&emoji).unwrap(); + assert_eq!(address_emoji_string, address_emoji); + // Generate random public key let public_key = PublicKey::from_secret_key(&PrivateKey::random(&mut rng)); @@ -464,7 +521,9 @@ mod test { ); let buff = address.to_vec(); + let base58 = address.to_base58(); let hex = address.to_hex(); + let emoji = address.to_emoji_string(); let address_buff = TariAddress::from_bytes(&buff); assert_eq!(address_buff, Ok(address.clone())); @@ -474,10 +533,27 @@ mod test { assert_eq!(address_buff.network(), address.network()); assert_eq!(address_buff.features(), address.features()); + let address_base58 = TariAddress::from_base58(&base58).unwrap(); + assert_eq!(address_base58.public_spend_key(), address.public_spend_key()); + assert_eq!(address_base58.network(), address.network()); + assert_eq!(address_base58.features(), address.features()); + let address_hex = TariAddress::from_hex(&hex).unwrap(); assert_eq!(address_hex.public_spend_key(), address.public_spend_key()); assert_eq!(address_hex.network(), address.network()); assert_eq!(address_hex.features(), address.features()); + + let address_emoji = TariAddress::from_emoji_string(&emoji).unwrap(); + assert_eq!(address_emoji.public_spend_key(), address.public_spend_key()); + assert_eq!(address_emoji.network(), address.network()); + assert_eq!(address_emoji.features(), address.features()); + + let address_base58_string = TariAddress::from_str(&base58).unwrap(); + assert_eq!(address_base58_string, address_base58); + let address_hex_string = TariAddress::from_str(&hex).unwrap(); + assert_eq!(address_hex_string, address_hex); + let address_emoji_string = TariAddress::from_str(&emoji).unwrap(); + assert_eq!(address_emoji_string, address_emoji); // Generate random public key let public_key = PublicKey::from_secret_key(&PrivateKey::random(&mut rng)); @@ -489,7 +565,9 @@ mod test { ); let buff = address.to_vec(); + let base58 = address.to_base58(); let hex = address.to_hex(); + let emoji = address.to_emoji_string(); let address_buff = TariAddress::from_bytes(&buff); assert_eq!(address_buff, Ok(address.clone())); @@ -499,15 +577,69 @@ mod test { assert_eq!(address_buff.network(), address.network()); assert_eq!(address_buff.features(), address.features()); + let address_base58 = TariAddress::from_base58(&base58).unwrap(); + assert_eq!(address_base58.public_spend_key(), address.public_spend_key()); + assert_eq!(address_base58.network(), address.network()); + assert_eq!(address_base58.features(), address.features()); + let address_hex = TariAddress::from_hex(&hex).unwrap(); assert_eq!(address_hex.public_spend_key(), address.public_spend_key()); assert_eq!(address_hex.network(), address.network()); assert_eq!(address_hex.features(), address.features()); + + let address_emoji = TariAddress::from_emoji_string(&emoji).unwrap(); + assert_eq!(address_emoji.public_spend_key(), address.public_spend_key()); + assert_eq!(address_emoji.network(), address.network()); + assert_eq!(address_emoji.features(), address.features()); + + let address_base58_string = TariAddress::from_str(&base58).unwrap(); + assert_eq!(address_base58_string, address_base58); + let address_hex_string = TariAddress::from_str(&hex).unwrap(); + assert_eq!(address_hex_string, address_hex); + let address_emoji_string = TariAddress::from_str(&emoji).unwrap(); + assert_eq!(address_emoji_string, address_emoji); } #[test] /// Test encoding for dual tari address fn encoding_dual() { + fn test_addres(address: TariAddress) { + let buff = address.to_vec(); + let base58 = address.to_base58(); + let hex = address.to_hex(); + let emoji = address.to_emoji_string(); + + let address_buff = TariAddress::from_bytes(&buff).unwrap(); + assert_eq!(address_buff.public_spend_key(), address.public_spend_key()); + assert_eq!(address_buff.public_view_key(), address.public_view_key()); + assert_eq!(address_buff.network(), address.network()); + assert_eq!(address_buff.features(), address.features()); + + let address_base58 = TariAddress::from_base58(&base58).unwrap(); + assert_eq!(address_base58.public_spend_key(), address.public_spend_key()); + assert_eq!(address_base58.public_view_key(), address.public_view_key()); + assert_eq!(address_base58.network(), address.network()); + assert_eq!(address_base58.features(), address.features()); + + let address_hex = TariAddress::from_hex(&hex).unwrap(); + assert_eq!(address_hex.public_spend_key(), address.public_spend_key()); + assert_eq!(address_hex.public_view_key(), address.public_view_key()); + assert_eq!(address_hex.network(), address.network()); + assert_eq!(address_hex.features(), address.features()); + + let address_emoji = TariAddress::from_emoji_string(&emoji).unwrap(); + assert_eq!(address_emoji.public_spend_key(), address.public_spend_key()); + assert_eq!(address_emoji.public_view_key(), address.public_view_key()); + assert_eq!(address_emoji.network(), address.network()); + assert_eq!(address_emoji.features(), address.features()); + + let address_base58_string = TariAddress::from_str(&base58).unwrap(); + assert_eq!(address_base58_string, address_base58); + let address_hex_string = TariAddress::from_str(&hex).unwrap(); + assert_eq!(address_hex_string, address_hex); + let address_emoji_string = TariAddress::from_str(&emoji).unwrap(); + assert_eq!(address_emoji_string, address_emoji); + } // Generate random public key let mut rng = rand::thread_rng(); let view_key = PublicKey::from_secret_key(&PrivateKey::random(&mut rng)); @@ -519,21 +651,7 @@ mod test { spend_key.clone(), Network::Esmeralda, ); - - let buff = address.to_vec(); - let hex = address.to_hex(); - - let address_buff = TariAddress::from_bytes(&buff).unwrap(); - assert_eq!(address_buff.public_spend_key(), address.public_spend_key()); - assert_eq!(address_buff.public_view_key(), address.public_view_key()); - assert_eq!(address_buff.network(), address.network()); - assert_eq!(address_buff.features(), address.features()); - - let address_hex = TariAddress::from_hex(&hex).unwrap(); - assert_eq!(address_hex.public_spend_key(), address.public_spend_key()); - assert_eq!(address_hex.public_view_key(), address.public_view_key()); - assert_eq!(address_hex.network(), address.network()); - assert_eq!(address_hex.features(), address.features()); + test_addres(address); let view_key = PublicKey::from_secret_key(&PrivateKey::random(&mut rng)); let spend_key = PublicKey::from_secret_key(&PrivateKey::random(&mut rng)); @@ -545,21 +663,7 @@ mod test { Network::Esmeralda, TariAddressFeatures::create_interactive_only(), ); - - let buff = address.to_vec(); - let hex = address.to_hex(); - - let address_buff = TariAddress::from_bytes(&buff).unwrap(); - assert_eq!(address_buff.public_spend_key(), address.public_spend_key()); - assert_eq!(address_buff.public_view_key(), address.public_view_key()); - assert_eq!(address_buff.network(), address.network()); - assert_eq!(address_buff.features(), address.features()); - - let address_hex = TariAddress::from_hex(&hex).unwrap(); - assert_eq!(address_hex.public_spend_key(), address.public_spend_key()); - assert_eq!(address_hex.public_view_key(), address.public_view_key()); - assert_eq!(address_hex.network(), address.network()); - assert_eq!(address_hex.features(), address.features()); + test_addres(address); let view_key = PublicKey::from_secret_key(&PrivateKey::random(&mut rng)); let spend_key = PublicKey::from_secret_key(&PrivateKey::random(&mut rng)); @@ -571,21 +675,7 @@ mod test { Network::Esmeralda, TariAddressFeatures::create_one_sided_only(), ); - - let buff = address.to_vec(); - let hex = address.to_hex(); - - let address_buff = TariAddress::from_bytes(&buff).unwrap(); - assert_eq!(address_buff.public_spend_key(), address.public_spend_key()); - assert_eq!(address_buff.public_view_key(), address.public_view_key()); - assert_eq!(address_buff.network(), address.network()); - assert_eq!(address_buff.features(), address.features()); - - let address_hex = TariAddress::from_hex(&hex).unwrap(); - assert_eq!(address_hex.public_spend_key(), address.public_spend_key()); - assert_eq!(address_hex.public_view_key(), address.public_view_key()); - assert_eq!(address_hex.network(), address.network()); - assert_eq!(address_hex.features(), address.features()); + test_addres(address); } #[test] diff --git a/base_layer/common_types/src/tari_address/single_address.rs b/base_layer/common_types/src/tari_address/single_address.rs index 9eca6e4807..5553fc0dcb 100644 --- a/base_layer/common_types/src/tari_address/single_address.rs +++ b/base_layer/common_types/src/tari_address/single_address.rs @@ -139,17 +139,50 @@ impl SingleAddress { buf } - /// Construct Tari Address from hex - pub fn from_hex(hex_str: &str) -> Result { - let buf = from_hex(hex_str).map_err(|_| TariAddressError::CannotRecoverPublicKey)?; - Self::from_bytes(buf.as_slice()) + /// Construct Tari Address from Base58 + pub fn from_base58(hex_str: &str) -> Result { + // Due to the byte length, it can be encoded as 46, 47 or 48 chars + if hex_str.len() != 46 && hex_str.len() != 47 && hex_str.len() != 48 { + return Err(TariAddressError::InvalidSize); + } + let (first, rest) = hex_str.split_at(2); + let (network, features) = first.split_at(1); + let mut result = bs58::decode(network) + .into_vec() + .map_err(|_| TariAddressError::CannotRecoverNetwork)?; + let mut features = bs58::decode(features) + .into_vec() + .map_err(|_| TariAddressError::CannotRecoverFeature)?; + let mut rest = bs58::decode(rest) + .into_vec() + .map_err(|_| TariAddressError::CannotRecoverPublicKey)?; + result.append(&mut features); + result.append(&mut rest); + Self::from_bytes(result.as_slice()) } - /// Convert Tari Address to bytes + /// Convert Tari Address to Base58 + pub fn to_base58(&self) -> String { + let bytes = self.to_bytes(); + let mut network = bs58::encode(&bytes[0..1]).into_string(); + let features = bs58::encode(&bytes[1..2].to_vec()).into_string(); + let rest = bs58::encode(&bytes[2..]).into_string(); + network.push_str(&features); + network.push_str(&rest); + network + } + + /// Convert Tari single Address to hex pub fn to_hex(&self) -> String { let buf = self.to_bytes(); buf.to_hex() } + + /// Creates Tari single Address from hex + pub fn from_hex(hex_str: &str) -> Result { + let buf = from_hex(hex_str).map_err(|_| TariAddressError::CannotRecoverPublicKey)?; + SingleAddress::from_bytes(buf.as_slice()) + } } #[cfg(test)] mod test { @@ -244,18 +277,30 @@ mod test { let address = SingleAddress::new_with_interactive_only(public_key.clone(), Network::Esmeralda); let buff = address.to_bytes(); + let base58 = address.to_base58(); let hex = address.to_hex(); + let emoji = address.to_emoji_string(); let address_buff = SingleAddress::from_bytes(&buff).unwrap(); assert_eq!(address_buff.public_spend_key(), address.public_spend_key()); assert_eq!(address_buff.network(), address.network()); assert_eq!(address_buff.features(), address.features()); + let address_base58 = SingleAddress::from_base58(&base58).unwrap(); + assert_eq!(address_base58.public_spend_key(), address.public_spend_key()); + assert_eq!(address_base58.network(), address.network()); + assert_eq!(address_base58.features(), address.features()); + let address_hex = SingleAddress::from_hex(&hex).unwrap(); assert_eq!(address_hex.public_spend_key(), address.public_spend_key()); assert_eq!(address_hex.network(), address.network()); assert_eq!(address_hex.features(), address.features()); + let address_emoji = SingleAddress::from_emoji_string(&emoji).unwrap(); + assert_eq!(address_emoji.public_spend_key(), address.public_spend_key()); + assert_eq!(address_emoji.network(), address.network()); + assert_eq!(address_emoji.features(), address.features()); + // Generate random public key let public_key = PublicKey::from_secret_key(&PrivateKey::random(&mut rng)); @@ -267,18 +312,30 @@ mod test { ); let buff = address.to_bytes(); + let base58 = address.to_base58(); let hex = address.to_hex(); + let emoji = address.to_emoji_string(); let address_buff = SingleAddress::from_bytes(&buff).unwrap(); assert_eq!(address_buff.public_spend_key(), address.public_spend_key()); assert_eq!(address_buff.network(), address.network()); assert_eq!(address_buff.features(), address.features()); + let address_base58 = SingleAddress::from_base58(&base58).unwrap(); + assert_eq!(address_base58.public_spend_key(), address.public_spend_key()); + assert_eq!(address_base58.network(), address.network()); + assert_eq!(address_base58.features(), address.features()); + let address_hex = SingleAddress::from_hex(&hex).unwrap(); assert_eq!(address_hex.public_spend_key(), address.public_spend_key()); assert_eq!(address_hex.network(), address.network()); assert_eq!(address_hex.features(), address.features()); + let address_emoji = SingleAddress::from_emoji_string(&emoji).unwrap(); + assert_eq!(address_emoji.public_spend_key(), address.public_spend_key()); + assert_eq!(address_emoji.network(), address.network()); + assert_eq!(address_emoji.features(), address.features()); + // Generate random public key let public_key = PublicKey::from_secret_key(&PrivateKey::random(&mut rng)); @@ -290,17 +347,29 @@ mod test { ); let buff = address.to_bytes(); + let base58 = address.to_base58(); let hex = address.to_hex(); + let emoji = address.to_emoji_string(); let address_buff = SingleAddress::from_bytes(&buff).unwrap(); assert_eq!(address_buff.public_spend_key(), address.public_spend_key()); assert_eq!(address_buff.network(), address.network()); assert_eq!(address_buff.features(), address.features()); + let address_base58 = SingleAddress::from_base58(&base58).unwrap(); + assert_eq!(address_base58.public_spend_key(), address.public_spend_key()); + assert_eq!(address_base58.network(), address.network()); + assert_eq!(address_base58.features(), address.features()); + let address_hex = SingleAddress::from_hex(&hex).unwrap(); assert_eq!(address_hex.public_spend_key(), address.public_spend_key()); assert_eq!(address_hex.network(), address.network()); assert_eq!(address_hex.features(), address.features()); + + let address_emoji = SingleAddress::from_emoji_string(&emoji).unwrap(); + assert_eq!(address_emoji.public_spend_key(), address.public_spend_key()); + assert_eq!(address_emoji.network(), address.network()); + assert_eq!(address_emoji.features(), address.features()); } #[test] diff --git a/base_layer/core/src/transactions/transaction_components/encrypted_data.rs b/base_layer/core/src/transactions/transaction_components/encrypted_data.rs index c03ef7bc27..a3329e9fa2 100644 --- a/base_layer/core/src/transactions/transaction_components/encrypted_data.rs +++ b/base_layer/core/src/transactions/transaction_components/encrypted_data.rs @@ -349,9 +349,14 @@ mod test { PaymentId::U256( U256::from_dec_str("465465489789785458694894263185648978947864164681631").expect("Should not fail"), ), - PaymentId::Address(DualAddress::from_hex("2603bc3d05fb55446f18031feb5494d19d6c795fc93d6218c65a285c7a88fd03917c72e4a70cbabcc52ad79cb2ac170df4a29912ffb345f20b0f8ae5524c749b9425f0").unwrap()), + PaymentId::Address( + DualAddress::from_base58( + "f425UWsDp714RiN53c1G6ek57rfFnotB5NCMyrn4iDgbR8i2sXVHa4xSsedd66o9KmkRgErQnyDdCaAdNLzcKrj7eUb", + ) + .unwrap(), + ), PaymentId::Open(vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10]), - PaymentId::Open(vec![1;256]), + PaymentId::Open(vec![1; 256]), ] { for (value, mask) in [ (0, PrivateKey::default()), @@ -364,7 +369,8 @@ mod test { let encryption_key = PrivateKey::random(&mut OsRng); let amount = MicroMinotari::from(value); let encrypted_data = - EncryptedData::encrypt_data(&encryption_key, &commitment, amount, &mask, payment_id.clone()).unwrap(); + EncryptedData::encrypt_data(&encryption_key, &commitment, amount, &mask, payment_id.clone()) + .unwrap(); let (decrypted_value, decrypted_mask, decrypted_payment_id) = EncryptedData::decrypt_data(&encryption_key, &commitment, &encrypted_data).unwrap(); assert_eq!(amount, decrypted_value); @@ -390,9 +396,14 @@ mod test { PaymentId::U256( U256::from_dec_str("465465489789785458694894263185648978947864164681631").expect("Should not fail"), ), - PaymentId::Address(DualAddress::from_hex("2603bc3d05fb55446f18031feb5494d19d6c795fc93d6218c65a285c7a88fd03917c72e4a70cbabcc52ad79cb2ac170df4a29912ffb345f20b0f8ae5524c749b9425f0").unwrap()), - PaymentId::Open(vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10]), - PaymentId::Open(vec![1;256]), + PaymentId::Address( + DualAddress::from_base58( + "f425UWsDp714RiN53c1G6ek57rfFnotB5NCMyrn4iDgbR8i2sXVHa4xSsedd66o9KmkRgErQnyDdCaAdNLzcKrj7eUb", + ) + .unwrap(), + ), + PaymentId::Open(vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10]), + PaymentId::Open(vec![1; 256]), ] { for (value, mask) in [ (0, PrivateKey::default()), @@ -405,7 +416,8 @@ mod test { let encryption_key = PrivateKey::random(&mut OsRng); let amount = MicroMinotari::from(value); let encrypted_data = - EncryptedData::encrypt_data(&encryption_key, &commitment, amount, &mask, payment_id.clone()).unwrap(); + EncryptedData::encrypt_data(&encryption_key, &commitment, amount, &mask, payment_id.clone()) + .unwrap(); let bytes = encrypted_data.to_byte_vec(); let encrypted_data_from_bytes = EncryptedData::from_bytes(&bytes).unwrap(); assert_eq!(encrypted_data, encrypted_data_from_bytes); diff --git a/base_layer/wallet_ffi/src/error.rs b/base_layer/wallet_ffi/src/error.rs index 2453fbea59..4ebef20914 100644 --- a/base_layer/wallet_ffi/src/error.rs +++ b/base_layer/wallet_ffi/src/error.rs @@ -402,7 +402,9 @@ impl From for LibWalletError { code: 701, message: format!("{:?}", e), }, - TariAddressError::CannotRecoverPublicKey => Self { + TariAddressError::CannotRecoverPublicKey | + TariAddressError::CannotRecoverFeature | + TariAddressError::CannotRecoverNetwork => Self { code: 702, message: format!("{:?}", e), }, diff --git a/base_layer/wallet_ffi/src/lib.rs b/base_layer/wallet_ffi/src/lib.rs index 44fb99f3c3..ddd094e54b 100644 --- a/base_layer/wallet_ffi/src/lib.rs +++ b/base_layer/wallet_ffi/src/lib.rs @@ -1157,7 +1157,7 @@ pub unsafe extern "C" fn tari_address_get_bytes( /// # Safety /// The ```public_key_destroy``` method must be called when finished with a TariWalletAddress to prevent a memory leak #[no_mangle] -pub unsafe extern "C" fn tari_address_from_hex( +pub unsafe extern "C" fn tari_address_from_base58( address: *const c_char, error_out: *mut c_int, ) -> *mut TariWalletAddress { @@ -1181,11 +1181,11 @@ pub unsafe extern "C" fn tari_address_from_hex( } } - let address = TariWalletAddress::from_hex(key_str.as_str()); + let address = TariWalletAddress::from_base58(key_str.as_str()); match address { Ok(address) => Box::into_raw(Box::new(address)), Err(e) => { - error!(target: LOG_TARGET, "Error creating a Tari Address from Hex: {:?}", e); + error!(target: LOG_TARGET, "Error creating a Tari Address from Base58 string: {:?}", e); error = LibWalletError::from(e).code; ptr::swap(error_out, &mut error as *mut c_int); ptr::null_mut() diff --git a/base_layer/wallet_ffi/wallet.h b/base_layer/wallet_ffi/wallet.h index d6f44a818e..753b157a6c 100644 --- a/base_layer/wallet_ffi/wallet.h +++ b/base_layer/wallet_ffi/wallet.h @@ -740,8 +740,8 @@ struct ByteVector *tari_address_get_bytes(TariWalletAddress *address, * # Safety * The ```public_key_destroy``` method must be called when finished with a TariWalletAddress to prevent a memory leak */ -TariWalletAddress *tari_address_from_hex(const char *address, - int *error_out); +TariWalletAddress *tari_address_from_base58(const char *address, + int *error_out); /** * Creates a char array from a TariWalletAddress in emoji format diff --git a/integration_tests/src/ffi/callbacks.rs b/integration_tests/src/ffi/callbacks.rs index 7530259662..e29711a4b5 100644 --- a/integration_tests/src/ffi/callbacks.rs +++ b/integration_tests/src/ffi/callbacks.rs @@ -23,6 +23,7 @@ use std::sync::{Arc, Mutex, Once}; use libc::c_void; +use tari_common_types::tari_address::TariAddress; use super::{Balance, CompletedTransaction, ContactsLivenessData, PendingInboundTransaction, Wallet}; use crate::ffi::TransactionSendStatus; @@ -236,11 +237,12 @@ impl Callbacks { pub fn on_contacts_liveness_data_updated(&mut self, ptr: *mut c_void) { let contact_liveness_data = ContactsLivenessData::from_ptr(ptr); + let address = TariAddress::from_bytes(&contact_liveness_data.get_public_key().address().get_vec()).unwrap(); println!( "{} callbackContactsLivenessUpdated: received {} from contact {} with latency {} at {} and is {}.", chrono::Local::now().format("%Y/%m/%d %H:%M:%S"), contact_liveness_data.get_message_type(), - contact_liveness_data.get_public_key().address().get_as_hex(), + address.to_base58(), contact_liveness_data.get_latency(), contact_liveness_data.get_last_seen(), contact_liveness_data.get_online_status() diff --git a/integration_tests/src/ffi/contact.rs b/integration_tests/src/ffi/contact.rs index 2485219b51..410d445662 100644 --- a/integration_tests/src/ffi/contact.rs +++ b/integration_tests/src/ffi/contact.rs @@ -52,7 +52,7 @@ impl Contact { unsafe { ptr = ffi_import::contact_create( CString::new(alias).unwrap().into_raw(), - WalletAddress::from_hex(address).get_ptr(), + WalletAddress::from_base58(address).get_ptr(), false, &mut error, ); diff --git a/integration_tests/src/ffi/ffi_import.rs b/integration_tests/src/ffi/ffi_import.rs index 6312fab4f6..f95eecc3e2 100644 --- a/integration_tests/src/ffi/ffi_import.rs +++ b/integration_tests/src/ffi/ffi_import.rs @@ -112,7 +112,7 @@ extern "C" { network: c_uint, error_out: *mut c_int, ) -> *mut TariWalletAddress; - pub fn tari_address_from_hex(address: *const c_char, error_out: *mut c_int) -> *mut TariWalletAddress; + pub fn tari_address_from_base58(address: *const c_char, error_out: *mut c_int) -> *mut TariWalletAddress; pub fn tari_address_to_emoji_id(address: *mut TariWalletAddress, error_out: *mut c_int) -> *mut c_char; pub fn emoji_id_to_tari_address(emoji: *const c_char, error_out: *mut c_int) -> *mut TariWalletAddress; pub fn commitment_and_public_signature_create_from_bytes( diff --git a/integration_tests/src/ffi/wallet.rs b/integration_tests/src/ffi/wallet.rs index d6bbbc9bb3..d406360296 100644 --- a/integration_tests/src/ffi/wallet.rs +++ b/integration_tests/src/ffi/wallet.rs @@ -29,6 +29,7 @@ use std::{ use callbacks::Callbacks; use indexmap::IndexMap; use libc::{c_ulonglong, c_void}; +use tari_common_types::tari_address::TariAddress; use super::{ ffi_import::{ @@ -216,10 +217,11 @@ impl Wallet { } pub fn add_liveness_data(&mut self, contact_liveness_data: ContactsLivenessData) { - self.liveness_data.lock().unwrap().insert( - contact_liveness_data.get_public_key().address().get_as_hex(), - contact_liveness_data, - ); + let address = TariAddress::from_bytes(&contact_liveness_data.get_public_key().address().get_vec()).unwrap(); + self.liveness_data + .lock() + .unwrap() + .insert(address.to_base58(), contact_liveness_data); } pub fn set_balance(&mut self, balance: Balance) { @@ -333,7 +335,7 @@ impl Wallet { unsafe { tx_id = ffi_import::wallet_send_transaction( self.ptr, - WalletAddress::from_hex(dest).get_ptr(), + WalletAddress::from_base58(dest).get_ptr(), amount, null_mut(), fee_per_gram, diff --git a/integration_tests/src/ffi/wallet_address.rs b/integration_tests/src/ffi/wallet_address.rs index dbfc252636..b65c396424 100644 --- a/integration_tests/src/ffi/wallet_address.rs +++ b/integration_tests/src/ffi/wallet_address.rs @@ -42,11 +42,11 @@ impl WalletAddress { Self { ptr } } - pub fn from_hex(address: String) -> Self { + pub fn from_base58(address: String) -> Self { let mut error = 0; let ptr; unsafe { - ptr = ffi_import::tari_address_from_hex(CString::new(address).unwrap().into_raw(), &mut error); + ptr = ffi_import::tari_address_from_base58(CString::new(address).unwrap().into_raw(), &mut error); if error > 0 { println!("wallet_get_tari_address error {}", error); } diff --git a/integration_tests/src/merge_mining_proxy.rs b/integration_tests/src/merge_mining_proxy.rs index 3a2f6e60c7..5baaeecb76 100644 --- a/integration_tests/src/merge_mining_proxy.rs +++ b/integration_tests/src/merge_mining_proxy.rs @@ -132,7 +132,7 @@ impl MergeMiningProxyProcess { ), ( "merge_mining_proxy.wallet_payment_address".to_string(), - wallet_payment_address.to_hex(), + wallet_payment_address.to_base58(), ), ("merge_mining_proxy.stealth_payment".to_string(), stealth.to_string()), ( diff --git a/integration_tests/src/miner.rs b/integration_tests/src/miner.rs index c139265c78..1016e162e4 100644 --- a/integration_tests/src/miner.rs +++ b/integration_tests/src/miner.rs @@ -127,7 +127,7 @@ impl MinerProcess { ("miner.mine_on_tip_only".to_string(), "false".to_string()), ( "miner.wallet_payment_address".to_string(), - wallet_payment_address.to_hex(), + wallet_payment_address.to_base58(), ), ("miner.stealth_payment".to_string(), self.stealth.to_string()), ], diff --git a/integration_tests/src/wallet_ffi.rs b/integration_tests/src/wallet_ffi.rs index f1834ebf28..25c9ef737b 100644 --- a/integration_tests/src/wallet_ffi.rs +++ b/integration_tests/src/wallet_ffi.rs @@ -31,6 +31,7 @@ use std::{ use chrono::{DateTime, Utc}; use indexmap::IndexMap; use libc::c_void; +use tari_common_types::tari_address::TariAddress; use super::ffi::{ Balance, @@ -86,7 +87,8 @@ impl WalletFFI { pub fn identify(&self) -> String { let tari_address = self.get_address(); let key = tari_address.address(); - key.get_as_hex() + let address = TariAddress::from_bytes(&key.get_vec()).unwrap(); + address.to_base58() } pub fn get_emoji_id(&self) -> String { diff --git a/integration_tests/src/world.rs b/integration_tests/src/world.rs index f477d07be1..3f9caae9d8 100644 --- a/integration_tests/src/world.rs +++ b/integration_tests/src/world.rs @@ -46,7 +46,6 @@ use tari_core::{ }; use tari_crypto::keys::{PublicKey as PK, SecretKey}; use tari_key_manager::key_manager_service::{KeyId, KeyManagerInterface}; -use tari_utilities::hex::Hex; use thiserror::Error; use crate::{ @@ -202,24 +201,25 @@ impl TariWorld { if let Some(address) = self.wallet_addresses.get(name.as_ref()) { return Ok(address.clone()); } - match self.get_wallet_client(name).await { + let address_bytes = match self.get_wallet_client(name).await { Ok(wallet) => { let mut wallet = wallet; - Ok(wallet + wallet .get_address(minotari_wallet_grpc_client::grpc::Empty {}) .await .unwrap() .into_inner() .address - .to_hex()) }, Err(_) => { let ffi_wallet = self.get_ffi_wallet(name).unwrap(); - Ok(ffi_wallet.get_address().address().get_as_hex()) + ffi_wallet.get_address().address().get_vec() }, - } + }; + let tari_address = TariAddress::from_bytes(&address_bytes)?; + Ok(tari_address.to_base58()) } #[allow(dead_code)] diff --git a/integration_tests/tests/steps/chat_ffi_steps.rs b/integration_tests/tests/steps/chat_ffi_steps.rs index 7461ebdf2a..ac4a3a126f 100644 --- a/integration_tests/tests/steps/chat_ffi_steps.rs +++ b/integration_tests/tests/steps/chat_ffi_steps.rs @@ -48,7 +48,7 @@ async fn chat_ffi_client_connected_to_base_node(world: &mut TariWorld, name: Str async fn sideloaded_chat_ffi_client_connected_to_wallet(world: &mut TariWorld, chat_name: String, wallet_name: String) { let wallet = world.get_ffi_wallet(&wallet_name).unwrap(); let address = world.get_wallet_address(&wallet_name).await.unwrap(); - let address = TariAddress::from_hex(&address).unwrap(); + let address = TariAddress::from_base58(&address).unwrap(); let client = sideload_ffi_chat_client(address, wallet.base_dir.clone(), wallet.contacts_handle()).await; world.chat_clients.insert(chat_name, Box::new(client)); } diff --git a/integration_tests/tests/steps/node_steps.rs b/integration_tests/tests/steps/node_steps.rs index 25631fcc33..a6c8cf2a60 100644 --- a/integration_tests/tests/steps/node_steps.rs +++ b/integration_tests/tests/steps/node_steps.rs @@ -753,18 +753,22 @@ async fn generate_block_with_2_coinbases(world: &mut TariWorld, node: String) { new_template: Some(block_template), coinbases: vec![ NewBlockCoinbase { - address: TariAddress::from_hex("2603025d6849dd3dcc42c59b4bbfed335a438a0538f0d46a12f5142fcded0159b34d42f59c53d2e9a9fa7b90d2baec1455a7ab1144c49d69599c52b8bd8e0bb3e32292") - .unwrap() - .to_hex(), + address: TariAddress::from_base58( + "f4L8GRWsXqz26DM3qAGErLtVknYzmTe2fYP2yKFn4biFXYJMP61W9MeD726QJ7ytWhRGyewTZzTzjZ7tEPskDptwRub", + ) + .unwrap() + .to_base58(), value: amount - 1000, stealth_payment: false, revealed_value_proof: true, coinbase_extra: Vec::new(), }, NewBlockCoinbase { - address: TariAddress::from_hex("2603cc911148f1a78fbf721e27c80d1717dcfe1e6750ffe60af2047bff1d4f066575e84190b0bc7e939d1998c6bbd81c8dfd654abaa7ffae6af295f1077124b5885751") - .unwrap() - .to_hex(), + address: TariAddress::from_base58( + "f4HS8b64MDbvdaG5fiNgtsHhnoeCPaniS5M7iFuvEMDoyh9uikhWmYbnRtjdgHHVPjAXr7oSW61VSH5QvHU8jps1JXW", + ) + .unwrap() + .to_base58(), value: 1000, stealth_payment: false, revealed_value_proof: true, @@ -809,18 +813,22 @@ async fn generate_block_with_2_as_single_request_coinbases(world: &mut TariWorld max_weight: 0, coinbases: vec![ NewBlockCoinbase { - address: TariAddress::from_hex("2603025d6849dd3dcc42c59b4bbfed335a438a0538f0d46a12f5142fcded0159b34d42f59c53d2e9a9fa7b90d2baec1455a7ab1144c49d69599c52b8bd8e0bb3e32292") - .unwrap() - .to_hex(), + address: TariAddress::from_base58( + "f4L8GRWsXqz26DM3qAGErLtVknYzmTe2fYP2yKFn4biFXYJMP61W9MeD726QJ7ytWhRGyewTZzTzjZ7tEPskDptwRub", + ) + .unwrap() + .to_base58(), value: 1, stealth_payment: false, revealed_value_proof: true, coinbase_extra: Vec::new(), }, NewBlockCoinbase { - address: TariAddress::from_hex("2603cc911148f1a78fbf721e27c80d1717dcfe1e6750ffe60af2047bff1d4f066575e84190b0bc7e939d1998c6bbd81c8dfd654abaa7ffae6af295f1077124b5885751") - .unwrap() - .to_hex(), + address: TariAddress::from_base58( + "f4HS8b64MDbvdaG5fiNgtsHhnoeCPaniS5M7iFuvEMDoyh9uikhWmYbnRtjdgHHVPjAXr7oSW61VSH5QvHU8jps1JXW", + ) + .unwrap() + .to_base58(), value: 2, stealth_payment: false, revealed_value_proof: true, diff --git a/integration_tests/tests/steps/wallet_cli_steps.rs b/integration_tests/tests/steps/wallet_cli_steps.rs index ab8785f112..1cf180fb77 100644 --- a/integration_tests/tests/steps/wallet_cli_steps.rs +++ b/integration_tests/tests/steps/wallet_cli_steps.rs @@ -146,7 +146,7 @@ async fn send_from_cli(world: &mut TariWorld, amount: u64, wallet_a: String, wal .into_inner() .address .to_hex(); - let wallet_b_address = TariAddress::from_hex(wallet_b_address.as_str()).unwrap(); + let wallet_b_address = TariAddress::from_base58(wallet_b_address.as_str()).unwrap(); let mut cli = get_default_cli(); @@ -210,7 +210,7 @@ async fn make_it_rain( .into_inner() .address .to_hex(); - let wallet_b_address = TariAddress::from_hex(wallet_b_address.as_str()).unwrap(); + let wallet_b_address = TariAddress::from_base58(wallet_b_address.as_str()).unwrap(); let mut cli = get_default_cli(); diff --git a/integration_tests/tests/steps/wallet_ffi_steps.rs b/integration_tests/tests/steps/wallet_ffi_steps.rs index a9dd1a360e..e49bd1e994 100644 --- a/integration_tests/tests/steps/wallet_ffi_steps.rs +++ b/integration_tests/tests/steps/wallet_ffi_steps.rs @@ -23,6 +23,7 @@ use std::{convert::TryFrom, io::BufRead, ptr::null, time::Duration}; use cucumber::{given, then, when}; +use tari_common_types::tari_address::TariAddress; use tari_integration_tests::{ wallet_ffi::{create_contact, create_seed_words, get_mnemonic_word_list_for_language, spawn_wallet_ffi}, TariWorld, @@ -166,7 +167,8 @@ async fn check_contact(world: &mut TariWorld, alias: String, pubkey: Option