From ac20d8453882c74843575aa36040071a944c5e7c Mon Sep 17 00:00:00 2001 From: Omer Yacine Date: Sun, 16 Mar 2025 16:50:34 +0200 Subject: [PATCH 01/50] store stats files in global db directory --- mm2src/mm2_main/src/lp_swap/maker_swap.rs | 7 ++++++- mm2src/mm2_main/src/lp_swap/taker_swap.rs | 7 ++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/mm2src/mm2_main/src/lp_swap/maker_swap.rs b/mm2src/mm2_main/src/lp_swap/maker_swap.rs index 716c9a059a..8de7794279 100644 --- a/mm2src/mm2_main/src/lp_swap/maker_swap.rs +++ b/mm2src/mm2_main/src/lp_swap/maker_swap.rs @@ -80,7 +80,12 @@ pub const MAKER_ERROR_EVENTS: [&str; 15] = [ pub const MAKER_PAYMENT_SENT_LOG: &str = "Maker payment sent"; #[cfg(not(target_arch = "wasm32"))] -pub fn stats_maker_swap_dir(ctx: &MmArc) -> PathBuf { ctx.dbdir().join("SWAPS").join("STATS").join("MAKER") } +pub fn stats_maker_swap_dir(ctx: &MmArc) -> PathBuf { + #[cfg(not(feature = "new-db-arch"))] + return ctx.dbdir().join("SWAPS").join("STATS").join("MAKER"); + #[cfg(feature = "new-db-arch")] + return ctx.global_dir().join("SWAPS").join("STATS").join("MAKER"); +} #[cfg(not(target_arch = "wasm32"))] pub fn stats_maker_swap_file_path(ctx: &MmArc, uuid: &Uuid) -> PathBuf { diff --git a/mm2src/mm2_main/src/lp_swap/taker_swap.rs b/mm2src/mm2_main/src/lp_swap/taker_swap.rs index 74e69384bf..51df5f21a4 100644 --- a/mm2src/mm2_main/src/lp_swap/taker_swap.rs +++ b/mm2src/mm2_main/src/lp_swap/taker_swap.rs @@ -103,7 +103,12 @@ pub const WATCHER_MESSAGE_SENT_LOG: &str = "Watcher message sent..."; pub const MAKER_PAYMENT_SPENT_BY_WATCHER_LOG: &str = "Maker payment is spent by the watcher..."; #[cfg(not(target_arch = "wasm32"))] -pub fn stats_taker_swap_dir(ctx: &MmArc) -> PathBuf { ctx.dbdir().join("SWAPS").join("STATS").join("TAKER") } +pub fn stats_taker_swap_dir(ctx: &MmArc) -> PathBuf { + #[cfg(not(feature = "new-db-arch"))] + return ctx.dbdir().join("SWAPS").join("STATS").join("MAKER"); + #[cfg(feature = "new-db-arch")] + return ctx.global_dir().join("SWAPS").join("STATS").join("TAKER"); +} #[cfg(not(target_arch = "wasm32"))] pub fn stats_taker_swap_file_path(ctx: &MmArc, uuid: &Uuid) -> PathBuf { From b219751584faebc9d7f20abf2b8ad2b742d0eb4e Mon Sep 17 00:00:00 2001 From: Omer Yacine Date: Thu, 20 Mar 2025 11:17:43 +0200 Subject: [PATCH 02/50] let MmCtx::address_dir() default back to Ctx::dbdir() based on compilation features --- mm2src/mm2_core/src/mm_ctx.rs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/mm2src/mm2_core/src/mm_ctx.rs b/mm2src/mm2_core/src/mm_ctx.rs index 265a0e2066..e11a85bd0a 100644 --- a/mm2src/mm2_core/src/mm_ctx.rs +++ b/mm2src/mm2_core/src/mm_ctx.rs @@ -368,10 +368,13 @@ impl MmCtx { /// /// Use this directory for data related to a specific address and only that specific address (e.g. swap data, order data, etc...). /// This makes sure that when this address is activated using a different technique, this data is still accessible. - #[cfg(all(feature = "new-db-arch", not(target_arch = "wasm32")))] + #[cfg(not(target_arch = "wasm32"))] pub fn address_dir(&self, address: &str) -> Result { + if cfg!(not(feature = "new-db-arch")) { + return Ok(self.dbdir()); + } let path = self.db_root().join("addresses").join(address); - if !path.exists() { + if !path.exists() || !path.is_dir() { std::fs::create_dir_all(&path).map_err(AddressDataError::CreateAddressDirFailure)?; } Ok(path) @@ -533,7 +536,8 @@ impl Drop for MmCtx { } } -#[cfg(all(feature = "new-db-arch", not(target_arch = "wasm32")))] +#[cfg(not(target_arch = "wasm32"))] +#[derive(Debug)] pub enum AddressDataError { CreateAddressDirFailure(std::io::Error), SqliteConnectionFailure(db_common::sqlite::rusqlite::Error), From 8d48284ee0a88f499db470e61aaab1414ac69a67 Mon Sep 17 00:00:00 2001 From: Omer Yacine Date: Thu, 20 Mar 2025 12:09:14 +0200 Subject: [PATCH 03/50] replace dbdir with address_dir in eth/erc20 traces path address available and easy to swap funcs --- mm2src/coins/eth.rs | 33 +++++++++++++++++++++------------ 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/mm2src/coins/eth.rs b/mm2src/coins/eth.rs index 63d2045bde..3666ef045a 100644 --- a/mm2src/coins/eth.rs +++ b/mm2src/coins/eth.rs @@ -129,6 +129,7 @@ use super::{coin_conf, lp_coinfind_or_err, AsyncMutex, BalanceError, BalanceFut, pub use rlp; cfg_native! { use std::path::PathBuf; + use mm2_core::mm_ctx::AddressDataError; } pub mod eth_balance_events; @@ -912,16 +913,19 @@ macro_rules! tx_type_from_pay_for_gas_option { impl EthCoinImpl { #[cfg(not(target_arch = "wasm32"))] - fn eth_traces_path(&self, ctx: &MmArc, my_address: Address) -> PathBuf { - ctx.dbdir() + fn eth_traces_path(&self, ctx: &MmArc, my_address: Address) -> Result { + let path = ctx + .address_dir(&my_address.addr_to_string())? .join("TRANSACTIONS") - .join(format!("{}_{:#02x}_trace.json", self.ticker, my_address)) + .join(format!("{}_{:#02x}_trace.json", self.ticker, my_address)); + Ok(path) } /// Load saved ETH traces from local DB #[cfg(not(target_arch = "wasm32"))] fn load_saved_traces(&self, ctx: &MmArc, my_address: Address) -> Option { - let content = gstuff::slurp(&self.eth_traces_path(ctx, my_address)); + let path = self.eth_traces_path(ctx, my_address).ok()?; + let content = gstuff::slurp(&path); if content.is_empty() { None } else { @@ -943,9 +947,10 @@ impl EthCoinImpl { #[cfg(not(target_arch = "wasm32"))] fn store_eth_traces(&self, ctx: &MmArc, my_address: Address, traces: &SavedTraces) { let content = json::to_vec(traces).unwrap(); - let tmp_file = format!("{}.tmp", self.eth_traces_path(ctx, my_address).display()); + let path = self.eth_traces_path(ctx, my_address).unwrap(); + let tmp_file = format!("{}.tmp", path.display()); std::fs::write(&tmp_file, content).unwrap(); - std::fs::rename(tmp_file, self.eth_traces_path(ctx, my_address)).unwrap(); + std::fs::rename(tmp_file, path).unwrap(); } /// Store ETH traces to local DB @@ -956,19 +961,22 @@ impl EthCoinImpl { } #[cfg(not(target_arch = "wasm32"))] - fn erc20_events_path(&self, ctx: &MmArc, my_address: Address) -> PathBuf { - ctx.dbdir() + fn erc20_events_path(&self, ctx: &MmArc, my_address: Address) -> Result { + let path = ctx + .address_dir(&my_address.addr_to_string())? .join("TRANSACTIONS") - .join(format!("{}_{:#02x}_events.json", self.ticker, my_address)) + .join(format!("{}_{:#02x}_events.json", self.ticker, my_address)); + Ok(path) } /// Store ERC20 events to local DB #[cfg(not(target_arch = "wasm32"))] fn store_erc20_events(&self, ctx: &MmArc, my_address: Address, events: &SavedErc20Events) { let content = json::to_vec(events).unwrap(); - let tmp_file = format!("{}.tmp", self.erc20_events_path(ctx, my_address).display()); + let path = self.erc20_events_path(ctx, my_address).unwrap(); + let tmp_file = format!("{}.tmp", path.display()); std::fs::write(&tmp_file, content).unwrap(); - std::fs::rename(tmp_file, self.erc20_events_path(ctx, my_address)).unwrap(); + std::fs::rename(tmp_file, path).unwrap(); } /// Store ERC20 events to local DB @@ -981,7 +989,8 @@ impl EthCoinImpl { /// Load saved ERC20 events from local DB #[cfg(not(target_arch = "wasm32"))] fn load_saved_erc20_events(&self, ctx: &MmArc, my_address: Address) -> Option { - let content = gstuff::slurp(&self.erc20_events_path(ctx, my_address)); + let path = self.erc20_events_path(ctx, my_address).ok()?; + let content = gstuff::slurp(&path); if content.is_empty() { None } else { From fa5134b53bd9463e945951927cfee64d353695d4 Mon Sep 17 00:00:00 2001 From: Omer Yacine Date: Thu, 20 Mar 2025 13:02:53 +0200 Subject: [PATCH 04/50] base the LN data directory and backup directory on address_dir --- mm2src/coins/lightning/ln_utils.rs | 17 +++++++++++------ .../src/lightning_activation.rs | 6 +++++- mm2src/mm2_core/src/mm_ctx.rs | 3 ++- 3 files changed, 18 insertions(+), 8 deletions(-) diff --git a/mm2src/coins/lightning/ln_utils.rs b/mm2src/coins/lightning/ln_utils.rs index 79868908fa..32dad8e5a8 100644 --- a/mm2src/coins/lightning/ln_utils.rs +++ b/mm2src/coins/lightning/ln_utils.rs @@ -18,7 +18,7 @@ use lightning::util::config::UserConfig; use lightning::util::errors::APIError; use lightning::util::ser::ReadableArgs; use lightning_invoice::payment::{Payer, PaymentError as InvoicePaymentError}; -use mm2_core::mm_ctx::MmArc; +use mm2_core::mm_ctx::{AddressDataError, MmArc}; use std::collections::hash_map::Entry; use std::fs::File; use std::path::PathBuf; @@ -54,13 +54,16 @@ impl From for RpcBestBlock { } #[inline] -fn ln_data_dir(ctx: &MmArc, ticker: &str) -> PathBuf { ctx.dbdir().join("LIGHTNING").join(ticker) } +fn ln_data_dir(ctx: &MmArc, platform_coin_address: &str, ticker: &str) -> Result { + ctx.address_dir(platform_coin_address) + .map(|dir| dir.join("LIGHTNING").join(ticker)) +} #[inline] -fn ln_data_backup_dir(ctx: &MmArc, path: Option, ticker: &str) -> Option { +fn ln_data_backup_dir(path: Option, platform_coin_address: &str, ticker: &str) -> Option { path.map(|p| { PathBuf::from(&p) - .join(hex::encode(ctx.rmd160().as_slice())) + .join(platform_coin_address) .join("LIGHTNING") .join(ticker) }) @@ -68,11 +71,13 @@ fn ln_data_backup_dir(ctx: &MmArc, path: Option, ticker: &str) -> Option pub async fn init_persister( ctx: &MmArc, + platform_coin_address: &str, ticker: String, backup_path: Option, ) -> EnableLightningResult> { - let ln_data_dir = ln_data_dir(ctx, &ticker); - let ln_data_backup_dir = ln_data_backup_dir(ctx, backup_path, &ticker); + let ln_data_dir = + ln_data_dir(ctx, platform_coin_address, &ticker).map_err(|e| EnableLightningError::IOError(e.to_string()))?; + let ln_data_backup_dir = ln_data_backup_dir(backup_path, platform_coin_address, &ticker); let persister = Arc::new(LightningFilesystemPersister::new(ln_data_dir, ln_data_backup_dir)); let is_initialized = persister.is_fs_initialized().await?; diff --git a/mm2src/coins_activation/src/lightning_activation.rs b/mm2src/coins_activation/src/lightning_activation.rs index 1d2f9ec232..e7fa794496 100644 --- a/mm2src/coins_activation/src/lightning_activation.rs +++ b/mm2src/coins_activation/src/lightning_activation.rs @@ -350,8 +350,12 @@ async fn start_lightning( // Initialize the Logger let logger = ctx.log.0.clone(); + // FIXME: Should we use the platform coin's address or the lightning node's address (my_node_id)? + let platform_coin_address = platform_coin + .my_address() + .map_err(|e| EnableLightningError::Internal(format!("Error while getting platform coin address: {:?}", e)))?; // Initialize Persister - let persister = init_persister(ctx, conf.ticker.clone(), params.backup_path).await?; + let persister = init_persister(ctx, &platform_coin_address, conf.ticker.clone(), params.backup_path).await?; // Initialize the KeysManager let keys_manager = init_keys_manager(&platform)?; diff --git a/mm2src/mm2_core/src/mm_ctx.rs b/mm2src/mm2_core/src/mm_ctx.rs index e11a85bd0a..85ea67065b 100644 --- a/mm2src/mm2_core/src/mm_ctx.rs +++ b/mm2src/mm2_core/src/mm_ctx.rs @@ -38,6 +38,7 @@ cfg_native! { use mm2_metrics::MmMetricsError; use std::net::{IpAddr, SocketAddr, AddrParseError}; use std::path::{Path, PathBuf}; + use derive_more::Display; use std::sync::MutexGuard; } @@ -537,7 +538,7 @@ impl Drop for MmCtx { } #[cfg(not(target_arch = "wasm32"))] -#[derive(Debug)] +#[derive(Debug, Display)] pub enum AddressDataError { CreateAddressDirFailure(std::io::Error), SqliteConnectionFailure(db_common::sqlite::rusqlite::Error), From 74b9ecbedc8dba4ea4b89715339eef1043c3e93d Mon Sep 17 00:00:00 2001 From: Omer Yacine Date: Thu, 20 Mar 2025 13:15:26 +0200 Subject: [PATCH 05/50] let MmCtx::address_db() default back to Ctx::sqlite_connection based on compilation features --- mm2src/mm2_core/src/mm_ctx.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mm2src/mm2_core/src/mm_ctx.rs b/mm2src/mm2_core/src/mm_ctx.rs index 85ea67065b..074dc876a7 100644 --- a/mm2src/mm2_core/src/mm_ctx.rs +++ b/mm2src/mm2_core/src/mm_ctx.rs @@ -400,7 +400,7 @@ impl MmCtx { } /// Returns a SQL connection to the address database. - #[cfg(all(feature = "new-db-arch", not(target_arch = "wasm32")))] + #[cfg(not(target_arch = "wasm32"))] pub fn address_db(&self, address: &str) -> Result { let path = self.address_dir(address)?.join("MM2.db"); log_sqlite_file_open_attempt(&path); From 1e024d4a7a593a53673c83a876c13183a990fb08 Mon Sep 17 00:00:00 2001 From: Omer Yacine Date: Thu, 20 Mar 2025 13:21:40 +0200 Subject: [PATCH 06/50] use the address_db for LN sqlite DB --- mm2src/coins/lightning/ln_utils.rs | 21 +++++++++---------- .../src/lightning_activation.rs | 2 +- 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/mm2src/coins/lightning/ln_utils.rs b/mm2src/coins/lightning/ln_utils.rs index 32dad8e5a8..f0c08e9bb0 100644 --- a/mm2src/coins/lightning/ln_utils.rs +++ b/mm2src/coins/lightning/ln_utils.rs @@ -22,7 +22,7 @@ use mm2_core::mm_ctx::{AddressDataError, MmArc}; use std::collections::hash_map::Entry; use std::fs::File; use std::path::PathBuf; -use std::sync::Arc; +use std::sync::{Arc, Mutex}; pub const PAYMENT_RETRY_ATTEMPTS: usize = 5; @@ -88,16 +88,15 @@ pub async fn init_persister( Ok(persister) } -pub async fn init_db(ctx: &MmArc, ticker: String) -> EnableLightningResult { - let db = SqliteLightningDB::new( - ticker, - ctx.sqlite_connection - .get() - .ok_or(MmError::new(EnableLightningError::DbError( - "sqlite_connection is not initialized".into(), - )))? - .clone(), - )?; +pub async fn init_db( + ctx: &MmArc, + platform_coin_address: &str, + ticker: String, +) -> EnableLightningResult { + let conn = ctx + .address_db(platform_coin_address) + .map_err(|e| EnableLightningError::IOError(e.to_string()))?; + let db = SqliteLightningDB::new(ticker, Arc::new(Mutex::new(conn)))?; if !db.is_db_initialized().await? { db.init_db().await?; diff --git a/mm2src/coins_activation/src/lightning_activation.rs b/mm2src/coins_activation/src/lightning_activation.rs index e7fa794496..d548518e72 100644 --- a/mm2src/coins_activation/src/lightning_activation.rs +++ b/mm2src/coins_activation/src/lightning_activation.rs @@ -375,7 +375,7 @@ async fn start_lightning( )); // Initialize DB - let db = init_db(ctx, conf.ticker.clone()).await?; + let db = init_db(ctx, &platform_coin_address, conf.ticker.clone()).await?; // Initialize the ChannelManager task_handle.update_in_progress_status(LightningInProgressStatus::InitializingChannelManager)?; From 6149dbcd83359133c2ab20604803f0b3e83bda04 Mon Sep 17 00:00:00 2001 From: Omer Yacine Date: Thu, 20 Mar 2025 15:13:51 +0200 Subject: [PATCH 07/50] put tx cache in proper address directory also fixes non-set own script pubkey for recently spent output tracking on trezor --- mm2src/coins/qrc20.rs | 14 ++++-- .../utxo/utxo_builder/utxo_coin_builder.rs | 46 ++++++++++++------- 2 files changed, 41 insertions(+), 19 deletions(-) diff --git a/mm2src/coins/qrc20.rs b/mm2src/coins/qrc20.rs index 3049a56ec2..0b96e5db69 100644 --- a/mm2src/coins/qrc20.rs +++ b/mm2src/coins/qrc20.rs @@ -59,6 +59,10 @@ use std::str::FromStr; use std::sync::Arc; use utxo_signer::with_key_pair::{sign_tx, UtxoSignWithKeyPairError}; +cfg_native! { + use mm2_core::mm_ctx::AddressDataError; +} + mod history; #[cfg(test)] mod qrc20_tests; pub mod rpc_clients; @@ -258,9 +262,13 @@ impl<'a> UtxoCoinBuilderCommonOps for Qrc20CoinBuilder<'a> { /// Please note the method is overridden for Native mode only. #[inline] #[cfg(not(target_arch = "wasm32"))] - fn tx_cache(&self) -> UtxoVerboseCacheShared { - crate::utxo::tx_cache::fs_tx_cache::FsVerboseCache::new(self.platform.clone(), self.tx_cache_path()) - .into_shared() + fn tx_cache(&self, my_address: &UtxoAddress) -> Result { + let tx_cache = crate::utxo::tx_cache::fs_tx_cache::FsVerboseCache::new( + self.platform.clone(), + self.tx_cache_path(my_address)?, + ) + .into_shared(); + Ok(tx_cache) } } diff --git a/mm2src/coins/utxo/utxo_builder/utxo_coin_builder.rs b/mm2src/coins/utxo/utxo_builder/utxo_coin_builder.rs index b916afc232..4c91251b7f 100644 --- a/mm2src/coins/utxo/utxo_builder/utxo_coin_builder.rs +++ b/mm2src/coins/utxo/utxo_builder/utxo_coin_builder.rs @@ -1,4 +1,4 @@ -use crate::hd_wallet::{load_hd_accounts_from_storage, HDAccountsMutex, HDWallet, HDWalletCoinStorage, +use crate::hd_wallet::{load_hd_accounts_from_storage, HDAccountsMutex, HDWallet, HDWalletCoinStorage, HDWalletOps, HDWalletStorageError, DEFAULT_GAP_LIMIT}; use crate::utxo::rpc_clients::{ElectrumClient, ElectrumClientSettings, ElectrumConnectionSettings, EstimateFeeMethod, UtxoRpcClientEnum}; @@ -19,7 +19,6 @@ use derive_more::Display; use futures::channel::mpsc::{channel, Receiver as AsyncReceiver}; use futures::compat::Future01CompatExt; use futures::lock::Mutex as AsyncMutex; -use keys::bytes::Bytes; pub use keys::{Address, AddressBuilder, AddressFormat as UtxoAddressFormat, AddressHashEnum, AddressScriptType, KeyPair, Private, Public, Secret}; use mm2_core::mm_ctx::MmArc; @@ -37,6 +36,7 @@ cfg_native! { use dirs::home_dir; use std::path::{Path, PathBuf}; use std::sync::Arc; + use mm2_core::mm_ctx::AddressDataError; } /// Number of seconds in a day (24 hours * 60 * 60) @@ -114,6 +114,11 @@ impl From for UtxoCoinBuildError { fn from(e: keys::Error) -> Self { UtxoCoinBuildError::Internal(e.to_string()) } } +#[cfg(not(target_arch = "wasm32"))] +impl From for UtxoCoinBuildError { + fn from(e: AddressDataError) -> Self { UtxoCoinBuildError::Internal(e.to_string()) } +} + #[async_trait] pub trait UtxoCoinBuilder: UtxoFieldsWithIguanaSecretBuilder + UtxoFieldsWithGlobalHDBuilder + UtxoFieldsWithHardwareWalletBuilder @@ -261,7 +266,7 @@ where let initial_history_state = builder.initial_history_state(); let tx_hash_algo = builder.tx_hash_algo(); let check_utxo_maturity = builder.check_utxo_maturity(); - let tx_cache = builder.tx_cache(); + let tx_cache = builder.tx_cache(&my_address)?; let (block_headers_status_notifier, block_headers_status_watcher) = builder.block_header_status_channel(&conf.spv_conf); @@ -298,11 +303,6 @@ pub trait UtxoFieldsWithHardwareWalletBuilder: UtxoCoinBuilderCommonOps { } let hd_wallet_rmd160 = self.trezor_wallet_rmd160()?; - // For now, use a default script pubkey. - // TODO change the type of `recently_spent_outpoints` to `AsyncMutex>` - let my_script_pubkey = Bytes::new(); - let recently_spent_outpoints = AsyncMutex::new(RecentlySpentOutPoints::new(my_script_pubkey)); - let address_format = self.address_format()?; let path_to_coin = conf .derivation_path @@ -339,7 +339,13 @@ pub trait UtxoFieldsWithHardwareWalletBuilder: UtxoCoinBuilderCommonOps { let initial_history_state = self.initial_history_state(); let tx_hash_algo = self.tx_hash_algo(); let check_utxo_maturity = self.check_utxo_maturity(); - let tx_cache = self.tx_cache(); + // FIXME: IS THIS CORRECT? DID WE GET THE CORRECT ADDRESS? + let my_address = hd_wallet + .get_enabled_address() + .await + .ok_or_else(|| UtxoCoinBuildError::Internal("Failed to get enabled address from HD wallet".to_owned()))?; + let my_script_pubkey = output_script(&my_address.address).map(|script| script.to_bytes())?; + let tx_cache = self.tx_cache(&my_address.address)?; let (block_headers_status_notifier, block_headers_status_watcher) = self.block_header_status_channel(&conf.spv_conf); @@ -352,7 +358,7 @@ pub trait UtxoFieldsWithHardwareWalletBuilder: UtxoCoinBuilderCommonOps { derivation_method: DerivationMethod::HDWallet(hd_wallet), history_sync_state: Mutex::new(initial_history_state), tx_cache, - recently_spent_outpoints, + recently_spent_outpoints: AsyncMutex::new(RecentlySpentOutPoints::new(my_script_pubkey)), tx_fee, tx_hash_algo, check_utxo_maturity, @@ -669,19 +675,27 @@ pub trait UtxoCoinBuilderCommonOps { } #[cfg(target_arch = "wasm32")] - fn tx_cache(&self) -> UtxoVerboseCacheShared { + fn tx_cache(&self, _my_address: &Address) -> Result { #[allow(clippy::default_constructed_unit_structs)] // This is a false-possitive bug from clippy - crate::utxo::tx_cache::wasm_tx_cache::WasmVerboseCache::default().into_shared() + Ok(crate::utxo::tx_cache::wasm_tx_cache::WasmVerboseCache::default().into_shared()) } #[cfg(not(target_arch = "wasm32"))] - fn tx_cache(&self) -> UtxoVerboseCacheShared { - crate::utxo::tx_cache::fs_tx_cache::FsVerboseCache::new(self.ticker().to_owned(), self.tx_cache_path()) - .into_shared() + fn tx_cache(&self, my_address: &Address) -> Result { + let tx_cache = crate::utxo::tx_cache::fs_tx_cache::FsVerboseCache::new( + self.ticker().to_owned(), + self.tx_cache_path(my_address)?, + ) + .into_shared(); + Ok(tx_cache) } #[cfg(not(target_arch = "wasm32"))] - fn tx_cache_path(&self) -> PathBuf { self.ctx().dbdir().join("TX_CACHE") } + fn tx_cache_path(&self, my_address: &Address) -> Result { + self.ctx() + .address_dir(&my_address.to_string()) + .map(|dir| dir.join("TX_CACHE")) + } fn block_header_status_channel( &self, From d96d8db372f14a4ca74c8d05cd127480d6a84e6f Mon Sep 17 00:00:00 2001 From: Omer Yacine Date: Mon, 24 Mar 2025 16:04:43 +0200 Subject: [PATCH 08/50] use correct address dirs for wallet and cache dbs for zcoin the gist of this commit is moving my_z_addr calcuations to ZCoinBuilder::new instead of ZCoinBuilder::build. this makes it so we can have a `my_z_addr_encoded` field in the builder, and we can use it to find the db path for wallet and cache dbs --- mm2src/coins/z_coin.rs | 93 ++++++++++--------- .../storage/walletdb/wallet_sql_storage.rs | 6 +- 2 files changed, 52 insertions(+), 47 deletions(-) diff --git a/mm2src/coins/z_coin.rs b/mm2src/coins/z_coin.rs index 880c60f90d..5d7f2b53b9 100644 --- a/mm2src/coins/z_coin.rs +++ b/mm2src/coins/z_coin.rs @@ -830,10 +830,6 @@ pub async fn z_coin_from_conf_and_params( protocol_info: ZcoinProtocolInfo, priv_key_policy: PrivKeyBuildPolicy, ) -> Result> { - #[cfg(target_arch = "wasm32")] - let db_dir_path = PathBuf::new(); - #[cfg(not(target_arch = "wasm32"))] - let db_dir_path = ctx.dbdir(); let z_spending_key = None; let builder = ZCoinBuilder::new( ctx, @@ -841,10 +837,9 @@ pub async fn z_coin_from_conf_and_params( conf, params, priv_key_policy, - db_dir_path, z_spending_key, protocol_info, - ); + )?; builder.build().await } @@ -876,10 +871,9 @@ pub struct ZCoinBuilder<'a> { z_coin_params: &'a ZcoinActivationParams, utxo_params: UtxoActivationParams, priv_key_policy: PrivKeyBuildPolicy, - #[cfg_attr(target_arch = "wasm32", allow(unused))] - db_dir_path: PathBuf, - /// `Some` if `ZCoin` should be initialized with a forced spending key. - z_spending_key: Option, + z_spending_key: ExtendedSpendingKey, + my_z_addr: PaymentAddress, + my_z_addr_encoded: String, protocol_info: ZcoinProtocolInfo, } @@ -912,19 +906,6 @@ impl<'a> UtxoCoinBuilder for ZCoinBuilder<'a> { let utxo = self.build_utxo_fields().await?; let utxo_arc = UtxoArc::new(utxo); - let z_spending_key = match self.z_spending_key { - Some(ref z_spending_key) => z_spending_key.clone(), - None => extended_spending_key_from_protocol_info_and_policy( - &self.protocol_info, - &self.priv_key_policy, - self.z_coin_params.account, - )?, - }; - - let (_, my_z_addr) = z_spending_key - .default_address() - .map_err(|_| MmError::new(ZCoinBuildError::GetAddressError))?; - let dex_fee_addr = decode_payment_address( self.protocol_info.consensus_params.hrp_sapling_payment_address(), DEX_FEE_Z_ADDR, @@ -940,17 +921,12 @@ impl<'a> UtxoCoinBuilder for ZCoinBuilder<'a> { .expect("DEX_BURN_Z_ADDR is a valid z-address"); let z_tx_prover = self.z_tx_prover().await?; - let my_z_addr_encoded = encode_payment_address( - self.protocol_info.consensus_params.hrp_sapling_payment_address(), - &my_z_addr, - ); - let blocks_db = self.init_blocks_db().await?; let (sync_state_connector, light_wallet_db) = match &self.z_coin_params.mode { #[cfg(not(target_arch = "wasm32"))] ZcoinRpcMode::Native => { - init_native_client(&self, self.native_client()?, blocks_db, &z_spending_key).await? + init_native_client(&self, self.native_client()?, blocks_db, &self.z_spending_key).await? }, ZcoinRpcMode::Light { light_wallet_d_servers, @@ -964,7 +940,7 @@ impl<'a> UtxoCoinBuilder for ZCoinBuilder<'a> { blocks_db, sync_params, skip_sync_params.unwrap_or_default(), - &z_spending_key, + &self.z_spending_key, ) .await? }, @@ -973,10 +949,10 @@ impl<'a> UtxoCoinBuilder for ZCoinBuilder<'a> { let z_fields = Arc::new(ZCoinFields { dex_fee_addr, dex_burn_addr, - my_z_addr, - my_z_addr_encoded, - evk: ExtendedFullViewingKey::from(&z_spending_key), - z_spending_key, + my_z_addr: self.my_z_addr, + my_z_addr_encoded: self.my_z_addr_encoded, + evk: ExtendedFullViewingKey::from(&self.z_spending_key), + z_spending_key: self.z_spending_key, z_tx_prover: Arc::new(z_tx_prover), light_wallet_db, consensus_params: self.protocol_info.consensus_params, @@ -995,10 +971,9 @@ impl<'a> ZCoinBuilder<'a> { conf: &'a Json, z_coin_params: &'a ZcoinActivationParams, priv_key_policy: PrivKeyBuildPolicy, - db_dir_path: PathBuf, z_spending_key: Option, protocol_info: ZcoinProtocolInfo, - ) -> ZCoinBuilder<'a> { + ) -> MmResult, ZCoinBuildError> { let utxo_mode = match &z_coin_params.mode { #[cfg(not(target_arch = "wasm32"))] ZcoinRpcMode::Native => UtxoRpcMode::Native, @@ -1027,27 +1002,54 @@ impl<'a> ZCoinBuilder<'a> { // This is not used for Zcoin so we just provide a default value path_to_address: HDPathAccountToAddressId::default(), }; - ZCoinBuilder { + + let z_spending_key = match z_spending_key { + Some(ref z_spending_key) => z_spending_key.clone(), + None => extended_spending_key_from_protocol_info_and_policy( + &protocol_info, + &priv_key_policy, + z_coin_params.account, + )?, + }; + + let (_, my_z_addr) = z_spending_key + .default_address() + .map_err(|_| MmError::new(ZCoinBuildError::GetAddressError))?; + + let my_z_addr_encoded = + encode_payment_address(protocol_info.consensus_params.hrp_sapling_payment_address(), &my_z_addr); + + Ok(ZCoinBuilder { ctx, ticker, conf, z_coin_params, utxo_params, priv_key_policy, - db_dir_path, z_spending_key, + my_z_addr, + my_z_addr_encoded, protocol_info, - } + }) } async fn init_blocks_db(&self) -> Result> { - let cache_db_path = self.db_dir_path.join(format!("{}_cache.db", self.ticker)); - let ctx = self.ctx.clone(); + let ctx = &self.ctx; let ticker = self.ticker.to_string(); - BlockDbImpl::new(&ctx, ticker, cache_db_path) - .map_err(|err| MmError::new(ZcoinClientInitError::ZcoinStorageError(err.to_string()))) - .await + #[cfg(not(target_arch = "wasm32"))] + let blocks_db = { + let cache_db_path = self + .ctx + .address_dir(&self.my_z_addr_encoded) + .map_err(|e| ZcoinClientInitError::ZcoinStorageError(e.to_string()))? + .join(format!("{}_cache.db", self.ticker)); + BlockDbImpl::new(ctx, ticker, cache_db_path).await + }; + #[cfg(target_arch = "wasm32")] + let blocks_db = BlockDbImpl::new(ctx, ticker, PathBuf::new()).await; + + blocks_db.map_err(|err| MmError::new(ZcoinClientInitError::ZcoinStorageError(err.to_string()))) } #[cfg(not(target_arch = "wasm32"))] @@ -1117,10 +1119,9 @@ async fn z_coin_from_conf_and_params_with_z_key( conf, params, priv_key_policy, - db_dir_path, Some(z_spending_key), protocol_info, - ); + )?; println!("ZOMBIE_wallet.db will be synch'ed with the chain, this may take a while for the first time."); println!("You may also run prepare_zombie_sapling_cache test to update ZOMBIE_wallet.db before running tests."); diff --git a/mm2src/coins/z_coin/storage/walletdb/wallet_sql_storage.rs b/mm2src/coins/z_coin/storage/walletdb/wallet_sql_storage.rs index 3a957d375f..d3175dc319 100644 --- a/mm2src/coins/z_coin/storage/walletdb/wallet_sql_storage.rs +++ b/mm2src/coins/z_coin/storage/walletdb/wallet_sql_storage.rs @@ -87,7 +87,11 @@ impl<'a> WalletDbShared { let ticker = builder.ticker; let consensus_params = builder.protocol_info.consensus_params.clone(); let wallet_db = create_wallet_db( - builder.db_dir_path.join(format!("{ticker}_wallet.db")), + builder + .ctx + .address_dir(&builder.my_z_addr_encoded) + .map_err(|e| ZcoinStorageError::DbError(e.to_string()))? + .join(format!("{ticker}_wallet.db")), consensus_params, checkpoint_block, ExtendedFullViewingKey::from(z_spending_key), From 190e6e1c633047eb0b86069bd9f3491836addd07 Mon Sep 17 00:00:00 2001 From: Omer Yacine Date: Mon, 24 Mar 2025 16:08:16 +0200 Subject: [PATCH 09/50] fix clippy for tests remove an unused arg --- mm2src/coins/z_coin.rs | 1 - mm2src/coins/z_coin/z_coin_native_tests.rs | 31 +++++++--------------- 2 files changed, 9 insertions(+), 23 deletions(-) diff --git a/mm2src/coins/z_coin.rs b/mm2src/coins/z_coin.rs index 5d7f2b53b9..8d2154b1b5 100644 --- a/mm2src/coins/z_coin.rs +++ b/mm2src/coins/z_coin.rs @@ -1109,7 +1109,6 @@ async fn z_coin_from_conf_and_params_with_z_key( conf: &Json, params: &ZcoinActivationParams, priv_key_policy: PrivKeyBuildPolicy, - db_dir_path: PathBuf, z_spending_key: ExtendedSpendingKey, protocol_info: ZcoinProtocolInfo, ) -> Result> { diff --git a/mm2src/coins/z_coin/z_coin_native_tests.rs b/mm2src/coins/z_coin/z_coin_native_tests.rs index 4e5ffc4325..892da5401e 100644 --- a/mm2src/coins/z_coin/z_coin_native_tests.rs +++ b/mm2src/coins/z_coin/z_coin_native_tests.rs @@ -26,7 +26,6 @@ use bitcrypto::dhash160; use common::{block_on, now_sec}; use mm2_core::mm_ctx::MmCtxBuilder; use mm2_test_helpers::for_tests::zombie_conf; -use std::path::PathBuf; use std::time::Duration; use zcash_client_backend::encoding::decode_extended_spending_key; @@ -50,7 +49,6 @@ async fn zombie_coin_send_and_refund_maker_payment() { let mut conf = zombie_conf(); let params = native_zcoin_activation_params(); let pk_data = [1; 32]; - let db_dir = PathBuf::from("./for_tests"); let z_key = decode_extended_spending_key(z_mainnet_constants::HRP_SAPLING_EXTENDED_SPENDING_KEY, "secret-extended-key-main1q0k2ga2cqqqqpq8m8j6yl0say83cagrqp53zqz54w38ezs8ly9ly5ptamqwfpq85u87w0df4k8t2lwyde3n9v0gcr69nu4ryv60t0kfcsvkr8h83skwqex2nf0vr32794fmzk89cpmjptzc22lgu5wfhhp8lgf3f5vn2l3sge0udvxnm95k6dtxj2jwlfyccnum7nz297ecyhmd5ph526pxndww0rqq0qly84l635mec0x4yedf95hzn6kcgq8yxts26k98j9g32kjc8y83fe").unwrap().unwrap(); let protocol_info = match serde_json::from_value::(conf["protocol"].take()).unwrap() { CoinProtocol::ZHTLC(protocol_info) => protocol_info, @@ -63,7 +61,6 @@ async fn zombie_coin_send_and_refund_maker_payment() { &conf, ¶ms, PrivKeyBuildPolicy::IguanaPrivKey(pk_data.into()), - db_dir, z_key, protocol_info, ) @@ -115,7 +112,6 @@ async fn zombie_coin_send_and_spend_maker_payment() { let mut conf = zombie_conf(); let params = native_zcoin_activation_params(); let pk_data = [1; 32]; - let db_dir = PathBuf::from("./for_tests"); let z_key = decode_extended_spending_key(z_mainnet_constants::HRP_SAPLING_EXTENDED_SPENDING_KEY, "secret-extended-key-main1q0k2ga2cqqqqpq8m8j6yl0say83cagrqp53zqz54w38ezs8ly9ly5ptamqwfpq85u87w0df4k8t2lwyde3n9v0gcr69nu4ryv60t0kfcsvkr8h83skwqex2nf0vr32794fmzk89cpmjptzc22lgu5wfhhp8lgf3f5vn2l3sge0udvxnm95k6dtxj2jwlfyccnum7nz297ecyhmd5ph526pxndww0rqq0qly84l635mec0x4yedf95hzn6kcgq8yxts26k98j9g32kjc8y83fe").unwrap().unwrap(); let protocol_info = match serde_json::from_value::(conf["protocol"].take()).unwrap() { CoinProtocol::ZHTLC(protocol_info) => protocol_info, @@ -128,7 +124,6 @@ async fn zombie_coin_send_and_spend_maker_payment() { &conf, ¶ms, PrivKeyBuildPolicy::IguanaPrivKey(pk_data.into()), - db_dir, z_key, protocol_info, ) @@ -184,17 +179,15 @@ async fn zombie_coin_send_dex_fee() { let mut conf = zombie_conf(); let params = native_zcoin_activation_params(); let priv_key = PrivKeyBuildPolicy::IguanaPrivKey([1; 32].into()); - let db_dir = PathBuf::from("./for_tests"); let z_key = decode_extended_spending_key(z_mainnet_constants::HRP_SAPLING_EXTENDED_SPENDING_KEY, "secret-extended-key-main1q0k2ga2cqqqqpq8m8j6yl0say83cagrqp53zqz54w38ezs8ly9ly5ptamqwfpq85u87w0df4k8t2lwyde3n9v0gcr69nu4ryv60t0kfcsvkr8h83skwqex2nf0vr32794fmzk89cpmjptzc22lgu5wfhhp8lgf3f5vn2l3sge0udvxnm95k6dtxj2jwlfyccnum7nz297ecyhmd5ph526pxndww0rqq0qly84l635mec0x4yedf95hzn6kcgq8yxts26k98j9g32kjc8y83fe").unwrap().unwrap(); let protocol_info = match serde_json::from_value::(conf["protocol"].take()).unwrap() { CoinProtocol::ZHTLC(protocol_info) => protocol_info, other_protocol => panic!("Failed to get protocol from config: {:?}", other_protocol), }; - let coin = - z_coin_from_conf_and_params_with_z_key(&ctx, "ZOMBIE", &conf, ¶ms, priv_key, db_dir, z_key, protocol_info) - .await - .unwrap(); + let coin = z_coin_from_conf_and_params_with_z_key(&ctx, "ZOMBIE", &conf, ¶ms, priv_key, z_key, protocol_info) + .await + .unwrap(); let dex_fee = DexFee::WithBurn { fee_amount: "0.0075".into(), @@ -211,17 +204,15 @@ async fn zombie_coin_send_standard_dex_fee() { let mut conf = zombie_conf(); let params = native_zcoin_activation_params(); let priv_key = PrivKeyBuildPolicy::IguanaPrivKey([1; 32].into()); - let db_dir = PathBuf::from("./for_tests"); let z_key = decode_extended_spending_key(z_mainnet_constants::HRP_SAPLING_EXTENDED_SPENDING_KEY, "secret-extended-key-main1q0k2ga2cqqqqpq8m8j6yl0say83cagrqp53zqz54w38ezs8ly9ly5ptamqwfpq85u87w0df4k8t2lwyde3n9v0gcr69nu4ryv60t0kfcsvkr8h83skwqex2nf0vr32794fmzk89cpmjptzc22lgu5wfhhp8lgf3f5vn2l3sge0udvxnm95k6dtxj2jwlfyccnum7nz297ecyhmd5ph526pxndww0rqq0qly84l635mec0x4yedf95hzn6kcgq8yxts26k98j9g32kjc8y83fe").unwrap().unwrap(); let protocol_info = match serde_json::from_value::(conf["protocol"].take()).unwrap() { CoinProtocol::ZHTLC(protocol_info) => protocol_info, other_protocol => panic!("Failed to get protocol from config: {:?}", other_protocol), }; - let coin = - z_coin_from_conf_and_params_with_z_key(&ctx, "ZOMBIE", &conf, ¶ms, priv_key, db_dir, z_key, protocol_info) - .await - .unwrap(); + let coin = z_coin_from_conf_and_params_with_z_key(&ctx, "ZOMBIE", &conf, ¶ms, priv_key, z_key, protocol_info) + .await + .unwrap(); let dex_fee = DexFee::Standard("0.01".into()); let tx = z_send_dex_fee(&coin, dex_fee, &[1; 16]).await.unwrap(); @@ -235,7 +226,6 @@ fn prepare_zombie_sapling_cache() { let mut conf = zombie_conf(); let params = native_zcoin_activation_params(); let priv_key = PrivKeyBuildPolicy::IguanaPrivKey([1; 32].into()); - let db_dir = PathBuf::from("./for_tests"); let z_key = decode_extended_spending_key(z_mainnet_constants::HRP_SAPLING_EXTENDED_SPENDING_KEY, "secret-extended-key-main1q0k2ga2cqqqqpq8m8j6yl0say83cagrqp53zqz54w38ezs8ly9ly5ptamqwfpq85u87w0df4k8t2lwyde3n9v0gcr69nu4ryv60t0kfcsvkr8h83skwqex2nf0vr32794fmzk89cpmjptzc22lgu5wfhhp8lgf3f5vn2l3sge0udvxnm95k6dtxj2jwlfyccnum7nz297ecyhmd5ph526pxndww0rqq0qly84l635mec0x4yedf95hzn6kcgq8yxts26k98j9g32kjc8y83fe").unwrap().unwrap(); let protocol_info = match serde_json::from_value::(conf["protocol"].take()).unwrap() { CoinProtocol::ZHTLC(protocol_info) => protocol_info, @@ -248,7 +238,6 @@ fn prepare_zombie_sapling_cache() { &conf, ¶ms, priv_key, - db_dir, z_key, protocol_info, )) @@ -265,17 +254,15 @@ async fn zombie_coin_validate_dex_fee() { let mut conf = zombie_conf(); let params = native_zcoin_activation_params(); let priv_key = PrivKeyBuildPolicy::IguanaPrivKey([1; 32].into()); - let db_dir = PathBuf::from("./for_tests"); let z_key = decode_extended_spending_key(z_mainnet_constants::HRP_SAPLING_EXTENDED_SPENDING_KEY, "secret-extended-key-main1q0k2ga2cqqqqpq8m8j6yl0say83cagrqp53zqz54w38ezs8ly9ly5ptamqwfpq85u87w0df4k8t2lwyde3n9v0gcr69nu4ryv60t0kfcsvkr8h83skwqex2nf0vr32794fmzk89cpmjptzc22lgu5wfhhp8lgf3f5vn2l3sge0udvxnm95k6dtxj2jwlfyccnum7nz297ecyhmd5ph526pxndww0rqq0qly84l635mec0x4yedf95hzn6kcgq8yxts26k98j9g32kjc8y83fe").unwrap().unwrap(); let protocol_info = match serde_json::from_value::(conf["protocol"].take()).unwrap() { CoinProtocol::ZHTLC(protocol_info) => protocol_info, other_protocol => panic!("Failed to get protocol from config: {:?}", other_protocol), }; - let coin = - z_coin_from_conf_and_params_with_z_key(&ctx, "ZOMBIE", &conf, ¶ms, priv_key, db_dir, z_key, protocol_info) - .await - .unwrap(); + let coin = z_coin_from_conf_and_params_with_z_key(&ctx, "ZOMBIE", &conf, ¶ms, priv_key, z_key, protocol_info) + .await + .unwrap(); // https://zombie.explorer.lordofthechains.com/tx/9390a26810342151f48f455b09e5d087a5429cbba08f2381b02c43b76f813e29 let tx_hex = "0400008085202f8900000000000001030c00e8030000000000000169e7017fbd969be53da2c1b8812002baaf59ce98b230a9c1001397ba7f4db8676bd77e8ea644b67067d1f996d8d81c279961343f00a10095bccbddc341c98539287c900cf969688ddc574786e0e34bd6d3ec2ffaab5e2d472848781b116906669786c14c5c608b20dc23c9566fd46861f6a258b5ffc6de73495b56f4823e098c8664eab895d5cd31c013428ae2cbe940dc236ca40465ea2b912ce6c36555b2affb1f38b99b28dc593d865b0b948d567f9315df666d2e65e666d829b9823154bae0410bd885582b4a8a6eb4b9ae214b59ffd9b1167b7cd48f48a11cbd67c08f4e01ed4fd78fc91d0c9e70baa4f25761ef6c78cd7268b307aaa6ece2b443937eb4beac2c8843279a8879adbe0b381e65d0b674f2feeb54b78f80b377f66baab72c4cf9f10dde48f343c001df91a1a6d252ad8eca26eea0fdee49ad7024b505e55b4e082e94616794ddd7c2b852594b4b7af2292f0aa9e34f38322f548f1a21c015e92dbfd239ce18144f3b8045e9efa3de6b4c6b338f01d0adeb26a088a3c8c00503b67b2980b7663e97541e2944e4ad3588554966b6a930d2dc01d9fc7f8a846583fcf3b721f979705eff5bb9bb1fb0cad9ad941ceb3f581710efd8c50713a53751a0a196322ef8618bf1e097383666e91b5133ba81645d2b542181476eba2326cd02fb29a9f09edc46ea04b32ed9243597318d23b955a2570d78cbfb46cc26c1807eddd1de4785b6e752f859f7e25fc67f9e8a00feafac6fd7781eb72a663d9b80c10e9c387abc4d41294b3573785fd53bc56ccac2edf5c7bbb99cb3bcf87161fa893d2e1aabfee75754767cef07a12e44bb707720e727e585a258356cc797ecee8263c0f61cfc8ffa0360c758f1348ac44c186e12ce0f4faad43b4638abd4a0bc9fd4a6fa4352c20cc771241f95c26f1671ca95c8f4a63a8318dc43299f54e8a899df78ccfd3112a0d5ea637847dd2e3b05be8c0658dd0d7d814473fa5369957c00e84df600df23faaee5faa17b9ededad4731e5e9c1099dfddf5264756800dcfcad4b006b736d1d47c59a019acde4dc22249fc40846b77b43294e32a21db745e1bec790324c3d505edc79388a6e44b02841b26306ed48cfce1e941642c30792315016dba03797c8e4e279eec5b78aad602620471f24c25aea3aaa57509aa9eef2057f11bc95bad708918f2f0df74ac179d7dffc772b2c603dd89e7aea0e8f94f1a8bab4a4fba10bf05c88fbe4b021b3faff3d558e32e4bc20be4bed62d653674ce697390e098e590a3e354cb4a1e703474de8aab30cd76cf7e237f2e66bf486c4fc6c22028764e95adf7d8fa018f44b51ae6acfa3bf80f14c45c06623b916d79649abe0a2b229f96e60e421f6e734160da37f01e915cf73d1cacd1eb7f06c26c33b4d8e4dde264f3cfe84bada0601d1c03aa31c5938750ca0b852f3177883cae9f285d582a4eb38c05f8ef6e5cff5be0745e1ec66e20752bfd5bd5a1590fa280ace3e9786e0022e7ae3c48bcca14e9c5513bc8b57e15820a685f8348159862be0579a35d8ac9d1abaf36d9274c7e750fd9ad265c0d8f08c95ed9ce69eef3a55aef05f2d5d601f80f472689f3428e4f0095829a459813d5dace7e6137a752ae5567982e67b2092afeba99561fbe4e716f67bd1b4e8de1f376dec30eed27371bcc42d7de2ea0f4288054618e9afa002a2d1996b7a70a9683229f28bab811b67629dad527f325c0f12e19d92bac51e5924f27048fa118673b52b296b3642ec946d9915ded0ae84e1a2236da65f672bdad75a22cc0ea751c07e56d2ec22caa41afc98ec6b37a8c1b6a5378a81f2cdb2228f4efb8d7f35c0086a955e1b04bd09bd7e056c949fab1805f733a8b2061adad0c2b7fae33d21363de911e517b21a1539dfa1b3cbb1ea0dbfa3ffff23bbac01183f852de41e798fca5a278b711893175aeaded90873574d8de30b360f39ea239492c630eda4a811d3bb7a125054d5ca74bb6698aeea1a417ad19415ca0e5ca36abc2f96725986f73bcbe3113e391010d08f58f05979c7cef26ff92506c5d1eb2a2f6f5689e9a39957f0723bef3262f5190de996234d4f00b73ed74d78fdf1e6bf31161e16bd083bc6fbddc4eba85c17067e15f08019e5ed943de8e23a974d516abc641e85e641b03779816c30b3449a16b142417c1ff93ab7fa8f96a175e9ef73b3f06ac76788c27889d426efa78d5b8ce35be4591902f7766fe579a0aa28229235a920d26264c09625dea807f619a040f08931d6e1fe57ff0c48ea476be93a16d1fc8de3617984eeebcf14b63c839b41f8f9305402d1288c8e481a4fa5c3302bb1f83e3f0dc8ff9550f9bacb44bccb58f3de152abef5d578afed1c29dc89495b9e54a0c6d00f1dba45a2cf68c9512d9a9ff0b2531e58e47428a99cb246ca23f867b660dc71785b57407cc292f735634c602409792c4640831809f1f1e51903273b623aa0ae0cdd335c7b9db360b0bceb0d15f2313e1944800f30f82ed5bb07cfa1c4740c2bf2806539a4afac1f79d779b923ad8dc2493ebb2d2fce9aea58a009d64e7d1b71ca6893b076e41f7e88a4b51b5402e3fa6c60fa65a686adea229f0164318c9fa1b6d2d2218e5ada710daffecb6b7dd8bf7447658795c4c7a0ad710c4f02fd19017a0575f9467600cdca019793f2f49d197dbfc937828e5790b90929e5ca16037ec79734b64feec36b36c220a2979c45dd51e24c9fb21d8634471aac20c6f179f90c0d61c7b3d89826d146b157bedd8f6b66f6edfabfe04b49f2f2d999fc2e578a440bafd524c82ae614dc8017e379cf926e042f4fbd6f0628fde52de18d764ba8385b77569eda30d5a3617fb0a0c7fd26c821308c3ae98498d33b974cb318a04af3ea3fbcb13fc62fc952aaef095423da9ec7bdc7b77adbd403931189ddc98fe19a06711415b40a9a68812bb7c5453b7b2377910c7b89c99b379e038a7940487c0fd2405456ee55ab6ead3ef25a8a5b1abcae479c24f5e6869057e0bdabcdf352b4a64a3e385171a6e14c8102b2a187034e21705e3a457167fe0dc0d63d6e8d489c9a18c9d84b541504d36b086c2c63cc1a34c0080122c5d60ca33ab60289d16f21e1ded753607267c2093b1c587b89da9df65584fbe3ff9eb7f91d64e33912b8e91adc27191d22f8e835be6bb24546f21488f7abcb29339c34058d4f4093096144b17b8ab76a346275b7e7c80bca59d20e0bb482bb2a9cc3c9515cc1b5be17348c65c73e9fb1ed77d423c509f7cff0e355a34d080d310f3b848dbc209bbba6b6b109fb8d9556dca0fab086e197327ab423d5d762b68961244d8d22c30a8a3a116770bb15b5a0a347091a843b68d6a8e0f1c79f12523a7561c1233cd44db90f6cd3c1ce5fc13f8382177b5522aae028379269b71ae2a42f41dff7374ed7e83c89566f57297b82478b04359a2c199ce8f842112b7450cc1e2e2e394cda4c67e0b2302e21f6af997607ceefd067f77be8900bb3ecb3e30782477aa76861b286b9ddc9e36fcebb50f04f9516e02da31e6219bb5bcb81ee673d95be14c1bd2be4909556d6dbca0365292c582dedcafcc60b255ab7bcd9d977a4139f394ca1da81040e784fd8e7534f230bc5201e7f1db47eadc30f37609d5bbaba624157d98d65029bbab766b6c23c3049a32b894c0cfcb40913ba1cd2d5acda7d2acc920fd01c36f28fc6b7ffd01a37b17fc3235d0dbe9b8098530bed6894b288604b8689f4aafc22cdf211fb95ef5c90cae62a250234e6f790e9a15012acac88305dc4f91fd564a9ab8bb27c057ec5dd46fe952a7be557caea9b7b1d6118aa42df79b8c207e2bae6c34d67dc32b4360ad20b3e609e9caeb7f432ad51cfce139f2d4eb9ed219f4323acd5685e0e0409939eb662175a83fa083f500516dbcb091a3448cb24c3198c8fc547fbda3cb0894edeceef7ccb4ad746aa06f4038b63ab4095a9c390656520561ba3763b1057b3af7cb548342a2bfc2ab725b01b12a7adfc30d7d9632acafd2595cde406b8637a911b7c86f7b09b11f58acec3f1a1bd7cf6853331b48d7907ed699d91fbdbcab8001e3d8d3a26b491b6e2d98c5e149847a07a2b7faa1f567cd4bc9c83ad553339632f3dcacb890c5222656b3349ddd5c8eacaa490ac0b2b38f8a26da9ce7789f5601769a7f10b93125cb93b589bda4ddb4e8795817b60cc149af7c0699b2bbbf655f2f5ec170d6af51213e8c725e699d181923ecf10c6f1069f46e6bc89c7a29d2ebe133b5c0c4b67826a93add7d4824e60b4c5f0cee358abedb50c54a59e95185d7a80081f2dddba5c7c7c637b2dfe8575ddaa71306a2725c9ec17b8e4e1f271a442f6798cc21bbd55c2d69819ddde37a8e8d6a812c41a3e58719b7c96e9375155c4a873ed698ad37144ef32e3fe41cce9c48bbe31441dbbeec7b97734769063d6d04cd8d4963f09f7101bf57cb97a83452cc5de873c5ac0ce001c471c9fcd3275d90a118dd4c25a525d9fb358ff85104b98136850786b387fa17cc1a1d128bc5f7c365ec7920ea677e4c8023071a958647d9fbd27e29d7d099b4dfbbac086ac2af00407fd12092ef1f4847bf8988d839e49a6b5b42482c3dde77022ace66e1ca15b46f2df88d053c1bc3623110b3be74b08749eba6d22f87a44cf7cc1997e7e45d0e"; From ce446c34b3f9a599c0426f03485d5ec002fe0545 Mon Sep 17 00:00:00 2001 From: Omer Yacine Date: Mon, 24 Mar 2025 16:18:11 +0200 Subject: [PATCH 10/50] use the z_spending_key field inside the builder and not pass it via func args --- mm2src/coins/z_coin.rs | 5 +---- .../coins/z_coin/storage/walletdb/wallet_sql_storage.rs | 5 ++--- mm2src/coins/z_coin/storage/walletdb/wasm/storage.rs | 5 ++--- mm2src/coins/z_coin/z_rpc.rs | 8 ++------ 4 files changed, 7 insertions(+), 16 deletions(-) diff --git a/mm2src/coins/z_coin.rs b/mm2src/coins/z_coin.rs index 8d2154b1b5..50e0ec0a36 100644 --- a/mm2src/coins/z_coin.rs +++ b/mm2src/coins/z_coin.rs @@ -925,9 +925,7 @@ impl<'a> UtxoCoinBuilder for ZCoinBuilder<'a> { let (sync_state_connector, light_wallet_db) = match &self.z_coin_params.mode { #[cfg(not(target_arch = "wasm32"))] - ZcoinRpcMode::Native => { - init_native_client(&self, self.native_client()?, blocks_db, &self.z_spending_key).await? - }, + ZcoinRpcMode::Native => init_native_client(&self, self.native_client()?, blocks_db).await?, ZcoinRpcMode::Light { light_wallet_d_servers, sync_params, @@ -940,7 +938,6 @@ impl<'a> UtxoCoinBuilder for ZCoinBuilder<'a> { blocks_db, sync_params, skip_sync_params.unwrap_or_default(), - &self.z_spending_key, ) .await? }, diff --git a/mm2src/coins/z_coin/storage/walletdb/wallet_sql_storage.rs b/mm2src/coins/z_coin/storage/walletdb/wallet_sql_storage.rs index d3175dc319..5ec50b58a8 100644 --- a/mm2src/coins/z_coin/storage/walletdb/wallet_sql_storage.rs +++ b/mm2src/coins/z_coin/storage/walletdb/wallet_sql_storage.rs @@ -11,7 +11,7 @@ use zcash_extras::{WalletRead, WalletWrite}; use zcash_primitives::block::BlockHash; use zcash_primitives::consensus::BlockHeight; use zcash_primitives::transaction::TxId; -use zcash_primitives::zip32::{ExtendedFullViewingKey, ExtendedSpendingKey}; +use zcash_primitives::zip32::ExtendedFullViewingKey; /// `create_wallet_db` is responsible for creating a new Zcoin wallet database, initializing it /// with the provided parameters, and executing various initialization steps. These steps include checking and @@ -81,7 +81,6 @@ impl<'a> WalletDbShared { pub async fn new( builder: &ZCoinBuilder<'a>, checkpoint_block: Option, - z_spending_key: &ExtendedSpendingKey, continue_from_prev_sync: bool, ) -> ZcoinStorageRes { let ticker = builder.ticker; @@ -94,7 +93,7 @@ impl<'a> WalletDbShared { .join(format!("{ticker}_wallet.db")), consensus_params, checkpoint_block, - ExtendedFullViewingKey::from(z_spending_key), + ExtendedFullViewingKey::from(&builder.z_spending_key), continue_from_prev_sync, ) .await diff --git a/mm2src/coins/z_coin/storage/walletdb/wasm/storage.rs b/mm2src/coins/z_coin/storage/walletdb/wasm/storage.rs index d9ac5ec322..06d06c4d32 100644 --- a/mm2src/coins/z_coin/storage/walletdb/wasm/storage.rs +++ b/mm2src/coins/z_coin/storage/walletdb/wasm/storage.rs @@ -33,7 +33,7 @@ use zcash_primitives::merkle_tree::{CommitmentTree, IncrementalWitness}; use zcash_primitives::sapling::{Node, Nullifier, PaymentAddress}; use zcash_primitives::transaction::components::Amount; use zcash_primitives::transaction::{Transaction, TxId}; -use zcash_primitives::zip32::{ExtendedFullViewingKey, ExtendedSpendingKey}; +use zcash_primitives::zip32::ExtendedFullViewingKey; const DB_NAME: &str = "wallet_db_cache"; const DB_VERSION: u32 = 1; @@ -54,7 +54,6 @@ impl<'a> WalletDbShared { pub async fn new( builder: &ZCoinBuilder<'a>, checkpoint_block: Option, - z_spending_key: &ExtendedSpendingKey, continue_from_prev_sync: bool, ) -> ZcoinStorageRes { let ticker = builder.ticker; @@ -62,7 +61,7 @@ impl<'a> WalletDbShared { let db = WalletIndexedDb::new(builder.ctx, ticker, consensus_params).await?; let extrema = db.block_height_extrema().await?; let get_evk = db.get_extended_full_viewing_keys().await?; - let evk = ExtendedFullViewingKey::from(z_spending_key); + let evk = ExtendedFullViewingKey::from(&builder.z_spending_key); let min_sync_height = extrema.map(|(min, _)| u32::from(min)); let init_block_height = checkpoint_block.clone().map(|block| block.height); diff --git a/mm2src/coins/z_coin/z_rpc.rs b/mm2src/coins/z_coin/z_rpc.rs index 91d897d126..e5dfd3bbb3 100644 --- a/mm2src/coins/z_coin/z_rpc.rs +++ b/mm2src/coins/z_coin/z_rpc.rs @@ -29,7 +29,6 @@ use z_coin_grpc::{BlockId, BlockRange, TreeState, TxFilter}; use zcash_extras::{WalletRead, WalletWrite}; use zcash_primitives::consensus::BlockHeight; use zcash_primitives::transaction::TxId; -use zcash_primitives::zip32::ExtendedSpendingKey; pub(crate) mod z_coin_grpc { tonic::include_proto!("pirate.wallet.sdk.rpc"); @@ -508,7 +507,6 @@ pub(super) async fn init_light_client<'a>( blocks_db: BlockDbImpl, sync_params: &Option, skip_sync_params: bool, - z_spending_key: &ExtendedSpendingKey, ) -> Result<(AsyncMutex, WalletDbShared), MmError> { let coin = builder.ticker.to_string(); let (sync_status_notifier, sync_watcher) = channel(1); @@ -541,8 +539,7 @@ pub(super) async fn init_light_client<'a>( // check if no sync_params was provided and continue syncing from last height in db if it's > 0 or skip_sync_params is true. let continue_from_prev_sync = (min_height > 0 && sync_params.is_none()) || (skip_sync_params && min_height < sapling_activation_height); - let wallet_db = - WalletDbShared::new(builder, maybe_checkpoint_block, z_spending_key, continue_from_prev_sync).await?; + let wallet_db = WalletDbShared::new(builder, maybe_checkpoint_block, continue_from_prev_sync).await?; // Check min_height in blocks_db and rewind blocks_db to 0 if sync_height != min_height if !continue_from_prev_sync && (sync_height != min_height) { // let user know we're clearing cache and re-syncing from new provided height. @@ -586,7 +583,6 @@ pub(super) async fn init_native_client<'a>( builder: &ZCoinBuilder<'a>, native_client: NativeClient, blocks_db: BlockDbImpl, - z_spending_key: &ExtendedSpendingKey, ) -> Result<(AsyncMutex, WalletDbShared), MmError> { let coin = builder.ticker.to_string(); let (sync_status_notifier, sync_watcher) = channel(1); @@ -600,7 +596,7 @@ pub(super) async fn init_native_client<'a>( is_pre_sapling: false, actual: checkpoint_height, }; - let wallet_db = WalletDbShared::new(builder, checkpoint_block, z_spending_key, true) + let wallet_db = WalletDbShared::new(builder, checkpoint_block, true) .await .mm_err(|err| ZcoinClientInitError::ZcoinStorageError(err.to_string()))?; From a1c73471ba121fefd8bb69e972cd448615156928 Mon Sep 17 00:00:00 2001 From: Omer Yacine Date: Mon, 24 Mar 2025 16:26:15 +0200 Subject: [PATCH 11/50] add a disucssion point regarding address dir for zcoin wallet & cache dbs --- mm2src/coins/z_coin/storage/walletdb/wallet_sql_storage.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mm2src/coins/z_coin/storage/walletdb/wallet_sql_storage.rs b/mm2src/coins/z_coin/storage/walletdb/wallet_sql_storage.rs index 5ec50b58a8..089584411b 100644 --- a/mm2src/coins/z_coin/storage/walletdb/wallet_sql_storage.rs +++ b/mm2src/coins/z_coin/storage/walletdb/wallet_sql_storage.rs @@ -88,6 +88,9 @@ impl<'a> WalletDbShared { let wallet_db = create_wallet_db( builder .ctx + // FIXME: Discussion point: we are storing wallet information in an address directory. + // What if the user enables a different address within the same wallet? this data will not be visible to the newly enabled address + // Does zcoin even allow HD wallets? If not, what if we allow it later? where such a DB should be stored? .address_dir(&builder.my_z_addr_encoded) .map_err(|e| ZcoinStorageError::DbError(e.to_string()))? .join(format!("{ticker}_wallet.db")), From 97d984998abd07f0dcf34d16753b71c3264855be Mon Sep 17 00:00:00 2001 From: Omer Yacine Date: Tue, 25 Mar 2025 11:12:47 +0200 Subject: [PATCH 12/50] fix wrong stats taker swap directory --- mm2src/mm2_main/src/lp_swap/taker_swap.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mm2src/mm2_main/src/lp_swap/taker_swap.rs b/mm2src/mm2_main/src/lp_swap/taker_swap.rs index 51df5f21a4..22ccbb7081 100644 --- a/mm2src/mm2_main/src/lp_swap/taker_swap.rs +++ b/mm2src/mm2_main/src/lp_swap/taker_swap.rs @@ -105,7 +105,7 @@ pub const MAKER_PAYMENT_SPENT_BY_WATCHER_LOG: &str = "Maker payment is spent by #[cfg(not(target_arch = "wasm32"))] pub fn stats_taker_swap_dir(ctx: &MmArc) -> PathBuf { #[cfg(not(feature = "new-db-arch"))] - return ctx.dbdir().join("SWAPS").join("STATS").join("MAKER"); + return ctx.dbdir().join("SWAPS").join("STATS").join("TAKER"); #[cfg(feature = "new-db-arch")] return ctx.global_dir().join("SWAPS").join("STATS").join("TAKER"); } From 2cd8ecdafc9cad87b070906e87c2bf64a47f6fe4 Mon Sep 17 00:00:00 2001 From: Omer Yacine Date: Thu, 27 Mar 2025 13:10:10 +0200 Subject: [PATCH 13/50] use global directory for swap locks this is simpiler - than having to require a specific address directory - and has no down side --- mm2src/mm2_main/src/lp_swap/swap_lock.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/mm2src/mm2_main/src/lp_swap/swap_lock.rs b/mm2src/mm2_main/src/lp_swap/swap_lock.rs index f4347dde3b..f95ef0bcce 100644 --- a/mm2src/mm2_main/src/lp_swap/swap_lock.rs +++ b/mm2src/mm2_main/src/lp_swap/swap_lock.rs @@ -32,7 +32,6 @@ pub trait SwapLockOps: Sized { #[cfg(not(target_arch = "wasm32"))] mod native_lock { use super::*; - use crate::lp_swap::my_swaps_dir; use mm2_io::file_lock::{FileLock, FileLockError}; use std::path::PathBuf; @@ -57,7 +56,10 @@ mod native_lock { #[async_trait] impl SwapLockOps for SwapLock { async fn lock(ctx: &MmArc, swap_uuid: Uuid, ttl_sec: f64) -> SwapLockResult> { - let lock_path = my_swaps_dir(ctx).join(format!("{}.lock", swap_uuid)); + #[cfg(feature = "new-db-arch")] + let lock_path = ctx.global_dir().join(format!("{}.lock", swap_uuid)); + #[cfg(not(feature = "new-db-arch"))] + let lock_path = ctx.dbdir().join("SWAPS").join("MY").join(format!("{}.lock", swap_uuid)); let file_lock = some_or_return_ok_none!(FileLock::lock(lock_path, ttl_sec)?); Ok(Some(SwapLock { file_lock })) From ffb454065b7ce327aabb54f04fff56c376185e78 Mon Sep 17 00:00:00 2001 From: Omer Yacine Date: Fri, 28 Mar 2025 13:41:09 +0200 Subject: [PATCH 14/50] don't create the address directory when calling address_dir() we call address_dir() and then join the retruned pathbuf with other directory(s), i.e. nesting more directories (see e.g. eth_trace_path() or ln_data_dir()). this means we really need to also create not just the address directory but the directories we nest on top. this commit removes the directory creation in address_dir() and makes this method infallible, this simplifies it's usage. BUT, now the caller needs to create the address directory (or make sure it's created) and any nested directories needed on top before using that directory or accessing any files in it --- mm2src/coins/eth.rs | 33 +++++-------- mm2src/coins/lightning/ln_utils.rs | 10 ++-- mm2src/coins/qrc20.rs | 10 ++-- .../utxo/utxo_builder/utxo_coin_builder.rs | 26 ++++------- mm2src/coins/z_coin.rs | 1 - .../storage/blockdb/blockdb_sql_storage.rs | 1 + .../storage/walletdb/wallet_sql_storage.rs | 2 +- mm2src/mm2_core/Cargo.toml | 1 + mm2src/mm2_core/src/mm_ctx.rs | 13 ++---- mm2src/mm2_io/src/fs.rs | 46 +++++++++++++++++-- 10 files changed, 77 insertions(+), 66 deletions(-) diff --git a/mm2src/coins/eth.rs b/mm2src/coins/eth.rs index 3666ef045a..7aa86699bc 100644 --- a/mm2src/coins/eth.rs +++ b/mm2src/coins/eth.rs @@ -129,7 +129,6 @@ use super::{coin_conf, lp_coinfind_or_err, AsyncMutex, BalanceError, BalanceFut, pub use rlp; cfg_native! { use std::path::PathBuf; - use mm2_core::mm_ctx::AddressDataError; } pub mod eth_balance_events; @@ -913,18 +912,16 @@ macro_rules! tx_type_from_pay_for_gas_option { impl EthCoinImpl { #[cfg(not(target_arch = "wasm32"))] - fn eth_traces_path(&self, ctx: &MmArc, my_address: Address) -> Result { - let path = ctx - .address_dir(&my_address.addr_to_string())? + fn eth_traces_path(&self, ctx: &MmArc, my_address: Address) -> PathBuf { + ctx.address_dir(&my_address.addr_to_string()) .join("TRANSACTIONS") - .join(format!("{}_{:#02x}_trace.json", self.ticker, my_address)); - Ok(path) + .join(format!("{}_{:#02x}_trace.json", self.ticker, my_address)) } /// Load saved ETH traces from local DB #[cfg(not(target_arch = "wasm32"))] fn load_saved_traces(&self, ctx: &MmArc, my_address: Address) -> Option { - let path = self.eth_traces_path(ctx, my_address).ok()?; + let path = self.eth_traces_path(ctx, my_address); let content = gstuff::slurp(&path); if content.is_empty() { None @@ -947,10 +944,8 @@ impl EthCoinImpl { #[cfg(not(target_arch = "wasm32"))] fn store_eth_traces(&self, ctx: &MmArc, my_address: Address, traces: &SavedTraces) { let content = json::to_vec(traces).unwrap(); - let path = self.eth_traces_path(ctx, my_address).unwrap(); - let tmp_file = format!("{}.tmp", path.display()); - std::fs::write(&tmp_file, content).unwrap(); - std::fs::rename(tmp_file, path).unwrap(); + let path = self.eth_traces_path(ctx, my_address); + mm2_io::fs::write(&path, &content, true).unwrap(); } /// Store ETH traces to local DB @@ -961,22 +956,18 @@ impl EthCoinImpl { } #[cfg(not(target_arch = "wasm32"))] - fn erc20_events_path(&self, ctx: &MmArc, my_address: Address) -> Result { - let path = ctx - .address_dir(&my_address.addr_to_string())? + fn erc20_events_path(&self, ctx: &MmArc, my_address: Address) -> PathBuf { + ctx.address_dir(&my_address.addr_to_string()) .join("TRANSACTIONS") - .join(format!("{}_{:#02x}_events.json", self.ticker, my_address)); - Ok(path) + .join(format!("{}_{:#02x}_events.json", self.ticker, my_address)) } /// Store ERC20 events to local DB #[cfg(not(target_arch = "wasm32"))] fn store_erc20_events(&self, ctx: &MmArc, my_address: Address, events: &SavedErc20Events) { let content = json::to_vec(events).unwrap(); - let path = self.erc20_events_path(ctx, my_address).unwrap(); - let tmp_file = format!("{}.tmp", path.display()); - std::fs::write(&tmp_file, content).unwrap(); - std::fs::rename(tmp_file, path).unwrap(); + let path = self.erc20_events_path(ctx, my_address); + mm2_io::fs::write(&path, &content, true).unwrap(); } /// Store ERC20 events to local DB @@ -989,7 +980,7 @@ impl EthCoinImpl { /// Load saved ERC20 events from local DB #[cfg(not(target_arch = "wasm32"))] fn load_saved_erc20_events(&self, ctx: &MmArc, my_address: Address) -> Option { - let path = self.erc20_events_path(ctx, my_address).ok()?; + let path = self.erc20_events_path(ctx, my_address); let content = gstuff::slurp(&path); if content.is_empty() { None diff --git a/mm2src/coins/lightning/ln_utils.rs b/mm2src/coins/lightning/ln_utils.rs index f0c08e9bb0..68f3c7f7ab 100644 --- a/mm2src/coins/lightning/ln_utils.rs +++ b/mm2src/coins/lightning/ln_utils.rs @@ -18,7 +18,7 @@ use lightning::util::config::UserConfig; use lightning::util::errors::APIError; use lightning::util::ser::ReadableArgs; use lightning_invoice::payment::{Payer, PaymentError as InvoicePaymentError}; -use mm2_core::mm_ctx::{AddressDataError, MmArc}; +use mm2_core::mm_ctx::MmArc; use std::collections::hash_map::Entry; use std::fs::File; use std::path::PathBuf; @@ -54,9 +54,8 @@ impl From for RpcBestBlock { } #[inline] -fn ln_data_dir(ctx: &MmArc, platform_coin_address: &str, ticker: &str) -> Result { - ctx.address_dir(platform_coin_address) - .map(|dir| dir.join("LIGHTNING").join(ticker)) +fn ln_data_dir(ctx: &MmArc, platform_coin_address: &str, ticker: &str) -> PathBuf { + ctx.address_dir(platform_coin_address).join("LIGHTNING").join(ticker) } #[inline] @@ -75,8 +74,7 @@ pub async fn init_persister( ticker: String, backup_path: Option, ) -> EnableLightningResult> { - let ln_data_dir = - ln_data_dir(ctx, platform_coin_address, &ticker).map_err(|e| EnableLightningError::IOError(e.to_string()))?; + let ln_data_dir = ln_data_dir(ctx, platform_coin_address, &ticker); let ln_data_backup_dir = ln_data_backup_dir(backup_path, platform_coin_address, &ticker); let persister = Arc::new(LightningFilesystemPersister::new(ln_data_dir, ln_data_backup_dir)); diff --git a/mm2src/coins/qrc20.rs b/mm2src/coins/qrc20.rs index 0b96e5db69..7c03e2f964 100644 --- a/mm2src/coins/qrc20.rs +++ b/mm2src/coins/qrc20.rs @@ -59,10 +59,6 @@ use std::str::FromStr; use std::sync::Arc; use utxo_signer::with_key_pair::{sign_tx, UtxoSignWithKeyPairError}; -cfg_native! { - use mm2_core::mm_ctx::AddressDataError; -} - mod history; #[cfg(test)] mod qrc20_tests; pub mod rpc_clients; @@ -262,13 +258,13 @@ impl<'a> UtxoCoinBuilderCommonOps for Qrc20CoinBuilder<'a> { /// Please note the method is overridden for Native mode only. #[inline] #[cfg(not(target_arch = "wasm32"))] - fn tx_cache(&self, my_address: &UtxoAddress) -> Result { + fn tx_cache(&self, my_address: &UtxoAddress) -> UtxoVerboseCacheShared { let tx_cache = crate::utxo::tx_cache::fs_tx_cache::FsVerboseCache::new( self.platform.clone(), - self.tx_cache_path(my_address)?, + self.tx_cache_path(my_address), ) .into_shared(); - Ok(tx_cache) + tx_cache } } diff --git a/mm2src/coins/utxo/utxo_builder/utxo_coin_builder.rs b/mm2src/coins/utxo/utxo_builder/utxo_coin_builder.rs index 4c91251b7f..6ed668e37b 100644 --- a/mm2src/coins/utxo/utxo_builder/utxo_coin_builder.rs +++ b/mm2src/coins/utxo/utxo_builder/utxo_coin_builder.rs @@ -36,7 +36,6 @@ cfg_native! { use dirs::home_dir; use std::path::{Path, PathBuf}; use std::sync::Arc; - use mm2_core::mm_ctx::AddressDataError; } /// Number of seconds in a day (24 hours * 60 * 60) @@ -114,11 +113,6 @@ impl From for UtxoCoinBuildError { fn from(e: keys::Error) -> Self { UtxoCoinBuildError::Internal(e.to_string()) } } -#[cfg(not(target_arch = "wasm32"))] -impl From for UtxoCoinBuildError { - fn from(e: AddressDataError) -> Self { UtxoCoinBuildError::Internal(e.to_string()) } -} - #[async_trait] pub trait UtxoCoinBuilder: UtxoFieldsWithIguanaSecretBuilder + UtxoFieldsWithGlobalHDBuilder + UtxoFieldsWithHardwareWalletBuilder @@ -266,7 +260,7 @@ where let initial_history_state = builder.initial_history_state(); let tx_hash_algo = builder.tx_hash_algo(); let check_utxo_maturity = builder.check_utxo_maturity(); - let tx_cache = builder.tx_cache(&my_address)?; + let tx_cache = builder.tx_cache(&my_address); let (block_headers_status_notifier, block_headers_status_watcher) = builder.block_header_status_channel(&conf.spv_conf); @@ -345,7 +339,7 @@ pub trait UtxoFieldsWithHardwareWalletBuilder: UtxoCoinBuilderCommonOps { .await .ok_or_else(|| UtxoCoinBuildError::Internal("Failed to get enabled address from HD wallet".to_owned()))?; let my_script_pubkey = output_script(&my_address.address).map(|script| script.to_bytes())?; - let tx_cache = self.tx_cache(&my_address.address)?; + let tx_cache = self.tx_cache(&my_address.address); let (block_headers_status_notifier, block_headers_status_watcher) = self.block_header_status_channel(&conf.spv_conf); @@ -675,26 +669,24 @@ pub trait UtxoCoinBuilderCommonOps { } #[cfg(target_arch = "wasm32")] - fn tx_cache(&self, _my_address: &Address) -> Result { + fn tx_cache(&self, _my_address: &Address) -> UtxoVerboseCacheShared { #[allow(clippy::default_constructed_unit_structs)] // This is a false-possitive bug from clippy - Ok(crate::utxo::tx_cache::wasm_tx_cache::WasmVerboseCache::default().into_shared()) + crate::utxo::tx_cache::wasm_tx_cache::WasmVerboseCache::default().into_shared() } #[cfg(not(target_arch = "wasm32"))] - fn tx_cache(&self, my_address: &Address) -> Result { + fn tx_cache(&self, my_address: &Address) -> UtxoVerboseCacheShared { let tx_cache = crate::utxo::tx_cache::fs_tx_cache::FsVerboseCache::new( self.ticker().to_owned(), - self.tx_cache_path(my_address)?, + self.tx_cache_path(my_address), ) .into_shared(); - Ok(tx_cache) + tx_cache } #[cfg(not(target_arch = "wasm32"))] - fn tx_cache_path(&self, my_address: &Address) -> Result { - self.ctx() - .address_dir(&my_address.to_string()) - .map(|dir| dir.join("TX_CACHE")) + fn tx_cache_path(&self, my_address: &Address) -> PathBuf { + self.ctx().address_dir(&my_address.to_string()).join("TX_CACHE") } fn block_header_status_channel( diff --git a/mm2src/coins/z_coin.rs b/mm2src/coins/z_coin.rs index 50e0ec0a36..e09d64c78e 100644 --- a/mm2src/coins/z_coin.rs +++ b/mm2src/coins/z_coin.rs @@ -1039,7 +1039,6 @@ impl<'a> ZCoinBuilder<'a> { let cache_db_path = self .ctx .address_dir(&self.my_z_addr_encoded) - .map_err(|e| ZcoinClientInitError::ZcoinStorageError(e.to_string()))? .join(format!("{}_cache.db", self.ticker)); BlockDbImpl::new(ctx, ticker, cache_db_path).await }; diff --git a/mm2src/coins/z_coin/storage/blockdb/blockdb_sql_storage.rs b/mm2src/coins/z_coin/storage/blockdb/blockdb_sql_storage.rs index 44721b4364..8dd4dd39f7 100644 --- a/mm2src/coins/z_coin/storage/blockdb/blockdb_sql_storage.rs +++ b/mm2src/coins/z_coin/storage/blockdb/blockdb_sql_storage.rs @@ -48,6 +48,7 @@ impl BlockDbImpl { #[cfg(not(test))] pub async fn new(_ctx: &MmArc, ticker: String, path: PathBuf) -> ZcoinStorageRes { async_blocking(move || { + mm2_io::fs::create_parents(&path).map_err(|err| ZcoinStorageError::IoError(err.to_string()))?; let conn = Connection::open(path).map_to_mm(|err| ZcoinStorageError::DbError(err.to_string()))?; let conn = Arc::new(Mutex::new(conn)); let conn_lock = conn.lock().unwrap(); diff --git a/mm2src/coins/z_coin/storage/walletdb/wallet_sql_storage.rs b/mm2src/coins/z_coin/storage/walletdb/wallet_sql_storage.rs index 089584411b..349b0e3984 100644 --- a/mm2src/coins/z_coin/storage/walletdb/wallet_sql_storage.rs +++ b/mm2src/coins/z_coin/storage/walletdb/wallet_sql_storage.rs @@ -24,6 +24,7 @@ pub async fn create_wallet_db( evk: ExtendedFullViewingKey, continue_from_prev_sync: bool, ) -> Result, MmError> { + mm2_io::fs::create_parents(&wallet_db_path).map_err(|err| ZcoinClientInitError::ZcoinStorageError(err.to_string()))?; let db = async_blocking(move || { WalletDbAsync::for_path(wallet_db_path, consensus_params) .map_to_mm(|err| ZcoinClientInitError::ZcoinStorageError(err.to_string())) @@ -92,7 +93,6 @@ impl<'a> WalletDbShared { // What if the user enables a different address within the same wallet? this data will not be visible to the newly enabled address // Does zcoin even allow HD wallets? If not, what if we allow it later? where such a DB should be stored? .address_dir(&builder.my_z_addr_encoded) - .map_err(|e| ZcoinStorageError::DbError(e.to_string()))? .join(format!("{ticker}_wallet.db")), consensus_params, checkpoint_block, diff --git a/mm2src/mm2_core/Cargo.toml b/mm2src/mm2_core/Cargo.toml index b3756f9b94..3ff3e823df 100644 --- a/mm2src/mm2_core/Cargo.toml +++ b/mm2src/mm2_core/Cargo.toml @@ -44,3 +44,4 @@ wasm-bindgen-test = { version = "0.3.2" } rustls = { version = "0.21", default-features = false } tokio = { version = "1.20", features = ["io-util", "rt-multi-thread", "net"] } timed-map = { version = "1.3", features = ["rustc-hash"] } +mm2_io = { path = "../mm2_io" } diff --git a/mm2src/mm2_core/src/mm_ctx.rs b/mm2src/mm2_core/src/mm_ctx.rs index 074dc876a7..5c45d9898d 100644 --- a/mm2src/mm2_core/src/mm_ctx.rs +++ b/mm2src/mm2_core/src/mm_ctx.rs @@ -370,15 +370,11 @@ impl MmCtx { /// Use this directory for data related to a specific address and only that specific address (e.g. swap data, order data, etc...). /// This makes sure that when this address is activated using a different technique, this data is still accessible. #[cfg(not(target_arch = "wasm32"))] - pub fn address_dir(&self, address: &str) -> Result { + pub fn address_dir(&self, address: &str) -> PathBuf { if cfg!(not(feature = "new-db-arch")) { - return Ok(self.dbdir()); + return self.dbdir(); } - let path = self.db_root().join("addresses").join(address); - if !path.exists() || !path.is_dir() { - std::fs::create_dir_all(&path).map_err(AddressDataError::CreateAddressDirFailure)?; - } - Ok(path) + self.db_root().join("addresses").join(address) } /// Returns a SQL connection to the global database. @@ -402,7 +398,8 @@ impl MmCtx { /// Returns a SQL connection to the address database. #[cfg(not(target_arch = "wasm32"))] pub fn address_db(&self, address: &str) -> Result { - let path = self.address_dir(address)?.join("MM2.db"); + let path = self.address_dir(address).join("MM2.db"); + mm2_io::fs::create_parents(&path).map_err(|err| AddressDataError::CreateAddressDirFailure(err.into_inner()))?; log_sqlite_file_open_attempt(&path); let connection = Connection::open(path).map_err(AddressDataError::SqliteConnectionFailure)?; Ok(connection) diff --git a/mm2src/mm2_io/src/fs.rs b/mm2src/mm2_io/src/fs.rs index 960886a2b2..abac94279d 100644 --- a/mm2src/mm2_io/src/fs.rs +++ b/mm2src/mm2_io/src/fs.rs @@ -111,11 +111,6 @@ pub async fn remove_file_async>(path: P) -> IoResult<()> { Ok(async_fs::remove_file(path.as_ref()).await?) } -pub fn write(path: &dyn AsRef, contents: &dyn AsRef<[u8]>) -> Result<(), String> { - try_s!(fs::write(path, contents)); - Ok(()) -} - /// Read a folder asynchronously and return a list of files. pub async fn read_dir_async>(dir: P) -> IoResult> { use futures::StreamExt; @@ -276,10 +271,51 @@ where read_files_with_extension(dir_path, "json").await } +/// Creates all the directories along the path to a file. +pub fn create_parents(path: &dyn AsRef) -> IoResult<()> { + let parent_dir = path.as_ref().parent(); + let Some(parent_dir) = parent_dir else { + return MmError::err( + io::Error::new( + io::ErrorKind::InvalidInput, + format!("{} has no parent directory", path.as_ref().display()), + )) + }; + if parent_dir.exists() { + if !parent_dir.is_dir() { + return MmError::err(io::Error::new( + io::ErrorKind::InvalidInput, + format!("{} is not a directory", parent_dir.display()), + )); + } + } else { + fs::create_dir_all(parent_dir)?; + } + Ok(()) +} + +pub fn write(path: &dyn AsRef, content: &[u8], use_tmp_file: bool) -> IoResult<()> { + // Create all the directories in the path. + create_parents(path)?; + let path_tmp = if use_tmp_file { + PathBuf::from(format!("{}.tmp", path.as_ref().display())) + } else { + path.as_ref().to_path_buf() + }; + // Write the file content into the temp file and then rename the temp file into the desired name. + fs::write(&path_tmp, content)?; + if use_tmp_file { + fs::rename(&path_tmp, path.as_ref())?; + } + Ok(()) +} + pub async fn write_json(t: &T, path: &Path, use_tmp_file: bool) -> FsJsonResult<()> where T: Serialize, { + // FIXME: Create an async counterpart for create_parents? Should we? + create_parents(&path).map_err(|err| FsJsonError::IoWriting(err.into_inner()))?; let content = json::to_vec(t).map_to_mm(FsJsonError::Serializing)?; let path_tmp = if use_tmp_file { From 302e23ff3bc23999061c2036f3cff78b56788b3a Mon Sep 17 00:00:00 2001 From: Omer Yacine Date: Fri, 28 Mar 2025 14:12:51 +0200 Subject: [PATCH 15/50] add cargo lock --- Cargo.lock | 1 + 1 file changed, 1 insertion(+) diff --git a/Cargo.lock b/Cargo.lock index 17a35767ab..6e674efa86 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3890,6 +3890,7 @@ dependencies = [ "libp2p", "mm2_err_handle", "mm2_event_stream", + "mm2_io", "mm2_metrics", "mm2_rpc", "primitives", From aad87052d8f25d1f0627e3cb7bab7ac45e08d4d1 Mon Sep 17 00:00:00 2001 From: Omer Yacine Date: Sun, 30 Mar 2025 23:05:16 +0200 Subject: [PATCH 16/50] half-bake address directory logic inside `SavedSwap` to follow: 1- correctly set the address_dir for SavedSwap on initialization, i.e., set it to address_from_pubkey(maker_htlc_pubkey) instead of String::new() that is currenlty set. 2- allow load_my_swap_from_db to accept an optional address_dir to shortcut the roundtrip to the global DB if possible (sometiems in the code we already have the address_dir and we don't need to hit the global DB for that). 3- implemented the global DB swap address querying logic --- mm2src/mm2_main/src/lp_swap.rs | 17 ++++++---- mm2src/mm2_main/src/lp_swap/maker_swap.rs | 8 +++++ .../src/lp_swap/recreate_swap_data.rs | 6 ++++ mm2src/mm2_main/src/lp_swap/saved_swap.rs | 31 +++++++++++++++++-- mm2src/mm2_main/src/lp_swap/taker_swap.rs | 6 ++++ 5 files changed, 59 insertions(+), 9 deletions(-) diff --git a/mm2src/mm2_main/src/lp_swap.rs b/mm2src/mm2_main/src/lp_swap.rs index b15806c059..ea94c6edbe 100644 --- a/mm2src/mm2_main/src/lp_swap.rs +++ b/mm2src/mm2_main/src/lp_swap.rs @@ -962,10 +962,12 @@ pub struct TransactionIdentifier { } #[cfg(not(target_arch = "wasm32"))] -pub fn my_swaps_dir(ctx: &MmArc) -> PathBuf { ctx.dbdir().join("SWAPS").join("MY") } +pub fn my_swaps_dir(ctx: &MmArc, address: &str) -> PathBuf { ctx.address_dir(address).join("SWAPS").join("MY") } #[cfg(not(target_arch = "wasm32"))] -pub fn my_swap_file_path(ctx: &MmArc, uuid: &Uuid) -> PathBuf { my_swaps_dir(ctx).join(format!("{}.json", uuid)) } +pub fn my_swap_file_path(ctx: &MmArc, address: &str, uuid: &Uuid) -> PathBuf { + my_swaps_dir(ctx, address).join(format!("{}.json", uuid)) +} pub async fn insert_new_swap_to_db( ctx: MmArc, @@ -2240,7 +2242,7 @@ mod lp_swap_tests { uuid, None, conf_settings, - rick_maker.into(), + rick_maker.clone().into(), morty_maker.into(), lock_duration, None, @@ -2261,7 +2263,7 @@ mod lp_swap_tests { uuid, None, conf_settings, - rick_taker.into(), + rick_taker.clone().into(), morty_taker.into(), lock_duration, None, @@ -2274,15 +2276,18 @@ mod lp_swap_tests { run_taker_swap(RunTakerSwapInput::StartNew(taker_swap), taker_ctx.clone()), )); + let makers_maker_coin_address = rick_maker.my_address().unwrap(); + let takers_maker_coin_address = rick_taker.my_address().unwrap(); + println!( "Maker swap path {}", - std::fs::canonicalize(my_swap_file_path(&maker_ctx, &uuid)) + std::fs::canonicalize(my_swap_file_path(&maker_ctx, &makers_maker_coin_address, &uuid)) .unwrap() .display() ); println!( "Taker swap path {}", - std::fs::canonicalize(my_swap_file_path(&taker_ctx, &uuid)) + std::fs::canonicalize(my_swap_file_path(&taker_ctx, &takers_maker_coin_address, &uuid)) .unwrap() .display() ); diff --git a/mm2src/mm2_main/src/lp_swap/maker_swap.rs b/mm2src/mm2_main/src/lp_swap/maker_swap.rs index 8de7794279..57b135f535 100644 --- a/mm2src/mm2_main/src/lp_swap/maker_swap.rs +++ b/mm2src/mm2_main/src/lp_swap/maker_swap.rs @@ -93,10 +93,14 @@ pub fn stats_maker_swap_file_path(ctx: &MmArc, uuid: &Uuid) -> PathBuf { } async fn save_my_maker_swap_event(ctx: &MmArc, swap: &MakerSwap, event: MakerSavedEvent) -> Result<(), String> { + // let maker_coin_pub = swap.my_maker_coin_htlc_pub(); let swap = match SavedSwap::load_my_swap_from_db(ctx, swap.uuid).await { Ok(Some(swap)) => swap, Ok(None) => SavedSwap::Maker(MakerSavedSwap { uuid: swap.uuid, + // FIXME: Put a real address. + #[cfg(all(not(target_arch = "wasm32"), feature = "new-db-arch"))] + address_dir: String::new(), my_order_uuid: swap.my_order_uuid, maker_amount: Some(swap.maker_amount.clone()), maker_coin: Some(swap.maker_coin.ticker().to_owned()), @@ -1860,6 +1864,8 @@ impl MakerSwapStatusChanged { #[derive(Debug, Default, PartialEq, Serialize, Deserialize)] pub struct MakerSavedSwap { pub uuid: Uuid, + #[cfg(all(not(target_arch = "wasm32"), feature = "new-db-arch"))] + pub address_dir: String, pub my_order_uuid: Option, pub events: Vec, pub maker_amount: Option, @@ -1916,6 +1922,8 @@ impl MakerSavedSwap { MakerSavedSwap { uuid: Default::default(), + #[cfg(all(not(target_arch = "wasm32"), feature = "new-db-arch"))] + address_dir: "".to_string(), my_order_uuid: None, events, maker_amount: Some(maker_amount.to_decimal()), diff --git a/mm2src/mm2_main/src/lp_swap/recreate_swap_data.rs b/mm2src/mm2_main/src/lp_swap/recreate_swap_data.rs index e389597f92..38cef1a6bb 100644 --- a/mm2src/mm2_main/src/lp_swap/recreate_swap_data.rs +++ b/mm2src/mm2_main/src/lp_swap/recreate_swap_data.rs @@ -82,6 +82,9 @@ pub async fn recreate_swap_data(ctx: MmArc, args: RecreateSwapRequest) -> Recrea fn recreate_maker_swap(ctx: MmArc, taker_swap: TakerSavedSwap) -> RecreateSwapResult { let mut maker_swap = MakerSavedSwap { uuid: taker_swap.uuid, + // FIXME: Put a real address. Also check how the other end imports the swap and whether we can set the address from their + #[cfg(all(not(target_arch = "wasm32"), feature = "new-db-arch"))] + address_dir: String::new(), my_order_uuid: taker_swap.my_order_uuid, events: Vec::new(), maker_amount: taker_swap.maker_amount, @@ -285,6 +288,9 @@ fn convert_taker_to_maker_events( async fn recreate_taker_swap(ctx: MmArc, maker_swap: MakerSavedSwap) -> RecreateSwapResult { let mut taker_swap = TakerSavedSwap { uuid: maker_swap.uuid, + // FIXME: Put a real address. Also check how the other end imports the swap and whether we can set the address from their + #[cfg(all(not(target_arch = "wasm32"), feature = "new-db-arch"))] + address_dir: String::new(), my_order_uuid: Some(maker_swap.uuid), events: Vec::new(), maker_amount: maker_swap.maker_amount, diff --git a/mm2src/mm2_main/src/lp_swap/saved_swap.rs b/mm2src/mm2_main/src/lp_swap/saved_swap.rs index 185edd1584..b0836b1d2c 100644 --- a/mm2src/mm2_main/src/lp_swap/saved_swap.rs +++ b/mm2src/mm2_main/src/lp_swap/saved_swap.rs @@ -75,6 +75,14 @@ impl SavedSwap { } } + #[cfg(all(not(target_arch = "wasm32"), feature = "new-db-arch"))] + pub fn address_dir(&self) -> &str { + match self { + SavedSwap::Maker(swap) => &swap.address_dir, + SavedSwap::Taker(swap) => &swap.address_dir, + } + } + pub fn maker_coin_ticker(&self) -> Result { match self { SavedSwap::Maker(swap) => swap.maker_coin(), @@ -209,12 +217,25 @@ mod native_impl { #[async_trait] impl SavedSwapIo for SavedSwap { async fn load_my_swap_from_db(ctx: &MmArc, uuid: Uuid) -> SavedSwapResult> { - let path = my_swap_file_path(ctx, &uuid); + // FIXME: Set the correct address directory for the new db arch branch. + #[cfg(feature = "new-db-arch")] + let address_dir = "Fetch the address directory from the global DB given the UUID."; + #[cfg(not(feature = "new-db-arch"))] + let address_dir = "no address directory for old DB architecture (has no effect)"; + let path = my_swap_file_path(ctx, address_dir, &uuid); Ok(read_json(&path).await?) } + #[cfg_attr(feature = "new-db-arch", allow(unreachable_code, unused_variables))] async fn load_all_my_swaps_from_db(ctx: &MmArc) -> SavedSwapResult> { - let path = my_swaps_dir(ctx); + #[cfg(feature = "new-db-arch")] + { + // This method is solely used for migrations. Which we should ditch or refactor with the new DB architecture. + // If we ditch the old migrations, this method should never be called (and should be deleted when we are + // done with the incremental architecture change). + todo!("Fix the dummy address directory in `my_swaps_dir` below or remove this method all together"); + } + let path = my_swaps_dir(ctx, "has no effect in not(feature = 'new-db-arch')"); Ok(read_dir_json(&path).await?) } @@ -239,7 +260,11 @@ mod native_impl { } async fn save_to_db(&self, ctx: &MmArc) -> SavedSwapResult<()> { - let path = my_swap_file_path(ctx, self.uuid()); + #[cfg(feature = "new-db-arch")] + let address_dir = self.address_dir(); + #[cfg(not(feature = "new-db-arch"))] + let address_dir = "no address directory for old DB architecture (has no effect)"; + let path = my_swap_file_path(ctx, address_dir, self.uuid()); write_json(self, &path, USE_TMP_FILE).await?; Ok(()) } diff --git a/mm2src/mm2_main/src/lp_swap/taker_swap.rs b/mm2src/mm2_main/src/lp_swap/taker_swap.rs index 22ccbb7081..17bb8e2a3e 100644 --- a/mm2src/mm2_main/src/lp_swap/taker_swap.rs +++ b/mm2src/mm2_main/src/lp_swap/taker_swap.rs @@ -116,10 +116,14 @@ pub fn stats_taker_swap_file_path(ctx: &MmArc, uuid: &Uuid) -> PathBuf { } async fn save_my_taker_swap_event(ctx: &MmArc, swap: &TakerSwap, event: TakerSavedEvent) -> Result<(), String> { + // let maker_coin_pub = swap.my_maker_coin_htlc_pub(); let swap = match SavedSwap::load_my_swap_from_db(ctx, swap.uuid).await { Ok(Some(swap)) => swap, Ok(None) => SavedSwap::Taker(TakerSavedSwap { uuid: swap.uuid, + // FIXME: Put a real address. + #[cfg(all(not(target_arch = "wasm32"), feature = "new-db-arch"))] + address_dir: String::new(), my_order_uuid: swap.my_order_uuid, maker_amount: Some(swap.maker_amount.to_decimal()), maker_coin: Some(swap.maker_coin.ticker().to_owned()), @@ -209,6 +213,8 @@ impl TakerSavedEvent { #[derive(Debug, Deserialize, PartialEq, Serialize)] pub struct TakerSavedSwap { pub uuid: Uuid, + #[cfg(all(not(target_arch = "wasm32"), feature = "new-db-arch"))] + pub address_dir: String, pub my_order_uuid: Option, pub events: Vec, pub maker_amount: Option, From abbe7162d4e080ac9f067801b978ce8b79ef9c41 Mon Sep 17 00:00:00 2001 From: Omer Yacine Date: Sun, 30 Mar 2025 23:35:30 +0200 Subject: [PATCH 17/50] give the option to specify an address directory when loading swap from DB this serves as a shortcut so we don't have to query the global DB to find the address directory of that UUID in question --- mm2src/mm2_main/src/lp_swap.rs | 14 +++++------ mm2src/mm2_main/src/lp_swap/maker_swap.rs | 4 ++-- mm2src/mm2_main/src/lp_swap/saved_swap.rs | 26 ++++++++++++++++----- mm2src/mm2_main/src/lp_swap/swap_v2_rpcs.rs | 2 +- mm2src/mm2_main/src/lp_swap/taker_swap.rs | 4 ++-- 5 files changed, 32 insertions(+), 18 deletions(-) diff --git a/mm2src/mm2_main/src/lp_swap.rs b/mm2src/mm2_main/src/lp_swap.rs index ea94c6edbe..3b389300f6 100644 --- a/mm2src/mm2_main/src/lp_swap.rs +++ b/mm2src/mm2_main/src/lp_swap.rs @@ -1082,7 +1082,7 @@ pub async fn my_swap_status(ctx: MmArc, req: Json) -> Result>, match swap_type { Some(LEGACY_SWAP_TYPE) => { - let status = match SavedSwap::load_my_swap_from_db(&ctx, uuid).await { + let status = match SavedSwap::load_my_swap_from_db(&ctx, None, uuid).await { Ok(Some(status)) => status, Ok(None) => return Err("swap data is not found".to_owned()), Err(e) => return ERR!("{}", e), @@ -1144,7 +1144,7 @@ struct SwapStatus { /// Broadcasts `my` swap status to P2P network async fn broadcast_my_swap_status(ctx: &MmArc, uuid: Uuid) -> Result<(), String> { - let mut status = match try_s!(SavedSwap::load_my_swap_from_db(ctx, uuid).await) { + let mut status = match try_s!(SavedSwap::load_my_swap_from_db(ctx, None, uuid).await) { Some(status) => status, None => return ERR!("swap data is not found"), }; @@ -1253,7 +1253,7 @@ pub async fn latest_swaps_for_pair( let mut swaps = Vec::with_capacity(db_result.uuids_and_types.len()); // TODO this is needed for trading bot, which seems not used as of now. Remove the code? for (uuid, _) in db_result.uuids_and_types.iter() { - let swap = match SavedSwap::load_my_swap_from_db(&ctx, *uuid).await { + let swap = match SavedSwap::load_my_swap_from_db(&ctx, None, *uuid).await { Ok(Some(swap)) => swap, Ok(None) => { error!("No such swap with the uuid '{}'", uuid); @@ -1280,7 +1280,7 @@ pub async fn my_recent_swaps_rpc(ctx: MmArc, req: Json) -> Result match SavedSwap::load_my_swap_from_db(&ctx, *uuid).await { + LEGACY_SWAP_TYPE => match SavedSwap::load_my_swap_from_db(&ctx, None, *uuid).await { Ok(Some(swap)) => { let swap_json = try_s!(json::to_value(MySwapStatusResponse::from(swap))); swaps.push(swap_json) @@ -1331,7 +1331,7 @@ pub async fn swap_kick_starts(ctx: MmArc) -> Result, String> { let mut coins = HashSet::new(); let legacy_unfinished_uuids = try_s!(get_unfinished_swaps_uuids(ctx.clone(), LEGACY_SWAP_TYPE).await); for uuid in legacy_unfinished_uuids { - let swap = match SavedSwap::load_my_swap_from_db(&ctx, uuid).await { + let swap = match SavedSwap::load_my_swap_from_db(&ctx, None, uuid).await { Ok(Some(s)) => s, Ok(None) => { warn!("Swap {} is indexed, but doesn't exist in DB", uuid); @@ -1479,7 +1479,7 @@ pub async fn coins_needed_for_kick_start(ctx: MmArc) -> Result> pub async fn recover_funds_of_swap(ctx: MmArc, req: Json) -> Result>, String> { let uuid: Uuid = try_s!(json::from_value(req["params"]["uuid"].clone())); - let swap = match SavedSwap::load_my_swap_from_db(&ctx, uuid).await { + let swap = match SavedSwap::load_my_swap_from_db(&ctx, None, uuid).await { Ok(Some(swap)) => swap, Ok(None) => return ERR!("swap data is not found"), Err(e) => return ERR!("{}", e), @@ -1556,7 +1556,7 @@ pub async fn active_swaps_rpc(ctx: MmArc, req: Json) -> Result> for (uuid, swap_type) in uuids_with_types.iter() { match *swap_type { LEGACY_SWAP_TYPE => { - let status = match SavedSwap::load_my_swap_from_db(&ctx, *uuid).await { + let status = match SavedSwap::load_my_swap_from_db(&ctx, None, *uuid).await { Ok(Some(status)) => status, Ok(None) => continue, Err(e) => { diff --git a/mm2src/mm2_main/src/lp_swap/maker_swap.rs b/mm2src/mm2_main/src/lp_swap/maker_swap.rs index 57b135f535..892c7b946b 100644 --- a/mm2src/mm2_main/src/lp_swap/maker_swap.rs +++ b/mm2src/mm2_main/src/lp_swap/maker_swap.rs @@ -94,7 +94,7 @@ pub fn stats_maker_swap_file_path(ctx: &MmArc, uuid: &Uuid) -> PathBuf { async fn save_my_maker_swap_event(ctx: &MmArc, swap: &MakerSwap, event: MakerSavedEvent) -> Result<(), String> { // let maker_coin_pub = swap.my_maker_coin_htlc_pub(); - let swap = match SavedSwap::load_my_swap_from_db(ctx, swap.uuid).await { + let swap = match SavedSwap::load_my_swap_from_db(ctx, None, swap.uuid).await { Ok(Some(swap)) => swap, Ok(None) => SavedSwap::Maker(MakerSavedSwap { uuid: swap.uuid, @@ -1369,7 +1369,7 @@ impl MakerSwap { taker_coin: MmCoinEnum, swap_uuid: &Uuid, ) -> Result<(Self, Option), String> { - let saved = match SavedSwap::load_my_swap_from_db(&ctx, *swap_uuid).await { + let saved = match SavedSwap::load_my_swap_from_db(&ctx, None, *swap_uuid).await { Ok(Some(saved)) => saved, Ok(None) => return ERR!("Couldn't find a swap with the uuid '{}'", swap_uuid), Err(e) => return ERR!("{}", e), diff --git a/mm2src/mm2_main/src/lp_swap/saved_swap.rs b/mm2src/mm2_main/src/lp_swap/saved_swap.rs index b0836b1d2c..f866b97595 100644 --- a/mm2src/mm2_main/src/lp_swap/saved_swap.rs +++ b/mm2src/mm2_main/src/lp_swap/saved_swap.rs @@ -167,7 +167,11 @@ impl SavedSwap { #[async_trait] pub trait SavedSwapIo { - async fn load_my_swap_from_db(ctx: &MmArc, uuid: Uuid) -> SavedSwapResult>; + async fn load_my_swap_from_db( + ctx: &MmArc, + optional_address_dir: Option<&str>, + uuid: Uuid, + ) -> SavedSwapResult>; async fn load_all_my_swaps_from_db(ctx: &MmArc) -> SavedSwapResult>; @@ -216,12 +220,18 @@ mod native_impl { #[async_trait] impl SavedSwapIo for SavedSwap { - async fn load_my_swap_from_db(ctx: &MmArc, uuid: Uuid) -> SavedSwapResult> { + async fn load_my_swap_from_db( + ctx: &MmArc, + optional_address_dir: Option<&str>, + uuid: Uuid, + ) -> SavedSwapResult> { // FIXME: Set the correct address directory for the new db arch branch. #[cfg(feature = "new-db-arch")] - let address_dir = "Fetch the address directory from the global DB given the UUID."; + let address_dir = + optional_address_dir.unwrap_or("Fetch the address directory from the global DB given the UUID."); #[cfg(not(feature = "new-db-arch"))] - let address_dir = "no address directory for old DB architecture (has no effect)"; + let address_dir = + optional_address_dir.unwrap_or("no address directory for old DB architecture (has no effect)"); let path = my_swap_file_path(ctx, address_dir, &uuid); Ok(read_json(&path).await?) } @@ -401,7 +411,11 @@ mod wasm_impl { #[async_trait] impl SavedSwapIo for SavedSwap { - async fn load_my_swap_from_db(ctx: &MmArc, uuid: Uuid) -> SavedSwapResult> { + async fn load_my_swap_from_db( + ctx: &MmArc, + _optional_address_dir: Option<&str>, + uuid: Uuid, + ) -> SavedSwapResult> { let swaps_ctx = SwapsContext::from_ctx(ctx).map_to_mm(SavedSwapError::InternalError)?; let db = swaps_ctx.swap_db().await?; let transaction = db.transaction().await?; @@ -511,7 +525,7 @@ mod tests { assert_eq!(item, second_saved_item); } - let actual_saved_swap = SavedSwap::load_my_swap_from_db(&ctx, *saved_swap.uuid()) + let actual_saved_swap = SavedSwap::load_my_swap_from_db(&ctx, None, *saved_swap.uuid()) .await .expect("!load_from_db") .expect("Swap not found"); diff --git a/mm2src/mm2_main/src/lp_swap/swap_v2_rpcs.rs b/mm2src/mm2_main/src/lp_swap/swap_v2_rpcs.rs index 669d17a492..92a305f252 100644 --- a/mm2src/mm2_main/src/lp_swap/swap_v2_rpcs.rs +++ b/mm2src/mm2_main/src/lp_swap/swap_v2_rpcs.rs @@ -301,7 +301,7 @@ async fn get_swap_data_by_uuid_and_type( ) -> MmResult, GetSwapDataErr> { match swap_type { LEGACY_SWAP_TYPE => { - let saved_swap = SavedSwap::load_my_swap_from_db(ctx, uuid).await?; + let saved_swap = SavedSwap::load_my_swap_from_db(ctx, None, uuid).await?; Ok(saved_swap.map(|swap| match swap { SavedSwap::Maker(m) => SwapRpcData::MakerV1(m), SavedSwap::Taker(t) => SwapRpcData::TakerV1(t), diff --git a/mm2src/mm2_main/src/lp_swap/taker_swap.rs b/mm2src/mm2_main/src/lp_swap/taker_swap.rs index 17bb8e2a3e..3b2444e5a2 100644 --- a/mm2src/mm2_main/src/lp_swap/taker_swap.rs +++ b/mm2src/mm2_main/src/lp_swap/taker_swap.rs @@ -117,7 +117,7 @@ pub fn stats_taker_swap_file_path(ctx: &MmArc, uuid: &Uuid) -> PathBuf { async fn save_my_taker_swap_event(ctx: &MmArc, swap: &TakerSwap, event: TakerSavedEvent) -> Result<(), String> { // let maker_coin_pub = swap.my_maker_coin_htlc_pub(); - let swap = match SavedSwap::load_my_swap_from_db(ctx, swap.uuid).await { + let swap = match SavedSwap::load_my_swap_from_db(ctx, None, swap.uuid).await { Ok(Some(swap)) => swap, Ok(None) => SavedSwap::Taker(TakerSavedSwap { uuid: swap.uuid, @@ -2096,7 +2096,7 @@ impl TakerSwap { taker_coin: MmCoinEnum, swap_uuid: &Uuid, ) -> Result<(Self, Option), String> { - let saved = match SavedSwap::load_my_swap_from_db(&ctx, *swap_uuid).await { + let saved = match SavedSwap::load_my_swap_from_db(&ctx, None, *swap_uuid).await { Ok(Some(saved)) => saved, Ok(None) => return ERR!("Couldn't find a swap with the uuid '{}'", swap_uuid), Err(e) => return ERR!("{}", e), From 638da9e2195cba998097ebb4d3dffc71ef605e49 Mon Sep 17 00:00:00 2001 From: Omer Yacine Date: Mon, 31 Mar 2025 00:51:13 +0200 Subject: [PATCH 18/50] add and partially implement `address_from_pubkey` --- mm2src/coins/coin_errors.rs | 5 +++++ mm2src/coins/eth.rs | 7 +++++- mm2src/coins/eth/v2_activation.rs | 4 ++-- mm2src/coins/lightning.rs | 9 ++++++-- mm2src/coins/lp_coins.rs | 7 ++++-- mm2src/coins/qrc20.rs | 10 +++++++-- mm2src/coins/siacoin.rs | 24 ++++++++++++++------- mm2src/coins/tendermint/tendermint_coin.rs | 11 ++++++++-- mm2src/coins/tendermint/tendermint_token.rs | 8 +++++-- mm2src/coins/test_coin.rs | 6 ++++-- mm2src/coins/utxo/bch.rs | 8 ++++++- mm2src/coins/utxo/qtum.rs | 8 ++++++- mm2src/coins/utxo/slp.rs | 10 ++++++--- mm2src/coins/utxo/utxo_standard.rs | 8 ++++++- mm2src/coins/z_coin.rs | 9 ++++++-- 15 files changed, 103 insertions(+), 31 deletions(-) diff --git a/mm2src/coins/coin_errors.rs b/mm2src/coins/coin_errors.rs index 3e9bbc7349..486a07fc83 100644 --- a/mm2src/coins/coin_errors.rs +++ b/mm2src/coins/coin_errors.rs @@ -108,3 +108,8 @@ pub enum MyAddressError { UnexpectedDerivationMethod(String), InternalError(String), } + +#[derive(Debug, Display)] +pub enum AddressFromPubkeyError { + InternalError(String), +} diff --git a/mm2src/coins/eth.rs b/mm2src/coins/eth.rs index 7aa86699bc..50d17e7e5c 100644 --- a/mm2src/coins/eth.rs +++ b/mm2src/coins/eth.rs @@ -102,7 +102,7 @@ use web3::{self, Web3}; cfg_wasm32! { use common::{now_ms, wait_until_ms}; use crypto::MetamaskArc; - use ethereum_types::{H264, H520}; + use ethereum_types::{H264 as EthH264, H520 as EthH520}; use mm2_metamask::MetamaskError; use web3::types::TransactionRequest; } @@ -2284,6 +2284,11 @@ impl MarketCoinOps for EthCoin { } } + fn address_from_pubkey(&self, pubkey: &H264) -> MmResult { + let addr = addr_from_raw_pubkey(&pubkey.0).map_err(AddressFromPubkeyError::InternalError)?; + Ok(addr.display_address()) + } + async fn get_public_key(&self) -> Result> { match self.priv_key_policy { EthPrivKeyPolicy::Iguana(ref key_pair) diff --git a/mm2src/coins/eth/v2_activation.rs b/mm2src/coins/eth/v2_activation.rs index 4e04bfebed..e1eeec11cb 100644 --- a/mm2src/coins/eth/v2_activation.rs +++ b/mm2src/coins/eth/v2_activation.rs @@ -974,9 +974,9 @@ async fn check_metamask_supports_chain_id( } #[cfg(target_arch = "wasm32")] -fn compress_public_key(uncompressed: H520) -> MmResult { +fn compress_public_key(uncompressed: EthH520) -> MmResult { let public_key = PublicKey::from_slice(uncompressed.as_bytes()) .map_to_mm(|e| EthActivationV2Error::InternalError(e.to_string()))?; let compressed = public_key.serialize(); - Ok(H264::from(compressed)) + Ok(EthH264::from(compressed)) } diff --git a/mm2src/coins/lightning.rs b/mm2src/coins/lightning.rs index 949c39a857..343cc81a72 100644 --- a/mm2src/coins/lightning.rs +++ b/mm2src/coins/lightning.rs @@ -10,7 +10,7 @@ mod ln_sql; pub mod ln_storage; pub mod ln_utils; -use crate::coin_errors::{MyAddressError, ValidatePaymentResult}; +use crate::coin_errors::{AddressFromPubkeyError, MyAddressError, ValidatePaymentResult}; use crate::lightning::ln_utils::{filter_channels, pay_invoice_with_max_total_cltv_expiry_delta, PaymentError}; use crate::utxo::rpc_clients::UtxoRpcClientEnum; use crate::utxo::utxo_common::{big_decimal_from_sat, big_decimal_from_sat_unsigned}; @@ -65,7 +65,7 @@ use mm2_err_handle::prelude::*; use mm2_net::ip_addr::myipaddr; use mm2_number::{BigDecimal, MmNumber}; use parking_lot::Mutex as PaMutex; -use rpc::v1::types::{Bytes as BytesJson, H256 as H256Json}; +use rpc::v1::types::{Bytes as BytesJson, H256 as H256Json, H264}; use script::TransactionInputSigner; use secp256k1v24::PublicKey; use serde::Deserialize; @@ -942,6 +942,11 @@ impl MarketCoinOps for LightningCoin { fn my_address(&self) -> MmResult { Ok(self.my_node_id()) } + fn address_from_pubkey(&self, pubkey: &H264) -> MmResult { + // FIXME: What's a pubkey in this case? Is it for L1 or L2 (hint: the pubkey input here is maker_coin_htlc_pubkey of the swap). + self.platform_coin().address_from_pubkey(pubkey) + } + async fn get_public_key(&self) -> Result> { Ok(self.my_node_id()) } fn sign_message_hash(&self, message: &str) -> Option<[u8; 32]> { diff --git a/mm2src/coins/lp_coins.rs b/mm2src/coins/lp_coins.rs index 4ebdac6fb4..b36991cff7 100644 --- a/mm2src/coins/lp_coins.rs +++ b/mm2src/coins/lp_coins.rs @@ -72,7 +72,7 @@ use mm2_rpc::data::legacy::{EnabledCoin, GetEnabledResponse, Mm2RpcResult}; #[cfg(any(test, feature = "for-tests"))] use mocktopus::macros::*; use parking_lot::Mutex as PaMutex; -use rpc::v1::types::{Bytes as BytesJson, H256 as H256Json}; +use rpc::v1::types::{Bytes as BytesJson, H256 as H256Json, H264}; use serde::{Deserialize, Deserializer, Serialize, Serializer}; use serde_json::{self as json, Value as Json}; use std::array::TryFromSliceError; @@ -214,7 +214,8 @@ pub mod lp_price; pub mod watcher_common; pub mod coin_errors; -use coin_errors::{MyAddressError, ValidatePaymentError, ValidatePaymentFut, ValidatePaymentResult}; +use coin_errors::{AddressFromPubkeyError, MyAddressError, ValidatePaymentError, ValidatePaymentFut, + ValidatePaymentResult}; use crypto::secret_hash_algo::SecretHashAlgo; #[doc(hidden)] @@ -2080,6 +2081,8 @@ pub trait MarketCoinOps { fn my_address(&self) -> MmResult; + fn address_from_pubkey(&self, pubkey: &H264) -> MmResult; + async fn get_public_key(&self) -> Result>; fn sign_message_hash(&self, _message: &str) -> Option<[u8; 32]>; diff --git a/mm2src/coins/qrc20.rs b/mm2src/coins/qrc20.rs index 7c03e2f964..c2d8944679 100644 --- a/mm2src/coins/qrc20.rs +++ b/mm2src/coins/qrc20.rs @@ -1,4 +1,4 @@ -use crate::coin_errors::{MyAddressError, ValidatePaymentError, ValidatePaymentResult}; +use crate::coin_errors::{AddressFromPubkeyError, MyAddressError, ValidatePaymentError, ValidatePaymentResult}; use crate::eth::{self, u256_to_big_decimal, wei_from_big_decimal, TryToAddress}; use crate::qrc20::rpc_clients::{LogEntry, Qrc20ElectrumOps, Qrc20NativeOps, Qrc20RpcOps, TopicFilter, TxReceipt, ViewContractCallType}; @@ -45,7 +45,8 @@ use mm2_core::mm_ctx::MmArc; use mm2_err_handle::prelude::*; use mm2_number::{BigDecimal, MmNumber}; #[cfg(test)] use mocktopus::macros::*; -use rpc::v1::types::{Bytes as BytesJson, ToTxHash, Transaction as RpcTransaction, H160 as H160Json, H256 as H256Json}; +use rpc::v1::types::{Bytes as BytesJson, ToTxHash, Transaction as RpcTransaction, H160 as H160Json, H256 as H256Json, + H264}; use script::{Builder as ScriptBuilder, Opcode, Script, TransactionInputSigner}; use script_pubkey::generate_contract_call_script_pubkey; use serde_json::{self as json, Value as Json}; @@ -1034,6 +1035,11 @@ impl MarketCoinOps for Qrc20Coin { fn my_address(&self) -> MmResult { utxo_common::my_address(self) } + fn address_from_pubkey(&self, pubkey: &H264) -> MmResult { + let pubkey = Public::Compressed((*pubkey).into()); + Ok(UtxoCommonOps::address_from_pubkey(self, &pubkey).to_string()) + } + async fn get_public_key(&self) -> Result> { let pubkey = utxo_common::my_public_key(self.as_ref())?; Ok(pubkey.to_string()) diff --git a/mm2src/coins/siacoin.rs b/mm2src/coins/siacoin.rs index bb5ec12353..5f828ad22f 100644 --- a/mm2src/coins/siacoin.rs +++ b/mm2src/coins/siacoin.rs @@ -1,12 +1,13 @@ use super::{BalanceError, CoinBalance, HistorySyncState, MarketCoinOps, MmCoin, RawTransactionFut, RawTransactionRequest, SwapOps, TradeFee, TransactionEnum}; -use crate::{coin_errors::MyAddressError, BalanceFut, CanRefundHtlc, CheckIfMyPaymentSentArgs, ConfirmPaymentInput, - DexFee, FeeApproxStage, FoundSwapTxSpend, NegotiateSwapContractAddrErr, PrivKeyBuildPolicy, PrivKeyPolicy, - RawTransactionResult, RefundPaymentArgs, SearchForSwapTxSpendInput, SendPaymentArgs, - SignRawTransactionRequest, SignatureResult, SpendPaymentArgs, TradePreimageFut, TradePreimageResult, - TradePreimageValue, TransactionResult, TxMarshalingErr, UnexpectedDerivationMethod, ValidateAddressResult, - ValidateFeeArgs, ValidateOtherPubKeyErr, ValidatePaymentInput, ValidatePaymentResult, VerificationResult, - WaitForHTLCTxSpendArgs, WatcherOps, WeakSpawner, WithdrawFut, WithdrawRequest}; +use crate::{coin_errors::MyAddressError, AddressFromPubkeyError, BalanceFut, CanRefundHtlc, CheckIfMyPaymentSentArgs, + ConfirmPaymentInput, DexFee, FeeApproxStage, FoundSwapTxSpend, NegotiateSwapContractAddrErr, + PrivKeyBuildPolicy, PrivKeyPolicy, RawTransactionResult, RefundPaymentArgs, SearchForSwapTxSpendInput, + SendPaymentArgs, SignRawTransactionRequest, SignatureResult, SpendPaymentArgs, TradePreimageFut, + TradePreimageResult, TradePreimageValue, TransactionResult, TxMarshalingErr, UnexpectedDerivationMethod, + ValidateAddressResult, ValidateFeeArgs, ValidateOtherPubKeyErr, ValidatePaymentInput, + ValidatePaymentResult, VerificationResult, WaitForHTLCTxSpendArgs, WatcherOps, WeakSpawner, WithdrawFut, + WithdrawRequest}; use async_trait::async_trait; use common::executor::AbortedError; pub use ed25519_dalek::{Keypair, PublicKey, SecretKey, Signature}; @@ -16,7 +17,7 @@ use keys::KeyPair; use mm2_core::mm_ctx::MmArc; use mm2_err_handle::prelude::*; use mm2_number::{BigDecimal, BigInt, MmNumber}; -use rpc::v1::types::Bytes as BytesJson; +use rpc::v1::types::{Bytes as BytesJson, H264}; use serde_json::Value as Json; use std::ops::Deref; use std::sync::Arc; @@ -312,6 +313,13 @@ impl MarketCoinOps for SiaCoin { Ok(address.to_string()) } + fn address_from_pubkey(&self, _pubkey: &H264) -> MmResult { + // FIXME: How to convert our H264 to H256 (ed25519_dalek pubkeys)? + // let address = SpendPolicy::PublicKey(*pubkey).address(); + // Ok(address.to_string()) + Ok("dummy_address".to_string()) + } + async fn get_public_key(&self) -> Result> { unimplemented!() } fn sign_message_hash(&self, _message: &str) -> Option<[u8; 32]> { unimplemented!() } diff --git a/mm2src/coins/tendermint/tendermint_coin.rs b/mm2src/coins/tendermint/tendermint_coin.rs index 4de40f9b74..ca2405ec53 100644 --- a/mm2src/coins/tendermint/tendermint_coin.rs +++ b/mm2src/coins/tendermint/tendermint_coin.rs @@ -4,7 +4,7 @@ use super::htlc::{ClaimHtlcMsg, ClaimHtlcProto, CreateHtlcMsg, CreateHtlcProto, use super::ibc::transfer_v1::MsgTransfer; use super::ibc::IBC_GAS_LIMIT_DEFAULT; use super::{rpc::*, TENDERMINT_COIN_PROTOCOL_TYPE}; -use crate::coin_errors::{MyAddressError, ValidatePaymentError, ValidatePaymentResult}; +use crate::coin_errors::{AddressFromPubkeyError, MyAddressError, ValidatePaymentError, ValidatePaymentResult}; use crate::hd_wallet::{HDPathAccountToAddressId, WithdrawFrom}; use crate::rpc_command::tendermint::staking::{ClaimRewardsPayload, Delegation, DelegationPayload, DelegationsQueryResponse, Undelegation, UndelegationEntry, @@ -81,7 +81,7 @@ use num_traits::Zero; use parking_lot::Mutex as PaMutex; use primitives::hash::H256; use regex::Regex; -use rpc::v1::types::Bytes as BytesJson; +use rpc::v1::types::{Bytes as BytesJson, H264}; use serde_json::{self as json, Value as Json}; use std::collections::HashMap; use std::convert::{TryFrom, TryInto}; @@ -3308,6 +3308,13 @@ impl MarketCoinOps for TendermintCoin { fn my_address(&self) -> MmResult { Ok(self.account_id.to_string()) } + fn address_from_pubkey(&self, pubkey: &H264) -> MmResult { + let pubkey_hash = dhash160(&pubkey.0); + let address = AccountId::new(&self.account_prefix, pubkey_hash.as_slice()) + .map_err(|e| AddressFromPubkeyError::InternalError(e.to_string()))?; + Ok(address.to_string()) + } + async fn get_public_key(&self) -> Result> { let key = SigningKey::from_slice(self.activation_policy.activated_key_or_err()?.as_slice()) .expect("privkey validity is checked on coin creation"); diff --git a/mm2src/coins/tendermint/tendermint_token.rs b/mm2src/coins/tendermint/tendermint_token.rs index eaee2abeb2..ce1c665717 100644 --- a/mm2src/coins/tendermint/tendermint_token.rs +++ b/mm2src/coins/tendermint/tendermint_token.rs @@ -3,7 +3,7 @@ use super::ibc::IBC_GAS_LIMIT_DEFAULT; use super::{create_withdraw_msg_as_any, TendermintCoin, TendermintFeeDetails, GAS_LIMIT_DEFAULT, MIN_TX_SATOSHIS, TIMEOUT_HEIGHT_DELTA, TX_DEFAULT_MEMO}; -use crate::coin_errors::ValidatePaymentResult; +use crate::coin_errors::{AddressFromPubkeyError, ValidatePaymentResult}; use crate::utxo::utxo_common::big_decimal_from_sat; use crate::{big_decimal_from_sat_unsigned, utxo::sat_from_big_decimal, BalanceFut, BigDecimal, CheckIfMyPaymentSentArgs, CoinBalance, ConfirmPaymentInput, DexFee, FeeApproxStage, FoundSwapTxSpend, @@ -28,7 +28,7 @@ use keys::KeyPair; use mm2_core::mm_ctx::MmArc; use mm2_err_handle::prelude::*; use mm2_number::MmNumber; -use rpc::v1::types::Bytes as BytesJson; +use rpc::v1::types::{Bytes as BytesJson, H264}; use serde_json::Value as Json; use std::ops::Deref; use std::str::FromStr; @@ -263,6 +263,10 @@ impl MarketCoinOps for TendermintToken { fn my_address(&self) -> MmResult { self.platform_coin.my_address() } + fn address_from_pubkey(&self, pubkey: &H264) -> MmResult { + self.platform_coin.address_from_pubkey(pubkey) + } + async fn get_public_key(&self) -> Result> { self.platform_coin.get_public_key().await } diff --git a/mm2src/coins/test_coin.rs b/mm2src/coins/test_coin.rs index ce2511b5b0..accddd1520 100644 --- a/mm2src/coins/test_coin.rs +++ b/mm2src/coins/test_coin.rs @@ -3,7 +3,7 @@ use super::{CoinBalance, CommonSwapOpsV2, FindPaymentSpendError, FundingTxSpend, HistorySyncState, MarketCoinOps, MmCoin, RawTransactionFut, RawTransactionRequest, RefundTakerPaymentArgs, SearchForFundingSpendErr, SwapOps, TradeFee, TransactionEnum, TransactionFut}; -use crate::coin_errors::ValidatePaymentResult; +use crate::coin_errors::{AddressFromPubkeyError, ValidatePaymentResult}; use crate::hd_wallet::AddrToString; use crate::{coin_errors::MyAddressError, BalanceFut, CanRefundHtlc, CheckIfMyPaymentSentArgs, ConfirmPaymentInput, FeeApproxStage, FoundSwapTxSpend, GenPreimageResult, GenTakerFundingSpendArgs, GenTakerPaymentSpendArgs, @@ -28,7 +28,7 @@ use mm2_err_handle::prelude::*; use mm2_number::{BigDecimal, MmNumber}; #[cfg(any(test, feature = "for-tests"))] use mocktopus::macros::*; -use rpc::v1::types::Bytes as BytesJson; +use rpc::v1::types::{Bytes as BytesJson, H264}; use serde_json::Value as Json; use std::fmt::{Display, Formatter}; use std::ops::Deref; @@ -65,6 +65,8 @@ impl MarketCoinOps for TestCoin { fn my_address(&self) -> MmResult { unimplemented!() } + fn address_from_pubkey(&self, _pubkey: &H264) -> MmResult { unimplemented!() } + async fn get_public_key(&self) -> Result> { unimplemented!() } fn sign_message_hash(&self, _message: &str) -> Option<[u8; 32]> { unimplemented!() } diff --git a/mm2src/coins/utxo/bch.rs b/mm2src/coins/utxo/bch.rs index e38a59ce27..9ca4f27380 100644 --- a/mm2src/coins/utxo/bch.rs +++ b/mm2src/coins/utxo/bch.rs @@ -1,6 +1,6 @@ use super::*; use crate::coin_balance::{EnableCoinBalanceError, HDAddressBalance, HDWalletBalance, HDWalletBalanceOps}; -use crate::coin_errors::{MyAddressError, ValidatePaymentResult}; +use crate::coin_errors::{AddressFromPubkeyError, MyAddressError, ValidatePaymentResult}; use crate::hd_wallet::{ExtractExtendedPubkey, HDCoinAddress, HDCoinWithdrawOps, HDExtractPubkeyError, HDXPubExtractor, TrezorCoinError, WithdrawSenderAddress}; use crate::my_tx_history_v2::{CoinWithTxHistoryV2, MyTxHistoryErrorV2, MyTxHistoryTarget, TxDetailsBuilder, @@ -34,6 +34,7 @@ use keys::CashAddress; pub use keys::NetworkPrefix as CashAddrPrefix; use mm2_metrics::MetricsArc; use mm2_number::MmNumber; +use rpc::v1::types::H264; use serde_json::{self as json, Value as Json}; use serialization::{deserialize, CoinVariant}; use std::sync::MutexGuard; @@ -1138,6 +1139,11 @@ impl MarketCoinOps for BchCoin { fn my_address(&self) -> MmResult { utxo_common::my_address(self) } + fn address_from_pubkey(&self, pubkey: &H264) -> MmResult { + let pubkey = Public::Compressed((*pubkey).into()); + Ok(UtxoCommonOps::address_from_pubkey(self, &pubkey).to_string()) + } + async fn get_public_key(&self) -> Result> { let pubkey = utxo_common::my_public_key(&self.utxo_arc)?; Ok(pubkey.to_string()) diff --git a/mm2src/coins/utxo/qtum.rs b/mm2src/coins/utxo/qtum.rs index 7701a84f4a..5e5f33eab1 100644 --- a/mm2src/coins/utxo/qtum.rs +++ b/mm2src/coins/utxo/qtum.rs @@ -2,7 +2,7 @@ use super::utxo_common::utxo_prepare_addresses_for_balance_stream_if_enabled; use super::*; use crate::coin_balance::{self, EnableCoinBalanceError, EnabledCoinBalanceParams, HDAccountBalance, HDAddressBalance, HDWalletBalance, HDWalletBalanceOps}; -use crate::coin_errors::{MyAddressError, ValidatePaymentResult}; +use crate::coin_errors::{AddressFromPubkeyError, MyAddressError, ValidatePaymentResult}; use crate::hd_wallet::{ExtractExtendedPubkey, HDCoinAddress, HDCoinWithdrawOps, HDConfirmAddress, HDExtractPubkeyError, HDXPubExtractor, TrezorCoinError, WithdrawSenderAddress}; use crate::my_tx_history_v2::{CoinWithTxHistoryV2, MyTxHistoryErrorV2, MyTxHistoryTarget, TxHistoryStorage}; @@ -40,6 +40,7 @@ use futures::{FutureExt, TryFutureExt}; use keys::AddressHashEnum; use mm2_metrics::MetricsArc; use mm2_number::MmNumber; +use rpc::v1::types::H264; use serde::Serialize; use serialization::CoinVariant; use utxo_signer::UtxoSignerOps; @@ -761,6 +762,11 @@ impl MarketCoinOps for QtumCoin { fn my_address(&self) -> MmResult { utxo_common::my_address(self) } + fn address_from_pubkey(&self, pubkey: &H264) -> MmResult { + let pubkey = Public::Compressed((*pubkey).into()); + Ok(UtxoCommonOps::address_from_pubkey(self, &pubkey).to_string()) + } + async fn get_public_key(&self) -> Result> { let pubkey = utxo_common::my_public_key(&self.utxo_arc)?; Ok(pubkey.to_string()) diff --git a/mm2src/coins/utxo/slp.rs b/mm2src/coins/utxo/slp.rs index 05fb8b816b..5b49573f4c 100644 --- a/mm2src/coins/utxo/slp.rs +++ b/mm2src/coins/utxo/slp.rs @@ -3,7 +3,7 @@ //! Tracking issue: https://github.com/KomodoPlatform/atomicDEX-API/issues/701 //! More info about the protocol and implementation guides can be found at https://slp.dev/ -use crate::coin_errors::{MyAddressError, ValidatePaymentError, ValidatePaymentResult}; +use crate::coin_errors::{AddressFromPubkeyError, MyAddressError, ValidatePaymentError, ValidatePaymentResult}; use crate::my_tx_history_v2::{CoinWithTxHistoryV2, MyTxHistoryErrorV2, MyTxHistoryTarget}; use crate::tx_history_storage::{GetTxHistoryFilters, WalletId}; use crate::utxo::bch::BchCoin; @@ -44,7 +44,7 @@ use mm2_core::mm_ctx::MmArc; use mm2_err_handle::prelude::*; use mm2_number::{BigDecimal, MmNumber}; use primitives::hash::H256; -use rpc::v1::types::{Bytes as BytesJson, ToTxHash, H256 as H256Json}; +use rpc::v1::types::{Bytes as BytesJson, ToTxHash, H256 as H256Json, H264}; use script::bytes::Bytes; use script::{Builder as ScriptBuilder, Opcode, Script, TransactionInputSigner}; use serde_json::Value as Json; @@ -1107,6 +1107,10 @@ impl MarketCoinOps for SlpToken { slp_address.encode().map_to_mm(MyAddressError::InternalError) } + fn address_from_pubkey(&self, pubkey: &H264) -> MmResult { + MarketCoinOps::address_from_pubkey(&self.platform_coin, pubkey) + } + async fn get_public_key(&self) -> Result> { let pubkey = utxo_common::my_public_key(self.platform_coin.as_ref())?; Ok(pubkey.to_string()) @@ -1127,7 +1131,7 @@ impl MarketCoinOps for SlpToken { let signature = CompactSignature::try_from(STANDARD.decode(signature)?) .map_to_mm(|err| VerificationError::SignatureDecodingError(err.to_string()))?; let pubkey = Public::recover_compact(&H256::from(message_hash), &signature)?; - let address_from_pubkey = self.platform_coin.address_from_pubkey(&pubkey); + let address_from_pubkey = UtxoCommonOps::address_from_pubkey(&self.platform_coin, &pubkey); let slp_address = self .platform_coin .slp_address(&address_from_pubkey) diff --git a/mm2src/coins/utxo/utxo_standard.rs b/mm2src/coins/utxo/utxo_standard.rs index 99a97d846f..bfb15c6b5a 100644 --- a/mm2src/coins/utxo/utxo_standard.rs +++ b/mm2src/coins/utxo/utxo_standard.rs @@ -2,7 +2,7 @@ use super::utxo_common::utxo_prepare_addresses_for_balance_stream_if_enabled; use super::*; use crate::coin_balance::{self, EnableCoinBalanceError, EnabledCoinBalanceParams, HDAccountBalance, HDAddressBalance, HDWalletBalance, HDWalletBalanceOps}; -use crate::coin_errors::{MyAddressError, ValidatePaymentResult}; +use crate::coin_errors::{AddressFromPubkeyError, MyAddressError, ValidatePaymentResult}; use crate::hd_wallet::{ExtractExtendedPubkey, HDCoinAddress, HDCoinWithdrawOps, HDConfirmAddress, HDExtractPubkeyError, HDXPubExtractor, TrezorCoinError, WithdrawSenderAddress}; use crate::my_tx_history_v2::{CoinWithTxHistoryV2, MyTxHistoryErrorV2, MyTxHistoryTarget, TxHistoryStorage}; @@ -43,6 +43,7 @@ use futures::{FutureExt, TryFutureExt}; use mm2_metrics::MetricsArc; use mm2_number::MmNumber; #[cfg(test)] use mocktopus::macros::*; +use rpc::v1::types::H264; use script::Opcode; use utxo_signer::UtxoSignerOps; @@ -852,6 +853,11 @@ impl MarketCoinOps for UtxoStandardCoin { fn my_address(&self) -> MmResult { utxo_common::my_address(self) } + fn address_from_pubkey(&self, pubkey: &H264) -> MmResult { + let pubkey = Public::Compressed((*pubkey).into()); + Ok(UtxoCommonOps::address_from_pubkey(self, &pubkey).to_string()) + } + fn sign_message_hash(&self, message: &str) -> Option<[u8; 32]> { utxo_common::sign_message_hash(self.as_ref(), message) } diff --git a/mm2src/coins/z_coin.rs b/mm2src/coins/z_coin.rs index e09d64c78e..75216745be 100644 --- a/mm2src/coins/z_coin.rs +++ b/mm2src/coins/z_coin.rs @@ -10,7 +10,7 @@ mod z_htlc; mod z_rpc; mod z_tx_history; -use crate::coin_errors::{MyAddressError, ValidatePaymentResult}; +use crate::coin_errors::{AddressFromPubkeyError, MyAddressError, ValidatePaymentResult}; use crate::hd_wallet::HDPathAccountToAddressId; use crate::my_tx_history_v2::{MyTxHistoryErrorV2, MyTxHistoryRequestV2, MyTxHistoryResponseV2}; use crate::rpc_command::init_withdraw::{InitWithdrawCoin, WithdrawInProgressStatus, WithdrawTaskHandleShared}; @@ -60,7 +60,7 @@ use mm2_err_handle::prelude::*; use mm2_number::{BigDecimal, MmNumber}; #[cfg(test)] use mocktopus::macros::*; use primitives::bytes::Bytes; -use rpc::v1::types::{Bytes as BytesJson, Transaction as RpcTransaction, H256 as H256Json}; +use rpc::v1::types::{Bytes as BytesJson, Transaction as RpcTransaction, H256 as H256Json, H264}; use script::{Builder as ScriptBuilder, Opcode, Script, TransactionInputSigner}; use serde_json::Value as Json; use serialization::CoinVariant; @@ -1129,6 +1129,11 @@ impl MarketCoinOps for ZCoin { fn my_address(&self) -> MmResult { Ok(self.z_fields.my_z_addr_encoded.clone()) } + fn address_from_pubkey(&self, _pubkey: &H264) -> MmResult { + // FIXME: How to derive the address from pubkey for zcoin? + Ok("dummy_address".to_string()) + } + async fn get_public_key(&self) -> Result> { let pubkey = utxo_common::my_public_key(self.as_ref())?; Ok(pubkey.to_string()) From 199b75b31a796391f070c827895725c57e863800 Mon Sep 17 00:00:00 2001 From: Omer Yacine Date: Mon, 31 Mar 2025 01:18:09 +0200 Subject: [PATCH 19/50] set address_dir in `SavedSwap`s initializations --- mm2src/mm2_main/src/lp_swap/maker_swap.rs | 8 ++-- .../src/lp_swap/recreate_swap_data.rs | 37 ++++++++++++++++--- mm2src/mm2_main/src/lp_swap/saved_swap.rs | 2 +- mm2src/mm2_main/src/lp_swap/taker_swap.rs | 8 ++-- 4 files changed, 40 insertions(+), 15 deletions(-) diff --git a/mm2src/mm2_main/src/lp_swap/maker_swap.rs b/mm2src/mm2_main/src/lp_swap/maker_swap.rs index 892c7b946b..b0c48bc063 100644 --- a/mm2src/mm2_main/src/lp_swap/maker_swap.rs +++ b/mm2src/mm2_main/src/lp_swap/maker_swap.rs @@ -93,14 +93,14 @@ pub fn stats_maker_swap_file_path(ctx: &MmArc, uuid: &Uuid) -> PathBuf { } async fn save_my_maker_swap_event(ctx: &MmArc, swap: &MakerSwap, event: MakerSavedEvent) -> Result<(), String> { - // let maker_coin_pub = swap.my_maker_coin_htlc_pub(); - let swap = match SavedSwap::load_my_swap_from_db(ctx, None, swap.uuid).await { + let maker_coin_pub = swap.my_maker_coin_htlc_pub(); + let maker_coin_address = try_s!(swap.maker_coin.address_from_pubkey(&maker_coin_pub)); + let swap = match SavedSwap::load_my_swap_from_db(ctx, Some(&maker_coin_address), swap.uuid).await { Ok(Some(swap)) => swap, Ok(None) => SavedSwap::Maker(MakerSavedSwap { uuid: swap.uuid, - // FIXME: Put a real address. #[cfg(all(not(target_arch = "wasm32"), feature = "new-db-arch"))] - address_dir: String::new(), + address_dir: maker_coin_address, my_order_uuid: swap.my_order_uuid, maker_amount: Some(swap.maker_amount.clone()), maker_coin: Some(swap.maker_coin.ticker().to_owned()), diff --git a/mm2src/mm2_main/src/lp_swap/recreate_swap_data.rs b/mm2src/mm2_main/src/lp_swap/recreate_swap_data.rs index 38cef1a6bb..ccc05523b4 100644 --- a/mm2src/mm2_main/src/lp_swap/recreate_swap_data.rs +++ b/mm2src/mm2_main/src/lp_swap/recreate_swap_data.rs @@ -73,16 +73,16 @@ pub async fn recreate_swap_data(ctx: MmArc, args: RecreateSwapRequest) -> Recrea }, InputSwap::SavedSwap(SavedSwap::Taker(taker_swap)) | InputSwap::TakerSavedSwap(taker_swap) => { recreate_maker_swap(ctx, taker_swap) + .await .map(SavedSwap::from) .map(|swap| RecreateSwapResponse { swap }) }, } } -fn recreate_maker_swap(ctx: MmArc, taker_swap: TakerSavedSwap) -> RecreateSwapResult { +async fn recreate_maker_swap(ctx: MmArc, taker_swap: TakerSavedSwap) -> RecreateSwapResult { let mut maker_swap = MakerSavedSwap { uuid: taker_swap.uuid, - // FIXME: Put a real address. Also check how the other end imports the swap and whether we can set the address from their #[cfg(all(not(target_arch = "wasm32"), feature = "new-db-arch"))] address_dir: String::new(), my_order_uuid: taker_swap.my_order_uuid, @@ -124,7 +124,7 @@ fn recreate_maker_swap(ctx: MmArc, taker_swap: TakerSavedSwap) -> RecreateSwapRe taker_p2p_pubkey.copy_from_slice(&started_event.my_persistent_pub.0[1..33]); let maker_started_event = MakerSwapEvent::Started(MakerSwapData { taker_coin: started_event.taker_coin, - maker_coin: started_event.maker_coin, + maker_coin: started_event.maker_coin.clone(), taker_pubkey: H256Json::from(taker_p2p_pubkey), // We could parse the `TakerSwapEvent::TakerPaymentSpent` event. // As for now, don't try to find the secret in the events since we can refund without it. @@ -179,6 +179,24 @@ fn recreate_maker_swap(ctx: MmArc, taker_swap: TakerSavedSwap) -> RecreateSwapRe .events .extend(convert_taker_to_maker_events(event_it, wait_refund_until)); + #[cfg(all(not(target_arch = "wasm32"), feature = "new-db-arch"))] + { + // FIXME: Discuss: Here we do our best effort to retrieve the maker coin address from the known swap data. + // The maker coin might not be available at this point where we recreating the swap though. + // What about returning the pubkey and letting the swap importer convert it to an address themselves? + let maker_coin_ticker = started_event.maker_coin; + let maker_coin = lp_coinfind(&ctx, &maker_coin_ticker) + .await + .map_to_mm(RecreateSwapError::Internal)? + .or_mm_err(move || RecreateSwapError::NoSuchCoin { + coin: maker_coin_ticker, + })?; + maker_swap.address_dir = negotiated_event + .maker_coin_htlc_pubkey + .and_then(|pubkey| maker_coin.address_from_pubkey(&pubkey).ok()) + .unwrap_or("Couldn't get the maker coin address. Please set it manually.".to_string()); + } + Ok(maker_swap) } @@ -288,7 +306,6 @@ fn convert_taker_to_maker_events( async fn recreate_taker_swap(ctx: MmArc, maker_swap: MakerSavedSwap) -> RecreateSwapResult { let mut taker_swap = TakerSavedSwap { uuid: maker_swap.uuid, - // FIXME: Put a real address. Also check how the other end imports the swap and whether we can set the address from their #[cfg(all(not(target_arch = "wasm32"), feature = "new-db-arch"))] address_dir: String::new(), my_order_uuid: Some(maker_swap.uuid), @@ -388,6 +405,14 @@ async fn recreate_taker_swap(ctx: MmArc, maker_swap: MakerSavedSwap) -> Recreate coin: maker_coin_ticker, })?; + #[cfg(all(not(target_arch = "wasm32"), feature = "new-db-arch"))] + { + taker_swap.address_dir = negotiated_event + .maker_coin_htlc_pubkey + .and_then(|pubkey| maker_coin.address_from_pubkey(&pubkey).ok()) + .unwrap_or("Couldn't get the maker coin address. Please set it manually.".to_string()); + } + // Then we can continue to process success Maker events. let wait_refund_until = negotiated_event.taker_payment_locktime + 3700; taker_swap @@ -515,7 +540,7 @@ mod tests { let ctx = MmCtxBuilder::default().into_mm_arc(); - let maker_actual_swap = recreate_maker_swap(ctx, taker_saved_swap).expect("!recreate_maker_swap"); + let maker_actual_swap = block_on(recreate_maker_swap(ctx, taker_saved_swap)).expect("!recreate_maker_swap"); println!("{}", json::to_string(&maker_actual_swap).unwrap()); assert_eq!(maker_actual_swap, maker_expected_swap); } @@ -533,7 +558,7 @@ mod tests { let ctx = MmCtxBuilder::default().into_mm_arc(); - let maker_actual_swap = recreate_maker_swap(ctx, taker_saved_swap).expect("!recreate_maker_swap"); + let maker_actual_swap = block_on(recreate_maker_swap(ctx, taker_saved_swap)).expect("!recreate_maker_swap"); println!("{}", json::to_string(&maker_actual_swap).unwrap()); assert_eq!(maker_actual_swap, maker_expected_swap); } diff --git a/mm2src/mm2_main/src/lp_swap/saved_swap.rs b/mm2src/mm2_main/src/lp_swap/saved_swap.rs index f866b97595..f66da80358 100644 --- a/mm2src/mm2_main/src/lp_swap/saved_swap.rs +++ b/mm2src/mm2_main/src/lp_swap/saved_swap.rs @@ -225,7 +225,7 @@ mod native_impl { optional_address_dir: Option<&str>, uuid: Uuid, ) -> SavedSwapResult> { - // FIXME: Set the correct address directory for the new db arch branch. + // TODO(new-db-arch): Set the correct address directory for the new db arch branch (via a query to the global DB). #[cfg(feature = "new-db-arch")] let address_dir = optional_address_dir.unwrap_or("Fetch the address directory from the global DB given the UUID."); diff --git a/mm2src/mm2_main/src/lp_swap/taker_swap.rs b/mm2src/mm2_main/src/lp_swap/taker_swap.rs index 3b2444e5a2..10919b11ed 100644 --- a/mm2src/mm2_main/src/lp_swap/taker_swap.rs +++ b/mm2src/mm2_main/src/lp_swap/taker_swap.rs @@ -116,14 +116,14 @@ pub fn stats_taker_swap_file_path(ctx: &MmArc, uuid: &Uuid) -> PathBuf { } async fn save_my_taker_swap_event(ctx: &MmArc, swap: &TakerSwap, event: TakerSavedEvent) -> Result<(), String> { - // let maker_coin_pub = swap.my_maker_coin_htlc_pub(); - let swap = match SavedSwap::load_my_swap_from_db(ctx, None, swap.uuid).await { + let maker_coin_pub = swap.my_maker_coin_htlc_pub(); + let maker_coin_address = try_s!(swap.maker_coin.address_from_pubkey(&maker_coin_pub)); + let swap = match SavedSwap::load_my_swap_from_db(ctx, Some(&maker_coin_address), swap.uuid).await { Ok(Some(swap)) => swap, Ok(None) => SavedSwap::Taker(TakerSavedSwap { uuid: swap.uuid, - // FIXME: Put a real address. #[cfg(all(not(target_arch = "wasm32"), feature = "new-db-arch"))] - address_dir: String::new(), + address_dir: maker_coin_address, my_order_uuid: swap.my_order_uuid, maker_amount: Some(swap.maker_amount.to_decimal()), maker_coin: Some(swap.maker_coin.ticker().to_owned()), From 212d18847c8f5132b8953432d7c53bc4debcc09c Mon Sep 17 00:00:00 2001 From: Omer Yacine Date: Thu, 3 Apr 2025 11:57:32 +0200 Subject: [PATCH 20/50] review(onur): remove optional_ from parameter name as it's obvious from its type --- mm2src/mm2_main/src/lp_swap/saved_swap.rs | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/mm2src/mm2_main/src/lp_swap/saved_swap.rs b/mm2src/mm2_main/src/lp_swap/saved_swap.rs index f66da80358..bac462ef53 100644 --- a/mm2src/mm2_main/src/lp_swap/saved_swap.rs +++ b/mm2src/mm2_main/src/lp_swap/saved_swap.rs @@ -169,7 +169,7 @@ impl SavedSwap { pub trait SavedSwapIo { async fn load_my_swap_from_db( ctx: &MmArc, - optional_address_dir: Option<&str>, + address_dir: Option<&str>, uuid: Uuid, ) -> SavedSwapResult>; @@ -222,16 +222,14 @@ mod native_impl { impl SavedSwapIo for SavedSwap { async fn load_my_swap_from_db( ctx: &MmArc, - optional_address_dir: Option<&str>, + address_dir: Option<&str>, uuid: Uuid, ) -> SavedSwapResult> { // TODO(new-db-arch): Set the correct address directory for the new db arch branch (via a query to the global DB). #[cfg(feature = "new-db-arch")] - let address_dir = - optional_address_dir.unwrap_or("Fetch the address directory from the global DB given the UUID."); + let address_dir = address_dir.unwrap_or("Fetch the address directory from the global DB given the UUID."); #[cfg(not(feature = "new-db-arch"))] - let address_dir = - optional_address_dir.unwrap_or("no address directory for old DB architecture (has no effect)"); + let address_dir = address_dir.unwrap_or("no address directory for old DB architecture (has no effect)"); let path = my_swap_file_path(ctx, address_dir, &uuid); Ok(read_json(&path).await?) } @@ -413,7 +411,7 @@ mod wasm_impl { impl SavedSwapIo for SavedSwap { async fn load_my_swap_from_db( ctx: &MmArc, - _optional_address_dir: Option<&str>, + _address_dir: Option<&str>, uuid: Uuid, ) -> SavedSwapResult> { let swaps_ctx = SwapsContext::from_ctx(ctx).map_to_mm(SavedSwapError::InternalError)?; From b896af6bcf6a3632e9734ca7f103ba8da43c7c81 Mon Sep 17 00:00:00 2001 From: Omer Yacine Date: Thu, 3 Apr 2025 14:58:11 +0200 Subject: [PATCH 21/50] review(onur): rename address_dir to maker_address in SavedSwaps as the name address_dir is way off-topic for the struct --- mm2src/mm2_main/src/lp_swap/maker_swap.rs | 6 +++--- mm2src/mm2_main/src/lp_swap/recreate_swap_data.rs | 8 ++++---- mm2src/mm2_main/src/lp_swap/saved_swap.rs | 8 ++++---- mm2src/mm2_main/src/lp_swap/taker_swap.rs | 4 ++-- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/mm2src/mm2_main/src/lp_swap/maker_swap.rs b/mm2src/mm2_main/src/lp_swap/maker_swap.rs index b0c48bc063..1d7c6bd7a6 100644 --- a/mm2src/mm2_main/src/lp_swap/maker_swap.rs +++ b/mm2src/mm2_main/src/lp_swap/maker_swap.rs @@ -100,7 +100,7 @@ async fn save_my_maker_swap_event(ctx: &MmArc, swap: &MakerSwap, event: MakerSav Ok(None) => SavedSwap::Maker(MakerSavedSwap { uuid: swap.uuid, #[cfg(all(not(target_arch = "wasm32"), feature = "new-db-arch"))] - address_dir: maker_coin_address, + maker_address: maker_coin_address, my_order_uuid: swap.my_order_uuid, maker_amount: Some(swap.maker_amount.clone()), maker_coin: Some(swap.maker_coin.ticker().to_owned()), @@ -1865,7 +1865,7 @@ impl MakerSwapStatusChanged { pub struct MakerSavedSwap { pub uuid: Uuid, #[cfg(all(not(target_arch = "wasm32"), feature = "new-db-arch"))] - pub address_dir: String, + pub maker_address: String, pub my_order_uuid: Option, pub events: Vec, pub maker_amount: Option, @@ -1923,7 +1923,7 @@ impl MakerSavedSwap { MakerSavedSwap { uuid: Default::default(), #[cfg(all(not(target_arch = "wasm32"), feature = "new-db-arch"))] - address_dir: "".to_string(), + maker_address: "".to_string(), my_order_uuid: None, events, maker_amount: Some(maker_amount.to_decimal()), diff --git a/mm2src/mm2_main/src/lp_swap/recreate_swap_data.rs b/mm2src/mm2_main/src/lp_swap/recreate_swap_data.rs index ccc05523b4..4b879e4b37 100644 --- a/mm2src/mm2_main/src/lp_swap/recreate_swap_data.rs +++ b/mm2src/mm2_main/src/lp_swap/recreate_swap_data.rs @@ -84,7 +84,7 @@ async fn recreate_maker_swap(ctx: MmArc, taker_swap: TakerSavedSwap) -> Recreate let mut maker_swap = MakerSavedSwap { uuid: taker_swap.uuid, #[cfg(all(not(target_arch = "wasm32"), feature = "new-db-arch"))] - address_dir: String::new(), + maker_address: String::new(), my_order_uuid: taker_swap.my_order_uuid, events: Vec::new(), maker_amount: taker_swap.maker_amount, @@ -191,7 +191,7 @@ async fn recreate_maker_swap(ctx: MmArc, taker_swap: TakerSavedSwap) -> Recreate .or_mm_err(move || RecreateSwapError::NoSuchCoin { coin: maker_coin_ticker, })?; - maker_swap.address_dir = negotiated_event + maker_swap.maker_address = negotiated_event .maker_coin_htlc_pubkey .and_then(|pubkey| maker_coin.address_from_pubkey(&pubkey).ok()) .unwrap_or("Couldn't get the maker coin address. Please set it manually.".to_string()); @@ -307,7 +307,7 @@ async fn recreate_taker_swap(ctx: MmArc, maker_swap: MakerSavedSwap) -> Recreate let mut taker_swap = TakerSavedSwap { uuid: maker_swap.uuid, #[cfg(all(not(target_arch = "wasm32"), feature = "new-db-arch"))] - address_dir: String::new(), + maker_address: String::new(), my_order_uuid: Some(maker_swap.uuid), events: Vec::new(), maker_amount: maker_swap.maker_amount, @@ -407,7 +407,7 @@ async fn recreate_taker_swap(ctx: MmArc, maker_swap: MakerSavedSwap) -> Recreate #[cfg(all(not(target_arch = "wasm32"), feature = "new-db-arch"))] { - taker_swap.address_dir = negotiated_event + taker_swap.maker_address = negotiated_event .maker_coin_htlc_pubkey .and_then(|pubkey| maker_coin.address_from_pubkey(&pubkey).ok()) .unwrap_or("Couldn't get the maker coin address. Please set it manually.".to_string()); diff --git a/mm2src/mm2_main/src/lp_swap/saved_swap.rs b/mm2src/mm2_main/src/lp_swap/saved_swap.rs index bac462ef53..158843dadb 100644 --- a/mm2src/mm2_main/src/lp_swap/saved_swap.rs +++ b/mm2src/mm2_main/src/lp_swap/saved_swap.rs @@ -76,10 +76,10 @@ impl SavedSwap { } #[cfg(all(not(target_arch = "wasm32"), feature = "new-db-arch"))] - pub fn address_dir(&self) -> &str { + pub fn maker_address(&self) -> &str { match self { - SavedSwap::Maker(swap) => &swap.address_dir, - SavedSwap::Taker(swap) => &swap.address_dir, + SavedSwap::Maker(swap) => &swap.maker_address, + SavedSwap::Taker(swap) => &swap.maker_address, } } @@ -269,7 +269,7 @@ mod native_impl { async fn save_to_db(&self, ctx: &MmArc) -> SavedSwapResult<()> { #[cfg(feature = "new-db-arch")] - let address_dir = self.address_dir(); + let address_dir = self.maker_address(); #[cfg(not(feature = "new-db-arch"))] let address_dir = "no address directory for old DB architecture (has no effect)"; let path = my_swap_file_path(ctx, address_dir, self.uuid()); diff --git a/mm2src/mm2_main/src/lp_swap/taker_swap.rs b/mm2src/mm2_main/src/lp_swap/taker_swap.rs index 10919b11ed..0bb99b0898 100644 --- a/mm2src/mm2_main/src/lp_swap/taker_swap.rs +++ b/mm2src/mm2_main/src/lp_swap/taker_swap.rs @@ -123,7 +123,7 @@ async fn save_my_taker_swap_event(ctx: &MmArc, swap: &TakerSwap, event: TakerSav Ok(None) => SavedSwap::Taker(TakerSavedSwap { uuid: swap.uuid, #[cfg(all(not(target_arch = "wasm32"), feature = "new-db-arch"))] - address_dir: maker_coin_address, + maker_address: maker_coin_address, my_order_uuid: swap.my_order_uuid, maker_amount: Some(swap.maker_amount.to_decimal()), maker_coin: Some(swap.maker_coin.ticker().to_owned()), @@ -214,7 +214,7 @@ impl TakerSavedEvent { pub struct TakerSavedSwap { pub uuid: Uuid, #[cfg(all(not(target_arch = "wasm32"), feature = "new-db-arch"))] - pub address_dir: String, + pub maker_address: String, pub my_order_uuid: Option, pub events: Vec, pub maker_amount: Option, From bb47ee265aae02538e1469c41848da3faa21a8af Mon Sep 17 00:00:00 2001 From: Omer Yacine Date: Thu, 3 Apr 2025 15:15:03 +0200 Subject: [PATCH 22/50] review(onur): add more comments for clairty in new mm2_io functions namely write() & create_parents() --- mm2src/mm2_io/src/fs.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/mm2src/mm2_io/src/fs.rs b/mm2src/mm2_io/src/fs.rs index abac94279d..618b4714bc 100644 --- a/mm2src/mm2_io/src/fs.rs +++ b/mm2src/mm2_io/src/fs.rs @@ -271,7 +271,7 @@ where read_files_with_extension(dir_path, "json").await } -/// Creates all the directories along the path to a file. +/// Creates all the directories along the path to a file if they do not exist. pub fn create_parents(path: &dyn AsRef) -> IoResult<()> { let parent_dir = path.as_ref().parent(); let Some(parent_dir) = parent_dir else { @@ -294,6 +294,11 @@ pub fn create_parents(path: &dyn AsRef) -> IoResult<()> { Ok(()) } +/// Writes the `content` to the file at `path`. +/// +/// This also creates any intermediary directories up to the file itself if they do not exist. +/// If `use_tmp_file` is true, it writes to a temporary file first and then renames it to the final file name +/// to ensure atomicity. pub fn write(path: &dyn AsRef, content: &[u8], use_tmp_file: bool) -> IoResult<()> { // Create all the directories in the path. create_parents(path)?; From b3b33843cabfe7541e6a35a151cf41542343d30b Mon Sep 17 00:00:00 2001 From: Omer Yacine Date: Thu, 3 Apr 2025 15:24:58 +0200 Subject: [PATCH 23/50] review(alina): say something if fs::rename() fails don't just be quiet --- mm2src/mm2_io/src/fs.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mm2src/mm2_io/src/fs.rs b/mm2src/mm2_io/src/fs.rs index 618b4714bc..394f91bb2f 100644 --- a/mm2src/mm2_io/src/fs.rs +++ b/mm2src/mm2_io/src/fs.rs @@ -310,7 +310,7 @@ pub fn write(path: &dyn AsRef, content: &[u8], use_tmp_file: bool) -> IoRe // Write the file content into the temp file and then rename the temp file into the desired name. fs::write(&path_tmp, content)?; if use_tmp_file { - fs::rename(&path_tmp, path.as_ref())?; + fs::rename(&path_tmp, path.as_ref()).error_log_passthrough()? } Ok(()) } From 7bcd1192cffac4ccbc188a1dc447b89b0bbd0d02 Mon Sep 17 00:00:00 2001 From: Omer Yacine Date: Fri, 4 Apr 2025 13:23:51 +0200 Subject: [PATCH 24/50] don't feature gate global_dir() to bridge the code between new-db-arch and not(new-db-arch) more. thus we can use things like if cfg!() {} instead of #[cfg(feature = ...)] --- mm2src/mm2_core/src/mm_ctx.rs | 9 +++++++-- mm2src/mm2_main/src/lp_swap/maker_swap.rs | 7 +------ mm2src/mm2_main/src/lp_swap/swap_lock.rs | 12 ++++++++---- mm2src/mm2_main/src/lp_swap/taker_swap.rs | 7 +------ 4 files changed, 17 insertions(+), 18 deletions(-) diff --git a/mm2src/mm2_core/src/mm_ctx.rs b/mm2src/mm2_core/src/mm_ctx.rs index 5c45d9898d..694370b30e 100644 --- a/mm2src/mm2_core/src/mm_ctx.rs +++ b/mm2src/mm2_core/src/mm_ctx.rs @@ -349,8 +349,13 @@ impl MmCtx { /// /// Such directory isn't bound to a specific seed/wallet or address. /// Data that should be stored there is public and shared between all seeds and addresses (e.g. stats, block headers, etc...). - #[cfg(all(feature = "new-db-arch", not(target_arch = "wasm32")))] - pub fn global_dir(&self) -> PathBuf { self.db_root().join("global") } + #[cfg(not(target_arch = "wasm32"))] + pub fn global_dir(&self) -> PathBuf { + if cfg!(not(feature = "new-db-arch")) { + return self.dbdir(); + } + self.db_root().join("global") + } /// Returns the path to wallet's data directory. /// diff --git a/mm2src/mm2_main/src/lp_swap/maker_swap.rs b/mm2src/mm2_main/src/lp_swap/maker_swap.rs index 1d7c6bd7a6..d16ec140cc 100644 --- a/mm2src/mm2_main/src/lp_swap/maker_swap.rs +++ b/mm2src/mm2_main/src/lp_swap/maker_swap.rs @@ -80,12 +80,7 @@ pub const MAKER_ERROR_EVENTS: [&str; 15] = [ pub const MAKER_PAYMENT_SENT_LOG: &str = "Maker payment sent"; #[cfg(not(target_arch = "wasm32"))] -pub fn stats_maker_swap_dir(ctx: &MmArc) -> PathBuf { - #[cfg(not(feature = "new-db-arch"))] - return ctx.dbdir().join("SWAPS").join("STATS").join("MAKER"); - #[cfg(feature = "new-db-arch")] - return ctx.global_dir().join("SWAPS").join("STATS").join("MAKER"); -} +pub fn stats_maker_swap_dir(ctx: &MmArc) -> PathBuf { ctx.global_dir().join("SWAPS").join("STATS").join("MAKER") } #[cfg(not(target_arch = "wasm32"))] pub fn stats_maker_swap_file_path(ctx: &MmArc, uuid: &Uuid) -> PathBuf { diff --git a/mm2src/mm2_main/src/lp_swap/swap_lock.rs b/mm2src/mm2_main/src/lp_swap/swap_lock.rs index f95ef0bcce..ff9b592ad2 100644 --- a/mm2src/mm2_main/src/lp_swap/swap_lock.rs +++ b/mm2src/mm2_main/src/lp_swap/swap_lock.rs @@ -56,10 +56,14 @@ mod native_lock { #[async_trait] impl SwapLockOps for SwapLock { async fn lock(ctx: &MmArc, swap_uuid: Uuid, ttl_sec: f64) -> SwapLockResult> { - #[cfg(feature = "new-db-arch")] - let lock_path = ctx.global_dir().join(format!("{}.lock", swap_uuid)); - #[cfg(not(feature = "new-db-arch"))] - let lock_path = ctx.dbdir().join("SWAPS").join("MY").join(format!("{}.lock", swap_uuid)); + let lock_path = if cfg!(feature = "new-db-arch") { + ctx.global_dir().join(format!("{}.lock", swap_uuid)) + } else { + ctx.global_dir() + .join("SWAPS") + .join("MY") + .join(format!("{}.lock", swap_uuid)) + }; let file_lock = some_or_return_ok_none!(FileLock::lock(lock_path, ttl_sec)?); Ok(Some(SwapLock { file_lock })) diff --git a/mm2src/mm2_main/src/lp_swap/taker_swap.rs b/mm2src/mm2_main/src/lp_swap/taker_swap.rs index 0bb99b0898..f4b52db12f 100644 --- a/mm2src/mm2_main/src/lp_swap/taker_swap.rs +++ b/mm2src/mm2_main/src/lp_swap/taker_swap.rs @@ -103,12 +103,7 @@ pub const WATCHER_MESSAGE_SENT_LOG: &str = "Watcher message sent..."; pub const MAKER_PAYMENT_SPENT_BY_WATCHER_LOG: &str = "Maker payment is spent by the watcher..."; #[cfg(not(target_arch = "wasm32"))] -pub fn stats_taker_swap_dir(ctx: &MmArc) -> PathBuf { - #[cfg(not(feature = "new-db-arch"))] - return ctx.dbdir().join("SWAPS").join("STATS").join("TAKER"); - #[cfg(feature = "new-db-arch")] - return ctx.global_dir().join("SWAPS").join("STATS").join("TAKER"); -} +pub fn stats_taker_swap_dir(ctx: &MmArc) -> PathBuf { ctx.global_dir().join("SWAPS").join("STATS").join("TAKER") } #[cfg(not(target_arch = "wasm32"))] pub fn stats_taker_swap_file_path(ctx: &MmArc, uuid: &Uuid) -> PathBuf { From 3ab56aba99dc6fd1b213ea700f7b52a65b61b37d Mon Sep 17 00:00:00 2001 From: Omer Yacine Date: Fri, 4 Apr 2025 13:30:09 +0200 Subject: [PATCH 25/50] nest swap locks inside a `swap_locks` directory inside the global_dir but first, we had to `create_parents` for such a file lock before trying to write it. as `swap_locks` intermediary directory might have not been created before --- mm2src/mm2_io/src/file_lock.rs | 6 ++++++ mm2src/mm2_main/src/lp_swap/swap_lock.rs | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/mm2src/mm2_io/src/file_lock.rs b/mm2src/mm2_io/src/file_lock.rs index 9a2e04bdef..334919a44f 100644 --- a/mm2src/mm2_io/src/file_lock.rs +++ b/mm2src/mm2_io/src/file_lock.rs @@ -4,6 +4,8 @@ use gstuff::now_float; use mm2_err_handle::prelude::*; use std::path::{Path, PathBuf}; +use crate::fs::create_parents; + pub type FileLockResult = std::result::Result>; #[derive(Debug, Display)] @@ -45,6 +47,10 @@ fn read_timestamp(path: &dyn AsRef) -> FileLockResult> { impl> FileLock { pub fn lock(lock_path: T, ttl_sec: f64) -> FileLockResult>> { + create_parents(&lock_path.as_ref()).map_err(|e| FileLockError::ErrorCreatingLockFile { + path: lock_path.as_ref().to_path_buf(), + error: e.to_string(), + })?; match std::fs::OpenOptions::new() .write(true) .create_new(true) diff --git a/mm2src/mm2_main/src/lp_swap/swap_lock.rs b/mm2src/mm2_main/src/lp_swap/swap_lock.rs index ff9b592ad2..38591deeff 100644 --- a/mm2src/mm2_main/src/lp_swap/swap_lock.rs +++ b/mm2src/mm2_main/src/lp_swap/swap_lock.rs @@ -57,7 +57,7 @@ mod native_lock { impl SwapLockOps for SwapLock { async fn lock(ctx: &MmArc, swap_uuid: Uuid, ttl_sec: f64) -> SwapLockResult> { let lock_path = if cfg!(feature = "new-db-arch") { - ctx.global_dir().join(format!("{}.lock", swap_uuid)) + ctx.global_dir().join("swap_locks").join(format!("{}.lock", swap_uuid)) } else { ctx.global_dir() .join("SWAPS") From 321087d0169d1b67c957662cd65b63ef92bdf317 Mon Sep 17 00:00:00 2001 From: Omer Yacine Date: Fri, 4 Apr 2025 16:37:12 +0200 Subject: [PATCH 26/50] transitively enable new-db-arch for dependency mm2 crates this fixes compilation errors when testing with --all-features set --- mm2src/coins/Cargo.toml | 2 +- mm2src/mm2_main/Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mm2src/coins/Cargo.toml b/mm2src/coins/Cargo.toml index 13aa9c2b72..1a88407810 100644 --- a/mm2src/coins/Cargo.toml +++ b/mm2src/coins/Cargo.toml @@ -13,7 +13,7 @@ enable-sia = [ default = [] run-docker-tests = [] for-tests = ["dep:mocktopus"] -new-db-arch = [] +new-db-arch = ["mm2_core/new-db-arch"] [lib] path = "lp_coins.rs" diff --git a/mm2src/mm2_main/Cargo.toml b/mm2src/mm2_main/Cargo.toml index 28291cb210..65c34cf8c6 100644 --- a/mm2src/mm2_main/Cargo.toml +++ b/mm2src/mm2_main/Cargo.toml @@ -25,7 +25,7 @@ enable-sia = ["coins/enable-sia", "coins_activation/enable-sia"] sepolia-maker-swap-v2-tests = [] sepolia-taker-swap-v2-tests = [] test-ext-api = ["trading_api/test-ext-api"] -new-db-arch = [] # A temporary feature to integrate the new db architecture incrementally +new-db-arch = ["mm2_core/new-db-arch"] # A temporary feature to integrate the new db architecture incrementally [dependencies] async-std = { version = "1.5", features = ["unstable"] } From 7b3f2b2ea63738e01f61570416f53308689bb235 Mon Sep 17 00:00:00 2001 From: Omer Yacine Date: Sat, 12 Apr 2025 14:22:00 +0200 Subject: [PATCH 27/50] make an async counter part for create_parents this one is to be used with async functions to not block them on fs operations --- mm2src/mm2_io/src/fs.rs | 52 +++++++++++++++++++++++++++++++++-------- 1 file changed, 42 insertions(+), 10 deletions(-) diff --git a/mm2src/mm2_io/src/fs.rs b/mm2src/mm2_io/src/fs.rs index 394f91bb2f..4867f65aad 100644 --- a/mm2src/mm2_io/src/fs.rs +++ b/mm2src/mm2_io/src/fs.rs @@ -281,15 +281,46 @@ pub fn create_parents(path: &dyn AsRef) -> IoResult<()> { format!("{} has no parent directory", path.as_ref().display()), )) }; - if parent_dir.exists() { - if !parent_dir.is_dir() { - return MmError::err(io::Error::new( + match fs::metadata(parent_dir) { + // Path exists, make sure it's a directory (and not a file for example). + Ok(metadata) => { + if !metadata.is_dir() { + return MmError::err(io::Error::new( + io::ErrorKind::InvalidInput, + format!("{} is not a directory", parent_dir.display()), + )); + } + }, + // This path doesn't exist, create it. + Err(_) => fs::create_dir_all(parent_dir)?, + } + Ok(()) +} + +/// Similar to [`create_parents`], but using non-blocking async IO operations. +/// +/// Creates all the directories along the path to a file if they do not exist. +pub async fn create_parents_async(path: &Path) -> IoResult<()> { + let parent_dir = path.parent(); + let Some(parent_dir) = parent_dir else { + return MmError::err( + io::Error::new( io::ErrorKind::InvalidInput, - format!("{} is not a directory", parent_dir.display()), - )); - } - } else { - fs::create_dir_all(parent_dir)?; + format!("{} has no parent directory", path.display()), + )) + }; + match async_fs::metadata(parent_dir).await { + // Path exists, make sure it's a directory (and not a file, for instance). + Ok(metadata) => { + if !metadata.is_dir() { + return MmError::err(io::Error::new( + io::ErrorKind::InvalidInput, + format!("{} is not a directory", parent_dir.display()), + )); + } + }, + // This path doesn't exist, try to create it. + Err(_) => async_fs::create_dir_all(parent_dir).await?, } Ok(()) } @@ -319,8 +350,9 @@ pub async fn write_json(t: &T, path: &Path, use_tmp_file: bool) -> FsJsonResu where T: Serialize, { - // FIXME: Create an async counterpart for create_parents? Should we? - create_parents(&path).map_err(|err| FsJsonError::IoWriting(err.into_inner()))?; + create_parents_async(path) + .await + .map_err(|err| FsJsonError::IoWriting(err.into_inner()))?; let content = json::to_vec(t).map_to_mm(FsJsonError::Serializing)?; let path_tmp = if use_tmp_file { From 8a00f1c7443ba59e0d7b018adea5486d469986aa Mon Sep 17 00:00:00 2001 From: Omer Yacine Date: Wed, 23 Apr 2025 14:47:58 +0200 Subject: [PATCH 28/50] fix sia address_from_pubkey impl --- mm2src/coins/siacoin.rs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/mm2src/coins/siacoin.rs b/mm2src/coins/siacoin.rs index 5f828ad22f..fa0c5da5e5 100644 --- a/mm2src/coins/siacoin.rs +++ b/mm2src/coins/siacoin.rs @@ -313,11 +313,12 @@ impl MarketCoinOps for SiaCoin { Ok(address.to_string()) } - fn address_from_pubkey(&self, _pubkey: &H264) -> MmResult { - // FIXME: How to convert our H264 to H256 (ed25519_dalek pubkeys)? - // let address = SpendPolicy::PublicKey(*pubkey).address(); - // Ok(address.to_string()) - Ok("dummy_address".to_string()) + fn address_from_pubkey(&self, pubkey: &H264) -> MmResult { + let pubkey = PublicKey::from_bytes(&pubkey.0[..32]).map_err(|e| { + AddressFromPubkeyError::InternalError(format!("Couldn't parse bytes into ed25519 pubkey: {e:?}")) + })?; + let address = SpendPolicy::PublicKey(pubkey).address(); + Ok(address.to_string()) } async fn get_public_key(&self) -> Result> { unimplemented!() } From 17a2bd0498af610cae62680ae73ccaa7f48842d5 Mon Sep 17 00:00:00 2001 From: Omer Yacine Date: Wed, 23 Apr 2025 15:27:20 +0200 Subject: [PATCH 29/50] lightning: impl address_from_pubkey by just formatting back the pubkey the same way it is formatted for node IDs --- mm2src/coins/lightning.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/mm2src/coins/lightning.rs b/mm2src/coins/lightning.rs index 343cc81a72..7a08ece8af 100644 --- a/mm2src/coins/lightning.rs +++ b/mm2src/coins/lightning.rs @@ -943,8 +943,9 @@ impl MarketCoinOps for LightningCoin { fn my_address(&self) -> MmResult { Ok(self.my_node_id()) } fn address_from_pubkey(&self, pubkey: &H264) -> MmResult { - // FIXME: What's a pubkey in this case? Is it for L1 or L2 (hint: the pubkey input here is maker_coin_htlc_pubkey of the swap). - self.platform_coin().address_from_pubkey(pubkey) + PublicKey::from_slice(&pubkey.0) + .map(|pubkey| pubkey.to_string()) + .map_to_mm(|e| AddressFromPubkeyError::InternalError(format!("Couldn't parse bytes into secp pubkey: {e}"))) } async fn get_public_key(&self) -> Result> { Ok(self.my_node_id()) } From 4a2d03ad5b9893cae3ddebfbb1d8fadfe9719ea1 Mon Sep 17 00:00:00 2001 From: Omer Yacine Date: Wed, 23 Apr 2025 18:41:49 +0200 Subject: [PATCH 30/50] use the global directory for blocks/cache db for zcoin such cache can safely be shared cross seeds/accounts/addresses --- mm2src/coins/z_coin.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/mm2src/coins/z_coin.rs b/mm2src/coins/z_coin.rs index 75216745be..e474fa381b 100644 --- a/mm2src/coins/z_coin.rs +++ b/mm2src/coins/z_coin.rs @@ -1036,10 +1036,7 @@ impl<'a> ZCoinBuilder<'a> { #[cfg(not(target_arch = "wasm32"))] let blocks_db = { - let cache_db_path = self - .ctx - .address_dir(&self.my_z_addr_encoded) - .join(format!("{}_cache.db", self.ticker)); + let cache_db_path = self.ctx.global_dir().join(format!("{}_cache.db", self.ticker)); BlockDbImpl::new(ctx, ticker, cache_db_path).await }; #[cfg(target_arch = "wasm32")] From 2896cb6423bc58f816f1f8ea73133852617f1043 Mon Sep 17 00:00:00 2001 From: Omer Yacine Date: Thu, 24 Apr 2025 08:42:17 +0200 Subject: [PATCH 31/50] treat zcoin's wallet_db as an HD wallet --- .../z_coin/storage/walletdb/wallet_sql_storage.rs | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/mm2src/coins/z_coin/storage/walletdb/wallet_sql_storage.rs b/mm2src/coins/z_coin/storage/walletdb/wallet_sql_storage.rs index 349b0e3984..7d594fab5c 100644 --- a/mm2src/coins/z_coin/storage/walletdb/wallet_sql_storage.rs +++ b/mm2src/coins/z_coin/storage/walletdb/wallet_sql_storage.rs @@ -24,7 +24,9 @@ pub async fn create_wallet_db( evk: ExtendedFullViewingKey, continue_from_prev_sync: bool, ) -> Result, MmError> { - mm2_io::fs::create_parents(&wallet_db_path).map_err(|err| ZcoinClientInitError::ZcoinStorageError(err.to_string()))?; + mm2_io::fs::create_parents_async(&wallet_db_path) + .await + .map_err(|err| ZcoinClientInitError::ZcoinStorageError(err.to_string()))?; let db = async_blocking(move || { WalletDbAsync::for_path(wallet_db_path, consensus_params) .map_to_mm(|err| ZcoinClientInitError::ZcoinStorageError(err.to_string())) @@ -87,13 +89,10 @@ impl<'a> WalletDbShared { let ticker = builder.ticker; let consensus_params = builder.protocol_info.consensus_params.clone(); let wallet_db = create_wallet_db( - builder - .ctx - // FIXME: Discussion point: we are storing wallet information in an address directory. - // What if the user enables a different address within the same wallet? this data will not be visible to the newly enabled address - // Does zcoin even allow HD wallets? If not, what if we allow it later? where such a DB should be stored? - .address_dir(&builder.my_z_addr_encoded) - .join(format!("{ticker}_wallet.db")), + #[cfg(feature = "new-db-arch")] + builder.ctx.wallet_dir().join(format!("{ticker}_wallet.db")), + #[cfg(not(feature = "new-db-arch"))] + builder.ctx.dbdir().join(format!("{ticker}_wallet.db")), consensus_params, checkpoint_block, ExtendedFullViewingKey::from(&builder.z_spending_key), From 71923e6d68b62b5559406946766cf6ca50016f30 Mon Sep 17 00:00:00 2001 From: Omer Yacine Date: Thu, 24 Apr 2025 14:03:17 +0200 Subject: [PATCH 32/50] remove lightning & HW wallet fixmes --- mm2src/coins/utxo/utxo_builder/utxo_coin_builder.rs | 1 - mm2src/coins_activation/src/lightning_activation.rs | 1 - 2 files changed, 2 deletions(-) diff --git a/mm2src/coins/utxo/utxo_builder/utxo_coin_builder.rs b/mm2src/coins/utxo/utxo_builder/utxo_coin_builder.rs index 6ed668e37b..94f5f61ca3 100644 --- a/mm2src/coins/utxo/utxo_builder/utxo_coin_builder.rs +++ b/mm2src/coins/utxo/utxo_builder/utxo_coin_builder.rs @@ -333,7 +333,6 @@ pub trait UtxoFieldsWithHardwareWalletBuilder: UtxoCoinBuilderCommonOps { let initial_history_state = self.initial_history_state(); let tx_hash_algo = self.tx_hash_algo(); let check_utxo_maturity = self.check_utxo_maturity(); - // FIXME: IS THIS CORRECT? DID WE GET THE CORRECT ADDRESS? let my_address = hd_wallet .get_enabled_address() .await diff --git a/mm2src/coins_activation/src/lightning_activation.rs b/mm2src/coins_activation/src/lightning_activation.rs index d548518e72..933f94ef0d 100644 --- a/mm2src/coins_activation/src/lightning_activation.rs +++ b/mm2src/coins_activation/src/lightning_activation.rs @@ -350,7 +350,6 @@ async fn start_lightning( // Initialize the Logger let logger = ctx.log.0.clone(); - // FIXME: Should we use the platform coin's address or the lightning node's address (my_node_id)? let platform_coin_address = platform_coin .my_address() .map_err(|e| EnableLightningError::Internal(format!("Error while getting platform coin address: {:?}", e)))?; From 52b0c599cda72ee81870617412871e1d2e4dcc01 Mon Sep 17 00:00:00 2001 From: Omer Yacine Date: Sat, 26 Apr 2025 12:26:01 +0300 Subject: [PATCH 33/50] impl address_from_pubkey for zcoin by disregarding the pubkey and returning own address but we prolly need to change the method name at this point, address_from_pubkey doesn't fit in this situation --- mm2src/coins/z_coin.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mm2src/coins/z_coin.rs b/mm2src/coins/z_coin.rs index e474fa381b..c6a47b3fb6 100644 --- a/mm2src/coins/z_coin.rs +++ b/mm2src/coins/z_coin.rs @@ -1127,8 +1127,8 @@ impl MarketCoinOps for ZCoin { fn my_address(&self) -> MmResult { Ok(self.z_fields.my_z_addr_encoded.clone()) } fn address_from_pubkey(&self, _pubkey: &H264) -> MmResult { - // FIXME: How to derive the address from pubkey for zcoin? - Ok("dummy_address".to_string()) + // NOTE: We can't derive a z-address from pubkey, so we will just return our own z_address. + Ok(self.z_fields.my_z_addr_encoded.clone()) } async fn get_public_key(&self) -> Result> { From 62d4a535d603deef3354072b0a8fda80f643086a Mon Sep 17 00:00:00 2001 From: Omer Yacine Date: Wed, 30 Apr 2025 20:33:30 +0300 Subject: [PATCH 34/50] move the recreate maker_swap fixme to a todo --- mm2src/mm2_main/src/lp_swap/recreate_swap_data.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/mm2src/mm2_main/src/lp_swap/recreate_swap_data.rs b/mm2src/mm2_main/src/lp_swap/recreate_swap_data.rs index 4b879e4b37..3d9edf5c69 100644 --- a/mm2src/mm2_main/src/lp_swap/recreate_swap_data.rs +++ b/mm2src/mm2_main/src/lp_swap/recreate_swap_data.rs @@ -181,9 +181,8 @@ async fn recreate_maker_swap(ctx: MmArc, taker_swap: TakerSavedSwap) -> Recreate #[cfg(all(not(target_arch = "wasm32"), feature = "new-db-arch"))] { - // FIXME: Discuss: Here we do our best effort to retrieve the maker coin address from the known swap data. - // The maker coin might not be available at this point where we recreating the swap though. - // What about returning the pubkey and letting the swap importer convert it to an address themselves? + // TODO(new-db-arch): Execute this plan: https://github.com/KomodoPlatform/komodo-defi-framework/pull/2398#discussion_r2036035916 + // instead of making the maker_address/address_dir available for the importer (i.e. let them find it themselves). let maker_coin_ticker = started_event.maker_coin; let maker_coin = lp_coinfind(&ctx, &maker_coin_ticker) .await From 6f6c3ec8eee612f165ae5482a883fb6ee515cd80 Mon Sep 17 00:00:00 2001 From: Omer Yacine Date: Fri, 9 May 2025 13:14:34 +0200 Subject: [PATCH 35/50] add -Json to H264 from rpc::v1::types --- mm2src/coins/eth.rs | 2 +- mm2src/coins/lp_coins.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/mm2src/coins/eth.rs b/mm2src/coins/eth.rs index 50d17e7e5c..bb9bb8efe6 100644 --- a/mm2src/coins/eth.rs +++ b/mm2src/coins/eth.rs @@ -2284,7 +2284,7 @@ impl MarketCoinOps for EthCoin { } } - fn address_from_pubkey(&self, pubkey: &H264) -> MmResult { + fn address_from_pubkey(&self, pubkey: &H264Json) -> MmResult { let addr = addr_from_raw_pubkey(&pubkey.0).map_err(AddressFromPubkeyError::InternalError)?; Ok(addr.display_address()) } diff --git a/mm2src/coins/lp_coins.rs b/mm2src/coins/lp_coins.rs index b36991cff7..23785d3571 100644 --- a/mm2src/coins/lp_coins.rs +++ b/mm2src/coins/lp_coins.rs @@ -72,7 +72,7 @@ use mm2_rpc::data::legacy::{EnabledCoin, GetEnabledResponse, Mm2RpcResult}; #[cfg(any(test, feature = "for-tests"))] use mocktopus::macros::*; use parking_lot::Mutex as PaMutex; -use rpc::v1::types::{Bytes as BytesJson, H256 as H256Json, H264}; +use rpc::v1::types::{Bytes as BytesJson, H256 as H256Json, H264 as H264Json}; use serde::{Deserialize, Deserializer, Serialize, Serializer}; use serde_json::{self as json, Value as Json}; use std::array::TryFromSliceError; @@ -2081,7 +2081,7 @@ pub trait MarketCoinOps { fn my_address(&self) -> MmResult; - fn address_from_pubkey(&self, pubkey: &H264) -> MmResult; + fn address_from_pubkey(&self, pubkey: &H264Json) -> MmResult; async fn get_public_key(&self) -> Result>; From 4e91a169f1b8076e9ab3c6c12dc67eb70878e12e Mon Sep 17 00:00:00 2001 From: Omer Yacine Date: Fri, 9 May 2025 14:22:55 +0200 Subject: [PATCH 36/50] fix post-merge clippy warnings --- .../mm2_main/tests/docker_tests/z_coin_docker_tests.rs | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/mm2src/mm2_main/tests/docker_tests/z_coin_docker_tests.rs b/mm2src/mm2_main/tests/docker_tests/z_coin_docker_tests.rs index c60813c134..f9cd8e99af 100644 --- a/mm2src/mm2_main/tests/docker_tests/z_coin_docker_tests.rs +++ b/mm2src/mm2_main/tests/docker_tests/z_coin_docker_tests.rs @@ -7,9 +7,7 @@ use common::now_sec; use lazy_static::lazy_static; use mm2_core::mm_ctx::{MmArc, MmCtxBuilder}; use mm2_number::MmNumber; -use mm2_test_helpers::for_tests::{new_mm2_temp_folder_path, zombie_conf_for_docker}; -use rand::distributions::Alphanumeric; -use rand::{thread_rng, Rng}; +use mm2_test_helpers::for_tests::zombie_conf_for_docker; use tokio::sync::Mutex; // https://github.com/KomodoPlatform/librustzcash/blob/4e030a0f44cc17f100bf5f019563be25c5b8755f/zcash_client_backend/src/data_api/wallet.rs#L72-L73 @@ -26,11 +24,6 @@ pub async fn z_coin_from_spending_key(spending_key: &str) -> (MmArc, ZCoin) { ..Default::default() }; let pk_data = [1; 32]; - let salt: String = thread_rng() - .sample_iter(&Alphanumeric) - .take(4) - .map(char::from) - .collect(); let protocol_info = match serde_json::from_value::(conf["protocol"].take()).unwrap() { CoinProtocol::ZHTLC(protocol_info) => protocol_info, other_protocol => panic!("Failed to get protocol from config: {:?}", other_protocol), From f13c611e3e2acd49832f058e3931bb9d509d03c5 Mon Sep 17 00:00:00 2001 From: Omer Yacine Date: Fri, 9 May 2025 14:21:50 +0200 Subject: [PATCH 37/50] add -Json to more H264s --- mm2src/coins/lightning.rs | 4 ++-- mm2src/coins/qrc20.rs | 4 ++-- mm2src/coins/siacoin.rs | 4 ++-- mm2src/coins/tendermint/tendermint_coin.rs | 4 ++-- mm2src/coins/tendermint/tendermint_token.rs | 4 ++-- mm2src/coins/test_coin.rs | 4 ++-- mm2src/coins/utxo/bch.rs | 4 ++-- mm2src/coins/utxo/qtum.rs | 4 ++-- mm2src/coins/utxo/slp.rs | 4 ++-- mm2src/coins/utxo/utxo_standard.rs | 4 ++-- mm2src/coins/z_coin.rs | 4 ++-- 11 files changed, 22 insertions(+), 22 deletions(-) diff --git a/mm2src/coins/lightning.rs b/mm2src/coins/lightning.rs index 7a08ece8af..64aa153aaa 100644 --- a/mm2src/coins/lightning.rs +++ b/mm2src/coins/lightning.rs @@ -65,7 +65,7 @@ use mm2_err_handle::prelude::*; use mm2_net::ip_addr::myipaddr; use mm2_number::{BigDecimal, MmNumber}; use parking_lot::Mutex as PaMutex; -use rpc::v1::types::{Bytes as BytesJson, H256 as H256Json, H264}; +use rpc::v1::types::{Bytes as BytesJson, H256 as H256Json, H264 as H264Json}; use script::TransactionInputSigner; use secp256k1v24::PublicKey; use serde::Deserialize; @@ -942,7 +942,7 @@ impl MarketCoinOps for LightningCoin { fn my_address(&self) -> MmResult { Ok(self.my_node_id()) } - fn address_from_pubkey(&self, pubkey: &H264) -> MmResult { + fn address_from_pubkey(&self, pubkey: &H264Json) -> MmResult { PublicKey::from_slice(&pubkey.0) .map(|pubkey| pubkey.to_string()) .map_to_mm(|e| AddressFromPubkeyError::InternalError(format!("Couldn't parse bytes into secp pubkey: {e}"))) diff --git a/mm2src/coins/qrc20.rs b/mm2src/coins/qrc20.rs index 8be01743b8..2e1da16e06 100644 --- a/mm2src/coins/qrc20.rs +++ b/mm2src/coins/qrc20.rs @@ -45,7 +45,7 @@ use mm2_err_handle::prelude::*; use mm2_number::{BigDecimal, MmNumber}; #[cfg(test)] use mocktopus::macros::*; use rpc::v1::types::{Bytes as BytesJson, ToTxHash, Transaction as RpcTransaction, H160 as H160Json, H256 as H256Json, - H264}; + H264 as H264Json}; use script::{Builder as ScriptBuilder, Opcode, Script, TransactionInputSigner}; use script_pubkey::generate_contract_call_script_pubkey; use serde_json::{self as json, Value as Json}; @@ -1029,7 +1029,7 @@ impl MarketCoinOps for Qrc20Coin { fn my_address(&self) -> MmResult { utxo_common::my_address(self) } - fn address_from_pubkey(&self, pubkey: &H264) -> MmResult { + fn address_from_pubkey(&self, pubkey: &H264Json) -> MmResult { let pubkey = Public::Compressed((*pubkey).into()); Ok(UtxoCommonOps::address_from_pubkey(self, &pubkey).to_string()) } diff --git a/mm2src/coins/siacoin.rs b/mm2src/coins/siacoin.rs index fa0c5da5e5..08458e5c0d 100644 --- a/mm2src/coins/siacoin.rs +++ b/mm2src/coins/siacoin.rs @@ -17,7 +17,7 @@ use keys::KeyPair; use mm2_core::mm_ctx::MmArc; use mm2_err_handle::prelude::*; use mm2_number::{BigDecimal, BigInt, MmNumber}; -use rpc::v1::types::{Bytes as BytesJson, H264}; +use rpc::v1::types::{Bytes as BytesJson, H264 as H264Json}; use serde_json::Value as Json; use std::ops::Deref; use std::sync::Arc; @@ -313,7 +313,7 @@ impl MarketCoinOps for SiaCoin { Ok(address.to_string()) } - fn address_from_pubkey(&self, pubkey: &H264) -> MmResult { + fn address_from_pubkey(&self, pubkey: &H264Json) -> MmResult { let pubkey = PublicKey::from_bytes(&pubkey.0[..32]).map_err(|e| { AddressFromPubkeyError::InternalError(format!("Couldn't parse bytes into ed25519 pubkey: {e:?}")) })?; diff --git a/mm2src/coins/tendermint/tendermint_coin.rs b/mm2src/coins/tendermint/tendermint_coin.rs index 585d4dc054..a45e643c8d 100644 --- a/mm2src/coins/tendermint/tendermint_coin.rs +++ b/mm2src/coins/tendermint/tendermint_coin.rs @@ -78,7 +78,7 @@ use num_traits::Zero; use parking_lot::Mutex as PaMutex; use primitives::hash::H256; use regex::Regex; -use rpc::v1::types::{Bytes as BytesJson, H264}; +use rpc::v1::types::{Bytes as BytesJson, H264 as H264Json}; use serde_json::{self as json, Value as Json}; use std::collections::HashMap; use std::convert::{TryFrom, TryInto}; @@ -3320,7 +3320,7 @@ impl MarketCoinOps for TendermintCoin { fn my_address(&self) -> MmResult { Ok(self.account_id.to_string()) } - fn address_from_pubkey(&self, pubkey: &H264) -> MmResult { + fn address_from_pubkey(&self, pubkey: &H264Json) -> MmResult { let pubkey_hash = dhash160(&pubkey.0); let address = AccountId::new(&self.account_prefix, pubkey_hash.as_slice()) .map_err(|e| AddressFromPubkeyError::InternalError(e.to_string()))?; diff --git a/mm2src/coins/tendermint/tendermint_token.rs b/mm2src/coins/tendermint/tendermint_token.rs index edadf302cf..d70b316d26 100644 --- a/mm2src/coins/tendermint/tendermint_token.rs +++ b/mm2src/coins/tendermint/tendermint_token.rs @@ -29,7 +29,7 @@ use mm2_core::mm_ctx::MmArc; use mm2_err_handle::prelude::*; use mm2_number::MmNumber; use primitives::hash::H256; -use rpc::v1::types::{Bytes as BytesJson, H264}; +use rpc::v1::types::{Bytes as BytesJson, H264 as H264Json}; use serde_json::Value as Json; use std::ops::Deref; use std::str::FromStr; @@ -269,7 +269,7 @@ impl MarketCoinOps for TendermintToken { fn my_address(&self) -> MmResult { self.platform_coin.my_address() } - fn address_from_pubkey(&self, pubkey: &H264) -> MmResult { + fn address_from_pubkey(&self, pubkey: &H264Json) -> MmResult { self.platform_coin.address_from_pubkey(pubkey) } diff --git a/mm2src/coins/test_coin.rs b/mm2src/coins/test_coin.rs index 9eb898741d..0faae14886 100644 --- a/mm2src/coins/test_coin.rs +++ b/mm2src/coins/test_coin.rs @@ -28,7 +28,7 @@ use mm2_err_handle::prelude::*; use mm2_number::{BigDecimal, MmNumber}; #[cfg(any(test, feature = "for-tests"))] use mocktopus::macros::*; -use rpc::v1::types::{Bytes as BytesJson, H264}; +use rpc::v1::types::{Bytes as BytesJson, H264 as H264Json}; use serde_json::Value as Json; use std::fmt::{Display, Formatter}; use std::ops::Deref; @@ -65,7 +65,7 @@ impl MarketCoinOps for TestCoin { fn my_address(&self) -> MmResult { unimplemented!() } - fn address_from_pubkey(&self, _pubkey: &H264) -> MmResult { unimplemented!() } + fn address_from_pubkey(&self, _pubkey: &H264Json) -> MmResult { unimplemented!() } async fn get_public_key(&self) -> Result> { unimplemented!() } diff --git a/mm2src/coins/utxo/bch.rs b/mm2src/coins/utxo/bch.rs index fb409f8fc7..7e18dfc913 100644 --- a/mm2src/coins/utxo/bch.rs +++ b/mm2src/coins/utxo/bch.rs @@ -34,7 +34,7 @@ use keys::CashAddress; pub use keys::NetworkPrefix as CashAddrPrefix; use mm2_metrics::MetricsArc; use mm2_number::MmNumber; -use rpc::v1::types::H264; +use rpc::v1::types::H264 as H264Json; use serde_json::{self as json, Value as Json}; use serialization::{deserialize, CoinVariant}; use std::sync::MutexGuard; @@ -1135,7 +1135,7 @@ impl MarketCoinOps for BchCoin { fn my_address(&self) -> MmResult { utxo_common::my_address(self) } - fn address_from_pubkey(&self, pubkey: &H264) -> MmResult { + fn address_from_pubkey(&self, pubkey: &H264Json) -> MmResult { let pubkey = Public::Compressed((*pubkey).into()); Ok(UtxoCommonOps::address_from_pubkey(self, &pubkey).to_string()) } diff --git a/mm2src/coins/utxo/qtum.rs b/mm2src/coins/utxo/qtum.rs index 8a1c8e6b93..cab1d3c5d5 100644 --- a/mm2src/coins/utxo/qtum.rs +++ b/mm2src/coins/utxo/qtum.rs @@ -40,7 +40,7 @@ use futures::{FutureExt, TryFutureExt}; use keys::AddressHashEnum; use mm2_metrics::MetricsArc; use mm2_number::MmNumber; -use rpc::v1::types::H264; +use rpc::v1::types::H264 as H264Json; use serde::Serialize; use serialization::CoinVariant; use utxo_signer::UtxoSignerOps; @@ -758,7 +758,7 @@ impl MarketCoinOps for QtumCoin { fn my_address(&self) -> MmResult { utxo_common::my_address(self) } - fn address_from_pubkey(&self, pubkey: &H264) -> MmResult { + fn address_from_pubkey(&self, pubkey: &H264Json) -> MmResult { let pubkey = Public::Compressed((*pubkey).into()); Ok(UtxoCommonOps::address_from_pubkey(self, &pubkey).to_string()) } diff --git a/mm2src/coins/utxo/slp.rs b/mm2src/coins/utxo/slp.rs index 77504c06c0..6e519c2026 100644 --- a/mm2src/coins/utxo/slp.rs +++ b/mm2src/coins/utxo/slp.rs @@ -44,7 +44,7 @@ use mm2_core::mm_ctx::MmArc; use mm2_err_handle::prelude::*; use mm2_number::{BigDecimal, MmNumber}; use primitives::hash::H256; -use rpc::v1::types::{Bytes as BytesJson, ToTxHash, H256 as H256Json, H264}; +use rpc::v1::types::{Bytes as BytesJson, ToTxHash, H256 as H256Json, H264 as H264Json}; use script::bytes::Bytes; use script::{Builder as ScriptBuilder, Opcode, Script, TransactionInputSigner}; use serde_json::Value as Json; @@ -1102,7 +1102,7 @@ impl MarketCoinOps for SlpToken { slp_address.encode().map_to_mm(MyAddressError::InternalError) } - fn address_from_pubkey(&self, pubkey: &H264) -> MmResult { + fn address_from_pubkey(&self, pubkey: &H264Json) -> MmResult { MarketCoinOps::address_from_pubkey(&self.platform_coin, pubkey) } diff --git a/mm2src/coins/utxo/utxo_standard.rs b/mm2src/coins/utxo/utxo_standard.rs index a1c07b5468..ec9fd8adb9 100644 --- a/mm2src/coins/utxo/utxo_standard.rs +++ b/mm2src/coins/utxo/utxo_standard.rs @@ -43,7 +43,7 @@ use futures::{FutureExt, TryFutureExt}; use mm2_metrics::MetricsArc; use mm2_number::MmNumber; #[cfg(test)] use mocktopus::macros::*; -use rpc::v1::types::H264; +use rpc::v1::types::H264 as H264Json; use script::Opcode; use utxo_signer::UtxoSignerOps; @@ -849,7 +849,7 @@ impl MarketCoinOps for UtxoStandardCoin { fn my_address(&self) -> MmResult { utxo_common::my_address(self) } - fn address_from_pubkey(&self, pubkey: &H264) -> MmResult { + fn address_from_pubkey(&self, pubkey: &H264Json) -> MmResult { let pubkey = Public::Compressed((*pubkey).into()); Ok(UtxoCommonOps::address_from_pubkey(self, &pubkey).to_string()) } diff --git a/mm2src/coins/z_coin.rs b/mm2src/coins/z_coin.rs index 6c83bbfdc4..2438ef2f35 100644 --- a/mm2src/coins/z_coin.rs +++ b/mm2src/coins/z_coin.rs @@ -57,7 +57,7 @@ use mm2_core::mm_ctx::MmArc; use mm2_err_handle::prelude::*; use mm2_number::{BigDecimal, MmNumber}; #[cfg(test)] use mocktopus::macros::*; -use rpc::v1::types::{Bytes as BytesJson, Transaction as RpcTransaction, H256 as H256Json, H264}; +use rpc::v1::types::{Bytes as BytesJson, Transaction as RpcTransaction, H256 as H256Json, H264 as H264Json}; use script::{Builder as ScriptBuilder, Opcode, Script, TransactionInputSigner}; use serde_json::Value as Json; use serialization::CoinVariant; @@ -1127,7 +1127,7 @@ impl MarketCoinOps for ZCoin { fn my_address(&self) -> MmResult { Ok(self.z_fields.my_z_addr_encoded.clone()) } - fn address_from_pubkey(&self, _pubkey: &H264) -> MmResult { + fn address_from_pubkey(&self, _pubkey: &H264Json) -> MmResult { // NOTE: We can't derive a z-address from pubkey, so we will just return our own z_address. Ok(self.z_fields.my_z_addr_encoded.clone()) } From 994d0dc32d2aa62a062a771917904d8ab758b568 Mon Sep 17 00:00:00 2001 From: Omer Yacine Date: Fri, 9 May 2025 14:32:35 +0200 Subject: [PATCH 38/50] DRY: use account_id_from_raw_pubkey --- mm2src/coins/tendermint/tendermint_coin.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/mm2src/coins/tendermint/tendermint_coin.rs b/mm2src/coins/tendermint/tendermint_coin.rs index a45e643c8d..b43c54bdf2 100644 --- a/mm2src/coins/tendermint/tendermint_coin.rs +++ b/mm2src/coins/tendermint/tendermint_coin.rs @@ -3321,8 +3321,7 @@ impl MarketCoinOps for TendermintCoin { fn my_address(&self) -> MmResult { Ok(self.account_id.to_string()) } fn address_from_pubkey(&self, pubkey: &H264Json) -> MmResult { - let pubkey_hash = dhash160(&pubkey.0); - let address = AccountId::new(&self.account_prefix, pubkey_hash.as_slice()) + let address = account_id_from_raw_pubkey(&self.account_prefix, &pubkey.0) .map_err(|e| AddressFromPubkeyError::InternalError(e.to_string()))?; Ok(address.to_string()) } From cbeba990798beab819c3369c398f8e69e9708edc Mon Sep 17 00:00:00 2001 From: Omer Yacine Date: Sun, 11 May 2025 21:41:21 +0200 Subject: [PATCH 39/50] let address_from_pubkey use non-checksumed address in eth for now --- mm2src/coins/eth.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/mm2src/coins/eth.rs b/mm2src/coins/eth.rs index 88679404b5..76497b1941 100644 --- a/mm2src/coins/eth.rs +++ b/mm2src/coins/eth.rs @@ -2286,7 +2286,10 @@ impl MarketCoinOps for EthCoin { fn address_from_pubkey(&self, pubkey: &H264Json) -> MmResult { let addr = addr_from_raw_pubkey(&pubkey.0).map_err(AddressFromPubkeyError::InternalError)?; - Ok(addr.display_address()) + // TODO: Here we use `addr_to_string` instead of `display_address` to not include the checksum (case change). + // As the output of this method could be used to derive an address_dir, we wanna be consistent with whether + // we include or not include the checksum. A possible solution is to lowercase everything in `Ctx::address_dir`. + Ok(addr.addr_to_string()) } async fn get_public_key(&self) -> Result> { From 0a5ae486506cf7a965fcf926542bc2fe25dccebd Mon Sep 17 00:00:00 2001 From: Omer Yacine Date: Mon, 12 May 2025 10:06:01 +0200 Subject: [PATCH 40/50] use node_id for the address_dir in lightning instead of a platform's address --- Cargo.lock | 1 + mm2src/coins_activation/Cargo.toml | 1 + .../src/lightning_activation.rs | 19 +++++++++++-------- 3 files changed, 13 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6c0987c7fe..9c44fd7130 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -976,6 +976,7 @@ dependencies = [ "parking_lot", "rpc", "rpc_task", + "secp256k1 0.24.3", "ser_error", "ser_error_derive", "serde", diff --git a/mm2src/coins_activation/Cargo.toml b/mm2src/coins_activation/Cargo.toml index be951c67d4..3ed8213e3b 100644 --- a/mm2src/coins_activation/Cargo.toml +++ b/mm2src/coins_activation/Cargo.toml @@ -28,6 +28,7 @@ mm2_number = { path = "../mm2_number" } parking_lot = { version = "0.12.0", features = ["nightly"] } rpc = { path = "../mm2_bitcoin/rpc" } rpc_task = { path = "../rpc_task" } +secp256k1 = { version = "0.24" } ser_error = { path = "../derives/ser_error" } ser_error_derive = { path = "../derives/ser_error_derive" } serde = "1.0" diff --git a/mm2src/coins_activation/src/lightning_activation.rs b/mm2src/coins_activation/src/lightning_activation.rs index 933f94ef0d..105fb2c422 100644 --- a/mm2src/coins_activation/src/lightning_activation.rs +++ b/mm2src/coins_activation/src/lightning_activation.rs @@ -20,7 +20,7 @@ use common::executor::{SpawnFuture, Timer}; use crypto::hw_rpc_task::{HwRpcTaskAwaitingStatus, HwRpcTaskUserAction}; use derive_more::Display; use futures::compat::Future01CompatExt; -use lightning::chain::keysinterface::KeysInterface; +use lightning::chain::keysinterface::{KeysInterface, Recipient}; use lightning::chain::Access; use lightning::routing::gossip; use lightning::routing::router::DefaultRouter; @@ -29,6 +29,7 @@ use lightning_invoice::payment; use mm2_core::mm_ctx::MmArc; use mm2_err_handle::prelude::*; use parking_lot::Mutex as PaMutex; +use secp256k1::Secp256k1; use ser_error_derive::SerializeErrorType; use serde_derive::{Deserialize, Serialize}; use serde_json::{self as json, Value as Json}; @@ -350,14 +351,16 @@ async fn start_lightning( // Initialize the Logger let logger = ctx.log.0.clone(); - let platform_coin_address = platform_coin - .my_address() - .map_err(|e| EnableLightningError::Internal(format!("Error while getting platform coin address: {:?}", e)))?; - // Initialize Persister - let persister = init_persister(ctx, &platform_coin_address, conf.ticker.clone(), params.backup_path).await?; - // Initialize the KeysManager let keys_manager = init_keys_manager(&platform)?; + let node_id = keys_manager + .get_node_secret(Recipient::Node) + .map_err(|e| EnableLightningError::Internal(format!("Error while getting node id: {:?}", e)))? + .public_key(&Secp256k1::new()); + let node_id = node_id.to_string(); + + // Initialize Persister + let persister = init_persister(ctx, &node_id, conf.ticker.clone(), params.backup_path).await?; // Initialize the P2PGossipSync. This is used for providing routes to send payments over task_handle.update_in_progress_status(LightningInProgressStatus::ReadingNetworkGraphFromFile)?; @@ -374,7 +377,7 @@ async fn start_lightning( )); // Initialize DB - let db = init_db(ctx, &platform_coin_address, conf.ticker.clone()).await?; + let db = init_db(ctx, &node_id, conf.ticker.clone()).await?; // Initialize the ChannelManager task_handle.update_in_progress_status(LightningInProgressStatus::InitializingChannelManager)?; From 2e74dffbfd6df4727312dac845c79d167a237e87 Mon Sep 17 00:00:00 2001 From: Omer Yacine Date: Wed, 14 May 2025 14:29:51 +0200 Subject: [PATCH 41/50] add a todo to getive different names to address_from_pubkey --- mm2src/coins/utxo/slp.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/mm2src/coins/utxo/slp.rs b/mm2src/coins/utxo/slp.rs index 6e519c2026..a0b29006cc 100644 --- a/mm2src/coins/utxo/slp.rs +++ b/mm2src/coins/utxo/slp.rs @@ -1103,6 +1103,7 @@ impl MarketCoinOps for SlpToken { } fn address_from_pubkey(&self, pubkey: &H264Json) -> MmResult { + // TODO: We have two `address_from_pubkey`s, one in MarketCoinOps and one in UtxoCommonOps. We should give them different names. MarketCoinOps::address_from_pubkey(&self.platform_coin, pubkey) } From 83e408991712605a0fe6a51567d1972c9b1dbaa3 Mon Sep 17 00:00:00 2001 From: Omer Yacine Date: Fri, 16 May 2025 16:24:01 +0200 Subject: [PATCH 42/50] use checksummed address for eth address dir --- mm2src/coins/eth.rs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/mm2src/coins/eth.rs b/mm2src/coins/eth.rs index b561b355bb..0bb6d7b1b2 100644 --- a/mm2src/coins/eth.rs +++ b/mm2src/coins/eth.rs @@ -940,7 +940,7 @@ macro_rules! tx_type_from_pay_for_gas_option { impl EthCoinImpl { #[cfg(not(target_arch = "wasm32"))] fn eth_traces_path(&self, ctx: &MmArc, my_address: Address) -> PathBuf { - ctx.address_dir(&my_address.addr_to_string()) + ctx.address_dir(&my_address.display_address()) .join("TRANSACTIONS") .join(format!("{}_{:#02x}_trace.json", self.ticker, my_address)) } @@ -984,7 +984,7 @@ impl EthCoinImpl { #[cfg(not(target_arch = "wasm32"))] fn erc20_events_path(&self, ctx: &MmArc, my_address: Address) -> PathBuf { - ctx.address_dir(&my_address.addr_to_string()) + ctx.address_dir(&my_address.display_address()) .join("TRANSACTIONS") .join(format!("{}_{:#02x}_events.json", self.ticker, my_address)) } @@ -2331,10 +2331,7 @@ impl MarketCoinOps for EthCoin { fn address_from_pubkey(&self, pubkey: &H264Json) -> MmResult { let addr = addr_from_raw_pubkey(&pubkey.0).map_err(AddressFromPubkeyError::InternalError)?; - // TODO: Here we use `addr_to_string` instead of `display_address` to not include the checksum (case change). - // As the output of this method could be used to derive an address_dir, we wanna be consistent with whether - // we include or not include the checksum. A possible solution is to lowercase everything in `Ctx::address_dir`. - Ok(addr.addr_to_string()) + Ok(addr.display_address()) } async fn get_public_key(&self) -> Result> { From 830100ca411f91611b8e309974ccac169933d811 Mon Sep 17 00:00:00 2001 From: Omer Yacine Date: Fri, 16 May 2025 16:37:59 +0200 Subject: [PATCH 43/50] create similar abstraction for wallet dir just like global and address dir --- mm2src/coins/z_coin/storage/walletdb/wallet_sql_storage.rs | 3 --- mm2src/mm2_core/src/mm_ctx.rs | 5 ++++- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/mm2src/coins/z_coin/storage/walletdb/wallet_sql_storage.rs b/mm2src/coins/z_coin/storage/walletdb/wallet_sql_storage.rs index 7d594fab5c..0408182ae0 100644 --- a/mm2src/coins/z_coin/storage/walletdb/wallet_sql_storage.rs +++ b/mm2src/coins/z_coin/storage/walletdb/wallet_sql_storage.rs @@ -89,10 +89,7 @@ impl<'a> WalletDbShared { let ticker = builder.ticker; let consensus_params = builder.protocol_info.consensus_params.clone(); let wallet_db = create_wallet_db( - #[cfg(feature = "new-db-arch")] builder.ctx.wallet_dir().join(format!("{ticker}_wallet.db")), - #[cfg(not(feature = "new-db-arch"))] - builder.ctx.dbdir().join(format!("{ticker}_wallet.db")), consensus_params, checkpoint_block, ExtendedFullViewingKey::from(&builder.z_spending_key), diff --git a/mm2src/mm2_core/src/mm_ctx.rs b/mm2src/mm2_core/src/mm_ctx.rs index e563892a6d..5d01b81245 100644 --- a/mm2src/mm2_core/src/mm_ctx.rs +++ b/mm2src/mm2_core/src/mm_ctx.rs @@ -363,8 +363,11 @@ impl MmCtx { /// For HD wallets, this `rmd160` is derived from `mm2_internal_derivation_path`. /// For Iguana, this `rmd160` is simply a hash of the seed. /// Use this directory to store seed/wallet related data rather than address related data (e.g. HD wallet accounts, HD wallet tx history, etc...) - #[cfg(all(feature = "new-db-arch", not(target_arch = "wasm32")))] + #[cfg(not(target_arch = "wasm32"))] pub fn wallet_dir(&self) -> PathBuf { + if cfg!(not(feature = "new-db-arch")) { + return self.dbdir(); + } self.db_root() .join("wallets") .join(hex::encode(self.rmd160().as_slice())) From 666513605883b598788bc42b72599436a5c07335 Mon Sep 17 00:00:00 2001 From: Omer Yacine Date: Fri, 16 May 2025 17:39:30 +0300 Subject: [PATCH 44/50] Update mm2src/coins/z_coin.rs Co-authored-by: Samuel Onoja --- mm2src/coins/z_coin.rs | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/mm2src/coins/z_coin.rs b/mm2src/coins/z_coin.rs index 2438ef2f35..3f5afb2d66 100644 --- a/mm2src/coins/z_coin.rs +++ b/mm2src/coins/z_coin.rs @@ -1030,15 +1030,14 @@ impl<'a> ZCoinBuilder<'a> { let ctx = &self.ctx; let ticker = self.ticker.to_string(); - #[cfg(not(target_arch = "wasm32"))] - let blocks_db = { - let cache_db_path = self.ctx.global_dir().join(format!("{}_cache.db", self.ticker)); - BlockDbImpl::new(ctx, ticker, cache_db_path).await - }; - #[cfg(target_arch = "wasm32")] - let blocks_db = BlockDbImpl::new(ctx, ticker, PathBuf::new()).await; +#[cfg(target_arch = "wasm32")] +let cache_db_path = PathBuf::new(); +#[cfg(not(target_arch = "wasm32"))] +let cache_db_path = self.ctx.global_dir().join(format!("{}_cache.db", self.ticker)); - blocks_db.map_err(|err| MmError::new(ZcoinClientInitError::ZcoinStorageError(err.to_string()))) +BlockDbImpl::new(ctx, ticker, cache_db_path) + .await + .map_err(|err| MmError::new(ZcoinClientInitError::ZcoinStorageError(err.to_string()))) } #[cfg(not(target_arch = "wasm32"))] From 4e11c571a22163c75c2a37cd8bcb98ee32ef27ba Mon Sep 17 00:00:00 2001 From: Omer Yacine Date: Fri, 16 May 2025 16:43:06 +0200 Subject: [PATCH 45/50] fix formatting --- mm2src/coins/z_coin.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/mm2src/coins/z_coin.rs b/mm2src/coins/z_coin.rs index 3f5afb2d66..17c8cec2fb 100644 --- a/mm2src/coins/z_coin.rs +++ b/mm2src/coins/z_coin.rs @@ -1030,14 +1030,14 @@ impl<'a> ZCoinBuilder<'a> { let ctx = &self.ctx; let ticker = self.ticker.to_string(); -#[cfg(target_arch = "wasm32")] -let cache_db_path = PathBuf::new(); -#[cfg(not(target_arch = "wasm32"))] -let cache_db_path = self.ctx.global_dir().join(format!("{}_cache.db", self.ticker)); + #[cfg(target_arch = "wasm32")] + let cache_db_path = PathBuf::new(); + #[cfg(not(target_arch = "wasm32"))] + let cache_db_path = self.ctx.global_dir().join(format!("{}_cache.db", self.ticker)); -BlockDbImpl::new(ctx, ticker, cache_db_path) - .await - .map_err(|err| MmError::new(ZcoinClientInitError::ZcoinStorageError(err.to_string()))) + BlockDbImpl::new(ctx, ticker, cache_db_path) + .await + .map_err(|err| MmError::new(ZcoinClientInitError::ZcoinStorageError(err.to_string()))) } #[cfg(not(target_arch = "wasm32"))] From 1741f340a61400774c627ed85442faa5eb7ce5f7 Mon Sep 17 00:00:00 2001 From: Omer Yacine Date: Fri, 16 May 2025 17:03:42 +0200 Subject: [PATCH 46/50] review(dimxy): refactor z_coin.rs to not lose trace location --- mm2src/coins/z_coin.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/mm2src/coins/z_coin.rs b/mm2src/coins/z_coin.rs index 17c8cec2fb..eb33ba08f6 100644 --- a/mm2src/coins/z_coin.rs +++ b/mm2src/coins/z_coin.rs @@ -396,7 +396,7 @@ impl ZCoin { let spendable_notes = self .spendable_notes_ordered() .await - .map_err(|err| GenTxError::SpendableNotesError(err.to_string()))?; + .map_err(|err| err.map(|err| GenTxError::SpendableNotesError(err.to_string())))?; let mut total_input_amount = BigDecimal::from(0); let mut change = BigDecimal::from(0); @@ -1007,7 +1007,7 @@ impl<'a> ZCoinBuilder<'a> { let (_, my_z_addr) = z_spending_key .default_address() - .map_err(|_| MmError::new(ZCoinBuildError::GetAddressError))?; + .map_to_mm(|_| ZCoinBuildError::GetAddressError)?; let my_z_addr_encoded = encode_payment_address(protocol_info.consensus_params.hrp_sapling_payment_address(), &my_z_addr); @@ -1037,7 +1037,7 @@ impl<'a> ZCoinBuilder<'a> { BlockDbImpl::new(ctx, ticker, cache_db_path) .await - .map_err(|err| MmError::new(ZcoinClientInitError::ZcoinStorageError(err.to_string()))) + .map_err(|err| err.map(|err| ZcoinClientInitError::ZcoinStorageError(err.to_string()))) } #[cfg(not(target_arch = "wasm32"))] @@ -1427,7 +1427,7 @@ impl SwapOps for ZCoin { .get_verbose_transaction(&tx_hash.into()) .compat() .await - .map_err(|e| MmError::new(ValidatePaymentError::InvalidRpcResponse(e.into_inner().to_string())))?; + .map_err(|e| e.map(|e| ValidatePaymentError::InvalidRpcResponse(e.to_string())))?; let mut encoded = Vec::with_capacity(1024); z_tx.write(&mut encoded).expect("Writing should not fail"); From e1f478feb0693fd3d3094c9f7b76981a894fd172 Mon Sep 17 00:00:00 2001 From: Omer Yacine Date: Fri, 16 May 2025 17:08:12 +0200 Subject: [PATCH 47/50] review(dimxy): don't use dyn in write/create_parents --- mm2src/mm2_io/src/fs.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mm2src/mm2_io/src/fs.rs b/mm2src/mm2_io/src/fs.rs index 4867f65aad..739e1c950d 100644 --- a/mm2src/mm2_io/src/fs.rs +++ b/mm2src/mm2_io/src/fs.rs @@ -272,7 +272,7 @@ where } /// Creates all the directories along the path to a file if they do not exist. -pub fn create_parents(path: &dyn AsRef) -> IoResult<()> { +pub fn create_parents(path: &impl AsRef) -> IoResult<()> { let parent_dir = path.as_ref().parent(); let Some(parent_dir) = parent_dir else { return MmError::err( @@ -330,7 +330,7 @@ pub async fn create_parents_async(path: &Path) -> IoResult<()> { /// This also creates any intermediary directories up to the file itself if they do not exist. /// If `use_tmp_file` is true, it writes to a temporary file first and then renames it to the final file name /// to ensure atomicity. -pub fn write(path: &dyn AsRef, content: &[u8], use_tmp_file: bool) -> IoResult<()> { +pub fn write(path: &impl AsRef, content: &[u8], use_tmp_file: bool) -> IoResult<()> { // Create all the directories in the path. create_parents(path)?; let path_tmp = if use_tmp_file { From 28dc4eafa283dadec46be9194d1b123ae6964101 Mon Sep 17 00:00:00 2001 From: Omer Yacine Date: Sun, 18 May 2025 19:13:27 +0200 Subject: [PATCH 48/50] Revert "put tx cache in proper address directory" + move tx cache in global dir This partially reverts commit 6149dbcd83359133c2ab20604803f0b3e83bda04. and puts tx cache in global direcotry. --- mm2src/coins/qrc20.rs | 10 ++---- .../utxo/utxo_builder/utxo_coin_builder.rs | 34 ++++++++----------- 2 files changed, 18 insertions(+), 26 deletions(-) diff --git a/mm2src/coins/qrc20.rs b/mm2src/coins/qrc20.rs index 2e1da16e06..ad01bba16f 100644 --- a/mm2src/coins/qrc20.rs +++ b/mm2src/coins/qrc20.rs @@ -258,13 +258,9 @@ impl<'a> UtxoCoinBuilderCommonOps for Qrc20CoinBuilder<'a> { /// Please note the method is overridden for Native mode only. #[inline] #[cfg(not(target_arch = "wasm32"))] - fn tx_cache(&self, my_address: &UtxoAddress) -> UtxoVerboseCacheShared { - let tx_cache = crate::utxo::tx_cache::fs_tx_cache::FsVerboseCache::new( - self.platform.clone(), - self.tx_cache_path(my_address), - ) - .into_shared(); - tx_cache + fn tx_cache(&self) -> UtxoVerboseCacheShared { + crate::utxo::tx_cache::fs_tx_cache::FsVerboseCache::new(self.platform.clone(), self.tx_cache_path()) + .into_shared() } } diff --git a/mm2src/coins/utxo/utxo_builder/utxo_coin_builder.rs b/mm2src/coins/utxo/utxo_builder/utxo_coin_builder.rs index dcca6363eb..03ccd6fd8b 100644 --- a/mm2src/coins/utxo/utxo_builder/utxo_coin_builder.rs +++ b/mm2src/coins/utxo/utxo_builder/utxo_coin_builder.rs @@ -260,7 +260,7 @@ where let initial_history_state = builder.initial_history_state(); let tx_hash_algo = builder.tx_hash_algo(); let check_utxo_maturity = builder.check_utxo_maturity(); - let tx_cache = builder.tx_cache(&my_address); + let tx_cache = builder.tx_cache(); let (block_headers_status_notifier, block_headers_status_watcher) = builder.block_header_status_channel(&conf.spv_conf); @@ -321,6 +321,13 @@ pub trait UtxoFieldsWithHardwareWalletBuilder: UtxoCoinBuilderCommonOps { address_format, }; + let my_address = hd_wallet + .get_enabled_address() + .await + .ok_or_else(|| UtxoCoinBuildError::Internal("Failed to get enabled address from HD wallet".to_owned()))?; + let my_script_pubkey = output_script(&my_address.address).map(|script| script.to_bytes())?; + let recently_spent_outpoints = AsyncMutex::new(RecentlySpentOutPoints::new(my_script_pubkey)); + // Create an abortable system linked to the `MmCtx` so if the context is stopped via `MmArc::stop`, // all spawned futures related to this `UTXO` coin will be aborted as well. let abortable_system: AbortableQueue = self.ctx().abortable_system.create_subsystem()?; @@ -333,12 +340,7 @@ pub trait UtxoFieldsWithHardwareWalletBuilder: UtxoCoinBuilderCommonOps { let initial_history_state = self.initial_history_state(); let tx_hash_algo = self.tx_hash_algo(); let check_utxo_maturity = self.check_utxo_maturity(); - let my_address = hd_wallet - .get_enabled_address() - .await - .ok_or_else(|| UtxoCoinBuildError::Internal("Failed to get enabled address from HD wallet".to_owned()))?; - let my_script_pubkey = output_script(&my_address.address).map(|script| script.to_bytes())?; - let tx_cache = self.tx_cache(&my_address.address); + let tx_cache = self.tx_cache(); let (block_headers_status_notifier, block_headers_status_watcher) = self.block_header_status_channel(&conf.spv_conf); @@ -351,7 +353,7 @@ pub trait UtxoFieldsWithHardwareWalletBuilder: UtxoCoinBuilderCommonOps { derivation_method: DerivationMethod::HDWallet(hd_wallet), history_sync_state: Mutex::new(initial_history_state), tx_cache, - recently_spent_outpoints: AsyncMutex::new(RecentlySpentOutPoints::new(my_script_pubkey)), + recently_spent_outpoints, tx_fee, tx_hash_algo, check_utxo_maturity, @@ -668,25 +670,19 @@ pub trait UtxoCoinBuilderCommonOps { } #[cfg(target_arch = "wasm32")] - fn tx_cache(&self, _my_address: &Address) -> UtxoVerboseCacheShared { + fn tx_cache(&self) -> UtxoVerboseCacheShared { #[allow(clippy::default_constructed_unit_structs)] // This is a false-possitive bug from clippy crate::utxo::tx_cache::wasm_tx_cache::WasmVerboseCache::default().into_shared() } #[cfg(not(target_arch = "wasm32"))] - fn tx_cache(&self, my_address: &Address) -> UtxoVerboseCacheShared { - let tx_cache = crate::utxo::tx_cache::fs_tx_cache::FsVerboseCache::new( - self.ticker().to_owned(), - self.tx_cache_path(my_address), - ) - .into_shared(); - tx_cache + fn tx_cache(&self) -> UtxoVerboseCacheShared { + crate::utxo::tx_cache::fs_tx_cache::FsVerboseCache::new(self.ticker().to_owned(), self.tx_cache_path()) + .into_shared() } #[cfg(not(target_arch = "wasm32"))] - fn tx_cache_path(&self, my_address: &Address) -> PathBuf { - self.ctx().address_dir(&my_address.to_string()).join("TX_CACHE") - } + fn tx_cache_path(&self) -> PathBuf { self.ctx().global_dir().join("TX_CACHE") } fn block_header_status_channel( &self, From 6d8328ae63dd9502712b76c2164a66ac94923ca1 Mon Sep 17 00:00:00 2001 From: Omer Yacine Date: Tue, 20 May 2025 08:15:45 +0200 Subject: [PATCH 49/50] put back the todo regarding recently spent outputs --- mm2src/coins/utxo.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/mm2src/coins/utxo.rs b/mm2src/coins/utxo.rs index 6fd2f28fe4..53e9bc7cdb 100644 --- a/mm2src/coins/utxo.rs +++ b/mm2src/coins/utxo.rs @@ -624,6 +624,7 @@ pub struct UtxoCoinFields { /// The cache of recently send transactions used to track the spent UTXOs and replace them with new outputs /// The daemon needs some time to update the listunspent list for address which makes it return already spent UTXOs /// This cache helps to prevent UTXO reuse in such cases + // TODO: change the type of `recently_spent_outpoints` to `AsyncMutex>` to better support HD wallets. pub recently_spent_outpoints: AsyncMutex, pub tx_hash_algo: TxHashAlgo, /// The flag determines whether to use mature unspent outputs *only* to generate transactions. From f76866a6a2edcc446d39c256cb1a84e3901b9a2d Mon Sep 17 00:00:00 2001 From: Omer Yacine Date: Tue, 20 May 2025 08:52:38 +0200 Subject: [PATCH 50/50] use mm_err instead of `.map_err(|e| e.map(|e| ...` --- mm2src/coins/z_coin.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mm2src/coins/z_coin.rs b/mm2src/coins/z_coin.rs index eb33ba08f6..d1487fc029 100644 --- a/mm2src/coins/z_coin.rs +++ b/mm2src/coins/z_coin.rs @@ -396,7 +396,7 @@ impl ZCoin { let spendable_notes = self .spendable_notes_ordered() .await - .map_err(|err| err.map(|err| GenTxError::SpendableNotesError(err.to_string())))?; + .mm_err(|err| GenTxError::SpendableNotesError(err.to_string()))?; let mut total_input_amount = BigDecimal::from(0); let mut change = BigDecimal::from(0); @@ -1037,7 +1037,7 @@ impl<'a> ZCoinBuilder<'a> { BlockDbImpl::new(ctx, ticker, cache_db_path) .await - .map_err(|err| err.map(|err| ZcoinClientInitError::ZcoinStorageError(err.to_string()))) + .mm_err(|err| ZcoinClientInitError::ZcoinStorageError(err.to_string())) } #[cfg(not(target_arch = "wasm32"))] @@ -1427,7 +1427,7 @@ impl SwapOps for ZCoin { .get_verbose_transaction(&tx_hash.into()) .compat() .await - .map_err(|e| e.map(|e| ValidatePaymentError::InvalidRpcResponse(e.to_string())))?; + .mm_err(|e| ValidatePaymentError::InvalidRpcResponse(e.to_string()))?; let mut encoded = Vec::with_capacity(1024); z_tx.write(&mut encoded).expect("Writing should not fail");