From eac9f81b7dc0c0ce736c9be60fe1d20df9055886 Mon Sep 17 00:00:00 2001 From: Samuel Onoja Date: Mon, 27 Jan 2025 19:38:15 +0100 Subject: [PATCH 01/25] save dev state --- mm2src/coins/lp_coins.rs | 20 +++++- mm2src/mm2_main/src/lp_native_dex.rs | 5 +- mm2src/mm2_main/src/lp_ordermatch.rs | 99 +++++++++++++++++++++++++++- 3 files changed, 120 insertions(+), 4 deletions(-) diff --git a/mm2src/coins/lp_coins.rs b/mm2src/coins/lp_coins.rs index ce23c3bfbe..195dba8b23 100644 --- a/mm2src/coins/lp_coins.rs +++ b/mm2src/coins/lp_coins.rs @@ -261,7 +261,7 @@ pub mod utxo; use utxo::bch::{bch_coin_with_policy, BchActivationRequest, BchCoin}; use utxo::qtum::{self, qtum_coin_with_policy, Qrc20AddressError, QtumCoin, QtumDelegationOps, QtumDelegationRequest, QtumStakingInfosDetails, ScriptHashTypeNotSupported}; -use utxo::rpc_clients::UtxoRpcError; +use utxo::rpc_clients::{ElectrumClient, UtxoRpcClientEnum, UtxoRpcError}; use utxo::slp::SlpToken; use utxo::slp::{slp_addr_from_pubkey_str, SlpFeeDetails}; use utxo::utxo_common::{big_decimal_from_sat_unsigned, payment_script, WaitForOutputSpendErr}; @@ -3565,6 +3565,24 @@ impl MmCoinEnum { pub fn is_eth(&self) -> bool { matches!(self, MmCoinEnum::EthCoin(_)) } fn is_platform_coin(&self) -> bool { self.ticker() == self.platform_ticker() } + + pub fn electrum_client(&self) -> Option { + let maybe_client = match self { + MmCoinEnum::UtxoCoin(c) => &c.as_ref().rpc_client, + MmCoinEnum::QtumCoin(c) => &c.as_ref().rpc_client, + MmCoinEnum::Qrc20Coin(c) => &c.as_ref().rpc_client, + MmCoinEnum::ZCoin(c) => &c.as_ref().rpc_client, + MmCoinEnum::Bch(c) => &c.as_ref().rpc_client, + MmCoinEnum::SlpToken(c) => &c.as_ref().rpc_client, + _ => return None, + }; + + if let UtxoRpcClientEnum::Electrum(c) = maybe_client { + Some(c.clone()) + } else { + None + } + } } #[async_trait] diff --git a/mm2src/mm2_main/src/lp_native_dex.rs b/mm2src/mm2_main/src/lp_native_dex.rs index 594daeb7d2..a9f5b29b61 100644 --- a/mm2src/mm2_main/src/lp_native_dex.rs +++ b/mm2src/mm2_main/src/lp_native_dex.rs @@ -51,7 +51,8 @@ use crate::lp_healthcheck::peer_healthcheck_topic; use crate::lp_message_service::{init_message_service, InitMessageServiceError}; use crate::lp_network::{lp_network_ports, p2p_event_process_loop, subscribe_to_topic, NetIdError}; use crate::lp_ordermatch::{broadcast_maker_orders_keep_alive_loop, clean_memory_loop, init_ordermatch_context, - lp_ordermatch_loop, orders_kick_start, BalanceUpdateOrdermatchHandler, OrdermatchInitError}; + lp_ordermatch_loop, monitor_electrum_and_cancel_orders, orders_kick_start, + BalanceUpdateOrdermatchHandler, OrdermatchInitError}; use crate::lp_swap; use crate::lp_swap::swap_kick_starts; use crate::lp_wallet::{initialize_wallet_passphrase, WalletInitError}; @@ -491,6 +492,8 @@ pub async fn lp_init_continue(ctx: MmArc) -> MmInitResult<()> { ctx.spawner().spawn(broadcast_maker_orders_keep_alive_loop(ctx.clone())); + ctx.spawner().spawn(monitor_electrum_and_cancel_orders(ctx.clone())); + #[cfg(target_arch = "wasm32")] init_wasm_event_streaming(&ctx); diff --git a/mm2src/mm2_main/src/lp_ordermatch.rs b/mm2src/mm2_main/src/lp_ordermatch.rs index 631d7cb55d..a2d81dd998 100644 --- a/mm2src/mm2_main/src/lp_ordermatch.rs +++ b/mm2src/mm2_main/src/lp_ordermatch.rs @@ -28,7 +28,7 @@ use coins::{coin_conf, find_pair, lp_coinfind, BalanceTradeFeeUpdatedHandler, Co FeeApproxStage, MarketCoinOps, MmCoinEnum}; use common::executor::{simple_map::AbortableSimpleMap, AbortSettings, AbortableSystem, AbortedError, SpawnAbortable, SpawnFuture, Timer}; -use common::log::{error, warn, LogOnError}; +use common::log::{info, debug, error, warn, LogOnError}; use common::{bits256, log, new_uuid, now_ms, now_sec}; use crypto::privkey::SerializableSecp256k1Keypair; use crypto::{CryptoCtx, CryptoCtxError}; @@ -59,9 +59,10 @@ use rpc::v1::types::H256 as H256Json; use serde_json::{self as json, Value as Json}; use sp_trie::{delta_trie_root, MemoryDB, Trie, TrieConfiguration, TrieDB, TrieDBMut, TrieHash, TrieMut}; use std::collections::hash_map::{Entry, HashMap, RawEntryMut}; -use std::collections::{BTreeSet, HashSet}; +use std::collections::{BTreeSet, HashSet, VecDeque}; use std::convert::TryInto; use std::fmt; +use std::iter::FromIterator; use std::ops::Deref; use std::path::PathBuf; use std::sync::Arc; @@ -131,6 +132,7 @@ const TRIE_STATE_HISTORY_TIMEOUT: u64 = 3; const TRIE_ORDER_HISTORY_TIMEOUT: u64 = 300; #[cfg(test)] const TRIE_ORDER_HISTORY_TIMEOUT: u64 = 3; +pub const MONITOR_ELECTRUM_CLIENT_INTERVAL: f64 = 30.; pub type OrderbookP2PHandlerResult = Result<(), MmError>; @@ -2320,6 +2322,97 @@ fn broadcast_ordermatch_message( broadcast_p2p_msg(ctx, topic, encoded_msg, peer_id); } +pub async fn monitor_electrum_and_cancel_orders(ctx: MmArc) { + info!("Monitor electrum connection and cancel orders loop running!"); + while !ctx.is_stopping() { + let ordermatch_ctx = OrdermatchContext::from_ctx(&ctx).expect("from_ctx failed"); + let my_maker_orders = ordermatch_ctx.maker_orders_ctx.lock().orders.clone(); + let mut order_queue = VecDeque::from_iter(my_maker_orders); + + while let Some((uuid, my_order)) = order_queue.pop_front() { + let order = my_order.lock().await; + if !order.is_cancellable() { + continue; + } + let Ok(coin) = lp_coinfind_or_err(&ctx, &order.base).await else { + debug!("[{uuid}] Maker order coin {} not activated yet, will check back in {MONITOR_ELECTRUM_CLIENT_INTERVAL}s"", order.base); + drop(order); + order_queue.push_back((uuid, my_order)); + continue; + }; + if let Some(c) = coin.electrum_client() { + if !c.deref().connection_manager.get_active_connections().is_empty() { + continue; + } + let removed_order_mutex = ordermatch_ctx.maker_orders_ctx.lock().remove_order(&uuid); + if removed_order_mutex.is_some() { + maker_order_cancelled_p2p_notify(&ctx, &order); + delete_my_maker_order( + ctx.clone(), + order.clone(), + MakerOrderCancellationReason::ElectrumServersOffline, + ) + .compat() + .await + .ok(); + info!( + "[{}]: Maker order cancelled - reason: {}", + uuid, + MakerOrderCancellationReason::ElectrumServersOffline + ); + }; + }; + } + // Taker order. + let mut my_taker_orders_queue = VecDeque::from_iter( + ordermatch_ctx + .my_taker_orders + .lock() + .await + .clone() + .into_iter() + .map(|(uuid, order)| (uuid, order.base_orderbook_ticker().to_owned())) + .collect::>(), + ); + while let Some((uuid, ticker)) = my_taker_orders_queue.pop_front() { + let Ok(coin) = lp_coinfind_or_err(&ctx, &ticker).await else { + debug!("[{uuid}] Taker order coin {ticker} not activated yet, will check back in {MONITOR_ELECTRUM_CLIENT_INTERVAL}s"); + my_taker_orders_queue.push_back((uuid, ticker)); + continue; + }; + if let Some(c) = coin.electrum_client() { + if !c.deref().connection_manager.get_active_connections().is_empty() { + continue; + } + let mut taker_orders = ordermatch_ctx.my_taker_orders.lock().await; + match taker_orders.entry(uuid) { + Entry::Occupied(order) => { + if !order.get().is_cancellable() { + continue; + } + delete_my_taker_order( + ctx.clone(), + order.remove(), + TakerOrderCancellationReason::ElectrumServersOffline, + ) + .compat() + .await + .ok(); + info!( + "[{}]: Taker order cancelled - reason: {}", + uuid, + TakerOrderCancellationReason::ElectrumServersOffline + ); + }, + // error is returned + Entry::Vacant(_) => (), + } + }; + } + Timer::sleep(MONITOR_ELECTRUM_CLIENT_INTERVAL).await; + } +} + /// The order is ordered by [`OrderbookItem::price`] and [`OrderbookItem::uuid`]. #[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd)] struct OrderedByPriceOrder { @@ -4989,6 +5082,7 @@ pub enum MakerOrderCancellationReason { Fulfilled, InsufficientBalance, Cancelled, + ElectrumServersOffline } #[derive(Display)] @@ -4997,6 +5091,7 @@ pub enum TakerOrderCancellationReason { ToMaker, TimedOut, Cancelled, + ElectrumServersOffline } #[derive(Debug, Deserialize)] From 3618dddf02461002830e64e16bc1710df55896e4 Mon Sep 17 00:00:00 2001 From: Samuel Onoja Date: Mon, 27 Jan 2025 19:50:14 +0100 Subject: [PATCH 02/25] fix string termination err --- mm2src/mm2_main/src/lp_ordermatch.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/mm2src/mm2_main/src/lp_ordermatch.rs b/mm2src/mm2_main/src/lp_ordermatch.rs index a2d81dd998..39c7acc6e1 100644 --- a/mm2src/mm2_main/src/lp_ordermatch.rs +++ b/mm2src/mm2_main/src/lp_ordermatch.rs @@ -24,11 +24,11 @@ use async_trait::async_trait; use blake2::digest::{Update, VariableOutput}; use blake2::Blake2bVar; use coins::utxo::{compressed_pub_key_from_priv_raw, ChecksumType, UtxoAddressFormat}; -use coins::{coin_conf, find_pair, lp_coinfind, BalanceTradeFeeUpdatedHandler, CoinProtocol, CoinsContext, - FeeApproxStage, MarketCoinOps, MmCoinEnum}; +use coins::{coin_conf, find_pair, lp_coinfind, lp_coinfind_or_err, BalanceTradeFeeUpdatedHandler, CoinProtocol, + CoinsContext, FeeApproxStage, MarketCoinOps, MmCoinEnum}; use common::executor::{simple_map::AbortableSimpleMap, AbortSettings, AbortableSystem, AbortedError, SpawnAbortable, SpawnFuture, Timer}; -use common::log::{info, debug, error, warn, LogOnError}; +use common::log::{debug, error, info, warn, LogOnError}; use common::{bits256, log, new_uuid, now_ms, now_sec}; use crypto::privkey::SerializableSecp256k1Keypair; use crypto::{CryptoCtx, CryptoCtxError}; @@ -132,7 +132,7 @@ const TRIE_STATE_HISTORY_TIMEOUT: u64 = 3; const TRIE_ORDER_HISTORY_TIMEOUT: u64 = 300; #[cfg(test)] const TRIE_ORDER_HISTORY_TIMEOUT: u64 = 3; -pub const MONITOR_ELECTRUM_CLIENT_INTERVAL: f64 = 30.; +const MONITOR_ELECTRUM_CLIENT_INTERVAL: f64 = 30.; pub type OrderbookP2PHandlerResult = Result<(), MmError>; @@ -2335,7 +2335,7 @@ pub async fn monitor_electrum_and_cancel_orders(ctx: MmArc) { continue; } let Ok(coin) = lp_coinfind_or_err(&ctx, &order.base).await else { - debug!("[{uuid}] Maker order coin {} not activated yet, will check back in {MONITOR_ELECTRUM_CLIENT_INTERVAL}s"", order.base); + debug!("[{uuid}] Maker order coin {} not activated yet, will check back in {MONITOR_ELECTRUM_CLIENT_INTERVAL}s", order.base); drop(order); order_queue.push_back((uuid, my_order)); continue; @@ -5082,7 +5082,7 @@ pub enum MakerOrderCancellationReason { Fulfilled, InsufficientBalance, Cancelled, - ElectrumServersOffline + ElectrumServersOffline, } #[derive(Display)] @@ -5091,7 +5091,7 @@ pub enum TakerOrderCancellationReason { ToMaker, TimedOut, Cancelled, - ElectrumServersOffline + ElectrumServersOffline, } #[derive(Debug, Deserialize)] From 6a48ca2a2dbd06475da419b9036e19e5ca9ba72f Mon Sep 17 00:00:00 2001 From: Samuel Onoja Date: Wed, 12 Feb 2025 20:34:15 +0100 Subject: [PATCH 03/25] add is_active flag for MakerOrder --- mm2src/mm2_main/src/lp_ordermatch.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/mm2src/mm2_main/src/lp_ordermatch.rs b/mm2src/mm2_main/src/lp_ordermatch.rs index 39c7acc6e1..3a5eaf0664 100644 --- a/mm2src/mm2_main/src/lp_ordermatch.rs +++ b/mm2src/mm2_main/src/lp_ordermatch.rs @@ -1691,6 +1691,8 @@ pub struct MakerOrder { /// A custom priv key for more privacy to prevent linking orders of the same node between each other /// Commonly used with privacy coins (ARRR, ZCash, etc.) p2p_privkey: Option, + // Signal for maker orders that should be ordermatched. + is_active: bool, } pub struct MakerOrderBuilder<'a> { @@ -1946,6 +1948,7 @@ impl<'a> MakerOrderBuilder<'a> { base_orderbook_ticker: self.base_orderbook_ticker, rel_orderbook_ticker: self.rel_orderbook_ticker, p2p_privkey, + is_active: true, }) } @@ -1970,6 +1973,7 @@ impl<'a> MakerOrderBuilder<'a> { base_orderbook_ticker: None, rel_orderbook_ticker: None, p2p_privkey: None, + is_active: true, } } } @@ -2077,6 +2081,8 @@ impl MakerOrder { fn was_updated(&self) -> bool { self.updated_at != Some(self.created_at) } fn p2p_keypair(&self) -> Option<&KeyPair> { self.p2p_privkey.as_ref().map(|key| key.key_pair()) } + + fn is_active(&self) -> bool { self.is_active } } impl From for MakerOrder { @@ -2100,6 +2106,7 @@ impl From for MakerOrder { base_orderbook_ticker: taker_order.base_orderbook_ticker, rel_orderbook_ticker: taker_order.rel_orderbook_ticker, p2p_privkey: taker_order.p2p_privkey, + is_active: true, }, // The "buy" taker order is recreated with reversed pair as Maker order is always considered as "sell" TakerAction::Buy => { @@ -2122,6 +2129,7 @@ impl From for MakerOrder { base_orderbook_ticker: taker_order.rel_orderbook_ticker, rel_orderbook_ticker: taker_order.base_orderbook_ticker, p2p_privkey: taker_order.p2p_privkey, + is_active: true, } }, } From d2b8cffd62f5e56c3403b56d0fae47249da79859 Mon Sep 17 00:00:00 2001 From: Samuel Onoja Date: Wed, 12 Feb 2025 21:01:41 +0100 Subject: [PATCH 04/25] add todos and fill is_active flag for MakerOrder initializations --- mm2src/mm2_main/src/lp_ordermatch.rs | 8 ++++++++ .../src/lp_ordermatch/my_orders_storage.rs | 1 + mm2src/mm2_main/src/ordermatch_tests.rs | 16 ++++++++++++++++ 3 files changed, 25 insertions(+) diff --git a/mm2src/mm2_main/src/lp_ordermatch.rs b/mm2src/mm2_main/src/lp_ordermatch.rs index 3a5eaf0664..5cb07da050 100644 --- a/mm2src/mm2_main/src/lp_ordermatch.rs +++ b/mm2src/mm2_main/src/lp_ordermatch.rs @@ -2004,6 +2004,8 @@ impl MakerOrder { } fn match_with_request(&self, taker: &TakerRequest) -> OrderMatchResult { + // TODO: only match with taker assuming our coin relies on electrum connections + // and there's an atleast 1 active connection. let taker_base_amount = taker.get_base_amount(); let taker_rel_amount = taker.get_rel_amount(); @@ -3557,6 +3559,10 @@ async fn check_balance_for_maker_orders(ctx: MmArc, ordermatch_ctx: &OrdermatchC continue; } + // TODO: check coin depends on electrum and check their connection status. + // if connection status to all electrum client for this coin is down, + // change maker_order.is_active to false. + let reason = if order.matches.is_empty() { MakerOrderCancellationReason::InsufficientBalance } else { @@ -4884,6 +4890,8 @@ async fn cancel_previous_maker_orders( } } +// TODO: I should probaly implement `update_maker_order_active_status` here. + pub async fn update_maker_order(ctx: &MmArc, req: MakerOrderUpdateReq) -> Result { let ordermatch_ctx = try_s!(OrdermatchContext::from_ctx(ctx)); let order_mutex = { diff --git a/mm2src/mm2_main/src/lp_ordermatch/my_orders_storage.rs b/mm2src/mm2_main/src/lp_ordermatch/my_orders_storage.rs index 05322325a5..338d0ee90a 100644 --- a/mm2src/mm2_main/src/lp_ordermatch/my_orders_storage.rs +++ b/mm2src/mm2_main/src/lp_ordermatch/my_orders_storage.rs @@ -724,6 +724,7 @@ mod tests { base_orderbook_ticker: None, rel_orderbook_ticker: None, p2p_privkey: None, + is_active: true, } } diff --git a/mm2src/mm2_main/src/ordermatch_tests.rs b/mm2src/mm2_main/src/ordermatch_tests.rs index 56a9c6a135..90c67fac73 100644 --- a/mm2src/mm2_main/src/ordermatch_tests.rs +++ b/mm2src/mm2_main/src/ordermatch_tests.rs @@ -39,6 +39,7 @@ fn test_match_maker_order_and_taker_request() { base_orderbook_ticker: None, rel_orderbook_ticker: None, p2p_privkey: None, + is_active: true, }; let request = TakerRequest { @@ -77,6 +78,7 @@ fn test_match_maker_order_and_taker_request() { base_orderbook_ticker: None, rel_orderbook_ticker: None, p2p_privkey: None, + is_active: true, }; let request = TakerRequest { @@ -115,6 +117,7 @@ fn test_match_maker_order_and_taker_request() { base_orderbook_ticker: None, rel_orderbook_ticker: None, p2p_privkey: None, + is_active: true, }; let request = TakerRequest { @@ -153,6 +156,7 @@ fn test_match_maker_order_and_taker_request() { base_orderbook_ticker: None, rel_orderbook_ticker: None, p2p_privkey: None, + is_active: true, }; let request = TakerRequest { @@ -191,6 +195,7 @@ fn test_match_maker_order_and_taker_request() { base_orderbook_ticker: None, rel_orderbook_ticker: None, p2p_privkey: None, + is_active: true, }; let request = TakerRequest { @@ -229,6 +234,7 @@ fn test_match_maker_order_and_taker_request() { base_orderbook_ticker: None, rel_orderbook_ticker: None, p2p_privkey: None, + is_active: true, }; let request = TakerRequest { @@ -269,6 +275,7 @@ fn test_match_maker_order_and_taker_request() { base_orderbook_ticker: None, rel_orderbook_ticker: None, p2p_privkey: None, + is_active: true, }; let request = TakerRequest { base: "KMD".to_owned(), @@ -309,6 +316,7 @@ fn test_match_maker_order_and_taker_request() { base_orderbook_ticker: None, rel_orderbook_ticker: None, p2p_privkey: None, + is_active: true, }; let request = TakerRequest { base: "REL".to_owned(), @@ -380,6 +388,7 @@ fn test_maker_order_available_amount() { base_orderbook_ticker: None, rel_orderbook_ticker: None, p2p_privkey: None, + is_active: true, }; maker.matches.insert(new_uuid(), MakerMatch { request: TakerRequest { @@ -974,6 +983,7 @@ fn prepare_for_cancel_by(ctx: &MmArc) -> mpsc::Receiver { base_orderbook_ticker: None, rel_orderbook_ticker: None, p2p_privkey: None, + is_active: true, }, None, ); @@ -996,6 +1006,7 @@ fn prepare_for_cancel_by(ctx: &MmArc) -> mpsc::Receiver { base_orderbook_ticker: None, rel_orderbook_ticker: None, p2p_privkey: None, + is_active: true, }, None, ); @@ -1018,6 +1029,7 @@ fn prepare_for_cancel_by(ctx: &MmArc) -> mpsc::Receiver { base_orderbook_ticker: None, rel_orderbook_ticker: None, p2p_privkey: None, + is_active: true, }, None, ); @@ -1206,6 +1218,7 @@ fn test_maker_order_was_updated() { base_orderbook_ticker: None, rel_orderbook_ticker: None, p2p_privkey: None, + is_active: true, }; let mut update_msg = MakerOrderUpdated::new(maker_order.uuid); update_msg.with_new_price(BigRational::from_integer(2.into())); @@ -3215,6 +3228,7 @@ fn test_maker_order_balance_loops() { base_orderbook_ticker: None, rel_orderbook_ticker: None, p2p_privkey: None, + is_active: true, }; let morty_order = MakerOrder { @@ -3234,6 +3248,7 @@ fn test_maker_order_balance_loops() { base_orderbook_ticker: None, rel_orderbook_ticker: None, p2p_privkey: None, + is_active: true, }; assert!(!maker_orders_ctx.balance_loop_exists(rick_ticker)); @@ -3266,6 +3281,7 @@ fn test_maker_order_balance_loops() { base_orderbook_ticker: None, rel_orderbook_ticker: None, p2p_privkey: None, + is_active: true, }; maker_orders_ctx.add_order(ctx.weak(), rick_order_2.clone(), None); From 98f53ccc8055853271ed3651efb44045e2683aee Mon Sep 17 00:00:00 2001 From: Samuel Onoja Date: Thu, 13 Feb 2025 00:08:00 +0100 Subject: [PATCH 05/25] pause maker others from matching if coin relies on electrum conns --- mm2src/coins/lp_coins.rs | 20 ++-- mm2src/mm2_main/src/lp_native_dex.rs | 5 +- mm2src/mm2_main/src/lp_ordermatch.rs | 139 ++++++------------------ mm2src/mm2_main/src/ordermatch_tests.rs | 42 +++++++ 4 files changed, 86 insertions(+), 120 deletions(-) diff --git a/mm2src/coins/lp_coins.rs b/mm2src/coins/lp_coins.rs index 195dba8b23..bb4a1c9757 100644 --- a/mm2src/coins/lp_coins.rs +++ b/mm2src/coins/lp_coins.rs @@ -261,7 +261,7 @@ pub mod utxo; use utxo::bch::{bch_coin_with_policy, BchActivationRequest, BchCoin}; use utxo::qtum::{self, qtum_coin_with_policy, Qrc20AddressError, QtumCoin, QtumDelegationOps, QtumDelegationRequest, QtumStakingInfosDetails, ScriptHashTypeNotSupported}; -use utxo::rpc_clients::{ElectrumClient, UtxoRpcClientEnum, UtxoRpcError}; +use utxo::rpc_clients::{UtxoRpcClientEnum, UtxoRpcError}; use utxo::slp::SlpToken; use utxo::slp::{slp_addr_from_pubkey_str, SlpFeeDetails}; use utxo::utxo_common::{big_decimal_from_sat_unsigned, payment_script, WaitForOutputSpendErr}; @@ -3566,8 +3566,8 @@ impl MmCoinEnum { fn is_platform_coin(&self) -> bool { self.ticker() == self.platform_ticker() } - pub fn electrum_client(&self) -> Option { - let maybe_client = match self { + pub fn utxo_in_electrum_mode_has_active_connection(&self) -> Option { + if let UtxoRpcClientEnum::Electrum(c) = match self { MmCoinEnum::UtxoCoin(c) => &c.as_ref().rpc_client, MmCoinEnum::QtumCoin(c) => &c.as_ref().rpc_client, MmCoinEnum::Qrc20Coin(c) => &c.as_ref().rpc_client, @@ -3575,13 +3575,15 @@ impl MmCoinEnum { MmCoinEnum::Bch(c) => &c.as_ref().rpc_client, MmCoinEnum::SlpToken(c) => &c.as_ref().rpc_client, _ => return None, - }; - - if let UtxoRpcClientEnum::Electrum(c) = maybe_client { - Some(c.clone()) - } else { - None + } { + if c.connection_manager.get_active_connections().is_empty() { + return Some(false); + } else { + return Some(true); + } } + + None } } diff --git a/mm2src/mm2_main/src/lp_native_dex.rs b/mm2src/mm2_main/src/lp_native_dex.rs index a9f5b29b61..594daeb7d2 100644 --- a/mm2src/mm2_main/src/lp_native_dex.rs +++ b/mm2src/mm2_main/src/lp_native_dex.rs @@ -51,8 +51,7 @@ use crate::lp_healthcheck::peer_healthcheck_topic; use crate::lp_message_service::{init_message_service, InitMessageServiceError}; use crate::lp_network::{lp_network_ports, p2p_event_process_loop, subscribe_to_topic, NetIdError}; use crate::lp_ordermatch::{broadcast_maker_orders_keep_alive_loop, clean_memory_loop, init_ordermatch_context, - lp_ordermatch_loop, monitor_electrum_and_cancel_orders, orders_kick_start, - BalanceUpdateOrdermatchHandler, OrdermatchInitError}; + lp_ordermatch_loop, orders_kick_start, BalanceUpdateOrdermatchHandler, OrdermatchInitError}; use crate::lp_swap; use crate::lp_swap::swap_kick_starts; use crate::lp_wallet::{initialize_wallet_passphrase, WalletInitError}; @@ -492,8 +491,6 @@ pub async fn lp_init_continue(ctx: MmArc) -> MmInitResult<()> { ctx.spawner().spawn(broadcast_maker_orders_keep_alive_loop(ctx.clone())); - ctx.spawner().spawn(monitor_electrum_and_cancel_orders(ctx.clone())); - #[cfg(target_arch = "wasm32")] init_wasm_event_streaming(&ctx); diff --git a/mm2src/mm2_main/src/lp_ordermatch.rs b/mm2src/mm2_main/src/lp_ordermatch.rs index 5cb07da050..028c3cbdef 100644 --- a/mm2src/mm2_main/src/lp_ordermatch.rs +++ b/mm2src/mm2_main/src/lp_ordermatch.rs @@ -24,11 +24,11 @@ use async_trait::async_trait; use blake2::digest::{Update, VariableOutput}; use blake2::Blake2bVar; use coins::utxo::{compressed_pub_key_from_priv_raw, ChecksumType, UtxoAddressFormat}; -use coins::{coin_conf, find_pair, lp_coinfind, lp_coinfind_or_err, BalanceTradeFeeUpdatedHandler, CoinProtocol, - CoinsContext, FeeApproxStage, MarketCoinOps, MmCoinEnum}; +use coins::{coin_conf, find_pair, lp_coinfind, BalanceTradeFeeUpdatedHandler, CoinProtocol, CoinsContext, + FeeApproxStage, MarketCoinOps, MmCoinEnum}; use common::executor::{simple_map::AbortableSimpleMap, AbortSettings, AbortableSystem, AbortedError, SpawnAbortable, SpawnFuture, Timer}; -use common::log::{debug, error, info, warn, LogOnError}; +use common::log::{error, info, warn, LogOnError}; use common::{bits256, log, new_uuid, now_ms, now_sec}; use crypto::privkey::SerializableSecp256k1Keypair; use crypto::{CryptoCtx, CryptoCtxError}; @@ -59,10 +59,9 @@ use rpc::v1::types::H256 as H256Json; use serde_json::{self as json, Value as Json}; use sp_trie::{delta_trie_root, MemoryDB, Trie, TrieConfiguration, TrieDB, TrieDBMut, TrieHash, TrieMut}; use std::collections::hash_map::{Entry, HashMap, RawEntryMut}; -use std::collections::{BTreeSet, HashSet, VecDeque}; +use std::collections::{BTreeSet, HashSet}; use std::convert::TryInto; use std::fmt; -use std::iter::FromIterator; use std::ops::Deref; use std::path::PathBuf; use std::sync::Arc; @@ -132,7 +131,6 @@ const TRIE_STATE_HISTORY_TIMEOUT: u64 = 3; const TRIE_ORDER_HISTORY_TIMEOUT: u64 = 300; #[cfg(test)] const TRIE_ORDER_HISTORY_TIMEOUT: u64 = 3; -const MONITOR_ELECTRUM_CLIENT_INTERVAL: f64 = 30.; pub type OrderbookP2PHandlerResult = Result<(), MmError>; @@ -1691,7 +1689,7 @@ pub struct MakerOrder { /// A custom priv key for more privacy to prevent linking orders of the same node between each other /// Commonly used with privacy coins (ARRR, ZCash, etc.) p2p_privkey: Option, - // Signal for maker orders that should be ordermatched. + // Indicates whether the maker order is eligible for order matching. is_active: bool, } @@ -2004,8 +2002,14 @@ impl MakerOrder { } fn match_with_request(&self, taker: &TakerRequest) -> OrderMatchResult { - // TODO: only match with taker assuming our coin relies on electrum connections - // and there's an atleast 1 active connection. + if !self.is_active { + info!( + "[{}] Maker order is inactive, skipping order match with taker", + self.uuid + ); + return OrderMatchResult::NotMatched; + } + let taker_base_amount = taker.get_base_amount(); let taker_rel_amount = taker.get_rel_amount(); @@ -2083,8 +2087,6 @@ impl MakerOrder { fn was_updated(&self) -> bool { self.updated_at != Some(self.created_at) } fn p2p_keypair(&self) -> Option<&KeyPair> { self.p2p_privkey.as_ref().map(|key| key.key_pair()) } - - fn is_active(&self) -> bool { self.is_active } } impl From for MakerOrder { @@ -2332,97 +2334,6 @@ fn broadcast_ordermatch_message( broadcast_p2p_msg(ctx, topic, encoded_msg, peer_id); } -pub async fn monitor_electrum_and_cancel_orders(ctx: MmArc) { - info!("Monitor electrum connection and cancel orders loop running!"); - while !ctx.is_stopping() { - let ordermatch_ctx = OrdermatchContext::from_ctx(&ctx).expect("from_ctx failed"); - let my_maker_orders = ordermatch_ctx.maker_orders_ctx.lock().orders.clone(); - let mut order_queue = VecDeque::from_iter(my_maker_orders); - - while let Some((uuid, my_order)) = order_queue.pop_front() { - let order = my_order.lock().await; - if !order.is_cancellable() { - continue; - } - let Ok(coin) = lp_coinfind_or_err(&ctx, &order.base).await else { - debug!("[{uuid}] Maker order coin {} not activated yet, will check back in {MONITOR_ELECTRUM_CLIENT_INTERVAL}s", order.base); - drop(order); - order_queue.push_back((uuid, my_order)); - continue; - }; - if let Some(c) = coin.electrum_client() { - if !c.deref().connection_manager.get_active_connections().is_empty() { - continue; - } - let removed_order_mutex = ordermatch_ctx.maker_orders_ctx.lock().remove_order(&uuid); - if removed_order_mutex.is_some() { - maker_order_cancelled_p2p_notify(&ctx, &order); - delete_my_maker_order( - ctx.clone(), - order.clone(), - MakerOrderCancellationReason::ElectrumServersOffline, - ) - .compat() - .await - .ok(); - info!( - "[{}]: Maker order cancelled - reason: {}", - uuid, - MakerOrderCancellationReason::ElectrumServersOffline - ); - }; - }; - } - // Taker order. - let mut my_taker_orders_queue = VecDeque::from_iter( - ordermatch_ctx - .my_taker_orders - .lock() - .await - .clone() - .into_iter() - .map(|(uuid, order)| (uuid, order.base_orderbook_ticker().to_owned())) - .collect::>(), - ); - while let Some((uuid, ticker)) = my_taker_orders_queue.pop_front() { - let Ok(coin) = lp_coinfind_or_err(&ctx, &ticker).await else { - debug!("[{uuid}] Taker order coin {ticker} not activated yet, will check back in {MONITOR_ELECTRUM_CLIENT_INTERVAL}s"); - my_taker_orders_queue.push_back((uuid, ticker)); - continue; - }; - if let Some(c) = coin.electrum_client() { - if !c.deref().connection_manager.get_active_connections().is_empty() { - continue; - } - let mut taker_orders = ordermatch_ctx.my_taker_orders.lock().await; - match taker_orders.entry(uuid) { - Entry::Occupied(order) => { - if !order.get().is_cancellable() { - continue; - } - delete_my_taker_order( - ctx.clone(), - order.remove(), - TakerOrderCancellationReason::ElectrumServersOffline, - ) - .compat() - .await - .ok(); - info!( - "[{}]: Taker order cancelled - reason: {}", - uuid, - TakerOrderCancellationReason::ElectrumServersOffline - ); - }, - // error is returned - Entry::Vacant(_) => (), - } - }; - } - Timer::sleep(MONITOR_ELECTRUM_CLIENT_INTERVAL).await; - } -} - /// The order is ordered by [`OrderbookItem::price`] and [`OrderbookItem::uuid`]. #[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd)] struct OrderedByPriceOrder { @@ -3554,15 +3465,29 @@ async fn check_balance_for_maker_orders(ctx: MmArc, ordermatch_ctx: &OrdermatchC let my_maker_orders = ordermatch_ctx.maker_orders_ctx.lock().orders.clone(); for (uuid, order) in my_maker_orders { - let order = order.lock().await; + let mut order = order.lock().await; + if order.available_amount() >= order.min_base_vol || order.has_ongoing_matches() { + if order.has_ongoing_matches() { + continue; + } + + if let Ok(Some(coin)) = lp_coinfind(&ctx, &order.base).await { + // Check if the base coin uses Electrum and update the order's active status only if it has changed + if let Some(is_active) = coin.utxo_in_electrum_mode_has_active_connection() { + if is_active != order.is_active { + order.is_active = is_active; + info!( + "[{}] Order status updated to `{is_active}` based on Electrum connection status", + order.uuid + ); + } + } + }; + continue; } - // TODO: check coin depends on electrum and check their connection status. - // if connection status to all electrum client for this coin is down, - // change maker_order.is_active to false. - let reason = if order.matches.is_empty() { MakerOrderCancellationReason::InsufficientBalance } else { diff --git a/mm2src/mm2_main/src/ordermatch_tests.rs b/mm2src/mm2_main/src/ordermatch_tests.rs index 90c67fac73..988d3c4c32 100644 --- a/mm2src/mm2_main/src/ordermatch_tests.rs +++ b/mm2src/mm2_main/src/ordermatch_tests.rs @@ -3299,3 +3299,45 @@ fn test_maker_order_balance_loops() { assert!(!maker_orders_ctx.balance_loop_exists(morty_ticker)); assert_eq!(*maker_orders_ctx.count_by_tickers.get(morty_ticker).unwrap(), 0); } + +#[test] +fn test_match_maker_order_and_taker_request_fails_with_not_active() { + let maker = MakerOrder { + base: "BASE".into(), + rel: "REL".into(), + created_at: now_ms(), + updated_at: Some(now_ms()), + max_base_vol: 10.into(), + min_base_vol: 0.into(), + price: 1.into(), + matches: HashMap::new(), + started_swaps: Vec::new(), + uuid: new_uuid(), + conf_settings: None, + changes_history: None, + save_in_history: false, + base_orderbook_ticker: None, + rel_orderbook_ticker: None, + p2p_privkey: None, + is_active: false, // maker order not active + }; + + let request = TakerRequest { + base: "BASE".into(), + rel: "REL".into(), + uuid: new_uuid(), + dest_pub_key: H256Json::default(), + sender_pubkey: H256Json::default(), + base_amount: 10.into(), + rel_amount: 20.into(), + action: TakerAction::Buy, + match_by: MatchBy::Any, + conf_settings: None, + base_protocol_info: None, + rel_protocol_info: None, + }; + + let actual = maker.match_with_request(&request); + let expected = OrderMatchResult::NotMatched; + assert_eq!(expected, actual); +} From ca7190ff0cf4141f8a2a7f0760935ac52ad82251 Mon Sep 17 00:00:00 2001 From: Samuel Onoja Date: Thu, 13 Feb 2025 00:31:24 +0100 Subject: [PATCH 06/25] remove todo comment and unneeded if-else --- mm2src/coins/lp_coins.rs | 6 +----- mm2src/mm2_main/src/lp_ordermatch.rs | 2 -- 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/mm2src/coins/lp_coins.rs b/mm2src/coins/lp_coins.rs index bb4a1c9757..7e60fcd82f 100644 --- a/mm2src/coins/lp_coins.rs +++ b/mm2src/coins/lp_coins.rs @@ -3576,11 +3576,7 @@ impl MmCoinEnum { MmCoinEnum::SlpToken(c) => &c.as_ref().rpc_client, _ => return None, } { - if c.connection_manager.get_active_connections().is_empty() { - return Some(false); - } else { - return Some(true); - } + return Some(!c.connection_manager.get_active_connections().is_empty()); } None diff --git a/mm2src/mm2_main/src/lp_ordermatch.rs b/mm2src/mm2_main/src/lp_ordermatch.rs index 028c3cbdef..b2124a592d 100644 --- a/mm2src/mm2_main/src/lp_ordermatch.rs +++ b/mm2src/mm2_main/src/lp_ordermatch.rs @@ -4815,8 +4815,6 @@ async fn cancel_previous_maker_orders( } } -// TODO: I should probaly implement `update_maker_order_active_status` here. - pub async fn update_maker_order(ctx: &MmArc, req: MakerOrderUpdateReq) -> Result { let ordermatch_ctx = try_s!(OrdermatchContext::from_ctx(ctx)); let order_mutex = { From 6420d9472022832ab6872091a18c1110df417a8d Mon Sep 17 00:00:00 2001 From: Samuel Onoja Date: Thu, 13 Feb 2025 01:47:39 +0100 Subject: [PATCH 07/25] remove unused --- mm2src/mm2_main/src/lp_ordermatch.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/mm2src/mm2_main/src/lp_ordermatch.rs b/mm2src/mm2_main/src/lp_ordermatch.rs index b2124a592d..53fbc3028a 100644 --- a/mm2src/mm2_main/src/lp_ordermatch.rs +++ b/mm2src/mm2_main/src/lp_ordermatch.rs @@ -131,6 +131,7 @@ const TRIE_STATE_HISTORY_TIMEOUT: u64 = 3; const TRIE_ORDER_HISTORY_TIMEOUT: u64 = 300; #[cfg(test)] const TRIE_ORDER_HISTORY_TIMEOUT: u64 = 3; +r pub type OrderbookP2PHandlerResult = Result<(), MmError>; @@ -5021,7 +5022,6 @@ pub enum MakerOrderCancellationReason { Fulfilled, InsufficientBalance, Cancelled, - ElectrumServersOffline, } #[derive(Display)] @@ -5030,7 +5030,6 @@ pub enum TakerOrderCancellationReason { ToMaker, TimedOut, Cancelled, - ElectrumServersOffline, } #[derive(Debug, Deserialize)] From 55e7f7affa78e3a8443d6ed39be31aa2af9685fb Mon Sep 17 00:00:00 2001 From: Samuel Onoja Date: Thu, 13 Feb 2025 01:49:32 +0100 Subject: [PATCH 08/25] nit --- mm2src/mm2_main/src/lp_ordermatch.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/mm2src/mm2_main/src/lp_ordermatch.rs b/mm2src/mm2_main/src/lp_ordermatch.rs index 53fbc3028a..cd54d8aa49 100644 --- a/mm2src/mm2_main/src/lp_ordermatch.rs +++ b/mm2src/mm2_main/src/lp_ordermatch.rs @@ -131,7 +131,6 @@ const TRIE_STATE_HISTORY_TIMEOUT: u64 = 3; const TRIE_ORDER_HISTORY_TIMEOUT: u64 = 300; #[cfg(test)] const TRIE_ORDER_HISTORY_TIMEOUT: u64 = 3; -r pub type OrderbookP2PHandlerResult = Result<(), MmError>; From 5818720fe850cc91b5a1c98ee0c7ec10c097bc5a Mon Sep 17 00:00:00 2001 From: Samuel Onoja Date: Mon, 17 Feb 2025 12:04:10 +0100 Subject: [PATCH 09/25] update flag to is_offline --- mm2src/coins/lightning.rs | 1 - mm2src/coins/lp_coins.rs | 4 +-- mm2src/mm2_main/src/lp_ordermatch.rs | 23 +++++++++-------- mm2src/mm2_main/src/ordermatch_tests.rs | 34 ++++++++++++------------- 4 files changed, 31 insertions(+), 31 deletions(-) diff --git a/mm2src/coins/lightning.rs b/mm2src/coins/lightning.rs index ed85df9817..c94215be9b 100644 --- a/mm2src/coins/lightning.rs +++ b/mm2src/coins/lightning.rs @@ -283,7 +283,6 @@ impl LightningCoin { { return false; } - // Checking if funding_tx is some and not equal if filter.funding_tx.is_some() && channel_details.funding_tx != filter.funding_tx { return false; diff --git a/mm2src/coins/lp_coins.rs b/mm2src/coins/lp_coins.rs index 0f9d7cde76..cf744c9334 100644 --- a/mm2src/coins/lp_coins.rs +++ b/mm2src/coins/lp_coins.rs @@ -3632,7 +3632,7 @@ impl MmCoinEnum { fn is_platform_coin(&self) -> bool { self.ticker() == self.platform_ticker() } - pub fn utxo_in_electrum_mode_has_active_connection(&self) -> Option { + pub fn utxo_in_electrum_mode_is_offline(&self) -> Option { if let UtxoRpcClientEnum::Electrum(c) = match self { MmCoinEnum::UtxoCoin(c) => &c.as_ref().rpc_client, MmCoinEnum::QtumCoin(c) => &c.as_ref().rpc_client, @@ -3642,7 +3642,7 @@ impl MmCoinEnum { MmCoinEnum::SlpToken(c) => &c.as_ref().rpc_client, _ => return None, } { - return Some(!c.connection_manager.get_active_connections().is_empty()); + return Some(c.connection_manager.get_active_connections().is_empty()); } None diff --git a/mm2src/mm2_main/src/lp_ordermatch.rs b/mm2src/mm2_main/src/lp_ordermatch.rs index 2943ab1280..b06f92aa7d 100644 --- a/mm2src/mm2_main/src/lp_ordermatch.rs +++ b/mm2src/mm2_main/src/lp_ordermatch.rs @@ -1720,8 +1720,9 @@ pub struct MakerOrder { /// A custom priv key for more privacy to prevent linking orders of the same node between each other /// Commonly used with privacy coins (ARRR, ZCash, etc.) p2p_privkey: Option, - // Indicates whether the maker order is eligible for order matching. - is_active: bool, + // Indicates whether the maker order is offline hence, it's not eligible for order matching. + #[serde(default)] + is_offline: bool, #[serde(default, skip_serializing_if = "SwapVersion::is_legacy")] pub swap_version: SwapVersion, } @@ -1987,7 +1988,7 @@ impl<'a> MakerOrderBuilder<'a> { base_orderbook_ticker: self.base_orderbook_ticker, rel_orderbook_ticker: self.rel_orderbook_ticker, p2p_privkey, - is_active: true, + is_offline: false, swap_version: SwapVersion::from(self.swap_version), }) } @@ -2013,7 +2014,7 @@ impl<'a> MakerOrderBuilder<'a> { base_orderbook_ticker: None, rel_orderbook_ticker: None, p2p_privkey: None, - is_active: true, + is_offline: false, swap_version: SwapVersion::from(self.swap_version), } } @@ -2045,7 +2046,7 @@ impl MakerOrder { } fn match_with_request(&self, taker: &TakerRequest) -> OrderMatchResult { - if !self.is_active { + if self.is_offline { info!( "[{}] Maker order is inactive, skipping order match with taker", self.uuid @@ -2153,7 +2154,7 @@ impl From for MakerOrder { base_orderbook_ticker: taker_order.base_orderbook_ticker, rel_orderbook_ticker: taker_order.rel_orderbook_ticker, p2p_privkey: taker_order.p2p_privkey, - is_active: true, + is_offline: false, swap_version: taker_order.request.swap_version, }, // The "buy" taker order is recreated with reversed pair as Maker order is always considered as "sell" @@ -2177,7 +2178,7 @@ impl From for MakerOrder { base_orderbook_ticker: taker_order.rel_orderbook_ticker, rel_orderbook_ticker: taker_order.base_orderbook_ticker, p2p_privkey: taker_order.p2p_privkey, - is_active: true, + is_offline: false, swap_version: taker_order.request.swap_version, } }, @@ -3710,11 +3711,11 @@ async fn check_balance_for_maker_orders(ctx: MmArc, ordermatch_ctx: &OrdermatchC if let Ok(Some(coin)) = lp_coinfind(&ctx, &order.base).await { // Check if the base coin uses Electrum and update the order's active status only if it has changed - if let Some(is_active) = coin.utxo_in_electrum_mode_has_active_connection() { - if is_active != order.is_active { - order.is_active = is_active; + if let Some(is_offline) = coin.utxo_in_electrum_mode_is_offline() { + if is_offline != order.is_offline { + order.is_offline = is_offline; info!( - "[{}] Order status updated to `{is_active}` based on Electrum connection status", + "[{}] Order status updated to `{is_offline}` based on Electrum connection status", order.uuid ); } diff --git a/mm2src/mm2_main/src/ordermatch_tests.rs b/mm2src/mm2_main/src/ordermatch_tests.rs index b09184070f..55c600f7dc 100644 --- a/mm2src/mm2_main/src/ordermatch_tests.rs +++ b/mm2src/mm2_main/src/ordermatch_tests.rs @@ -39,7 +39,7 @@ fn test_match_maker_order_and_taker_request() { base_orderbook_ticker: None, rel_orderbook_ticker: None, p2p_privkey: None, - is_active: true, + is_offline: false, swap_version: SwapVersion::default(), }; @@ -80,7 +80,7 @@ fn test_match_maker_order_and_taker_request() { base_orderbook_ticker: None, rel_orderbook_ticker: None, p2p_privkey: None, - is_active: true, + is_offline: false, swap_version: SwapVersion::default(), }; @@ -121,7 +121,7 @@ fn test_match_maker_order_and_taker_request() { base_orderbook_ticker: None, rel_orderbook_ticker: None, p2p_privkey: None, - is_active: true, + is_offline: false, swap_version: SwapVersion::default(), }; @@ -162,7 +162,7 @@ fn test_match_maker_order_and_taker_request() { base_orderbook_ticker: None, rel_orderbook_ticker: None, p2p_privkey: None, - is_active: true, + is_offline: false, swap_version: SwapVersion::default(), }; @@ -203,7 +203,7 @@ fn test_match_maker_order_and_taker_request() { base_orderbook_ticker: None, rel_orderbook_ticker: None, p2p_privkey: None, - is_active: true, + is_offline: false, swap_version: SwapVersion::default(), }; @@ -244,7 +244,7 @@ fn test_match_maker_order_and_taker_request() { base_orderbook_ticker: None, rel_orderbook_ticker: None, p2p_privkey: None, - is_active: true, + is_offline: false, swap_version: SwapVersion::default(), }; @@ -287,7 +287,7 @@ fn test_match_maker_order_and_taker_request() { base_orderbook_ticker: None, rel_orderbook_ticker: None, p2p_privkey: None, - is_active: true, + is_offline: false, swap_version: SwapVersion::default(), }; let request = TakerRequest { @@ -330,7 +330,7 @@ fn test_match_maker_order_and_taker_request() { base_orderbook_ticker: None, rel_orderbook_ticker: None, p2p_privkey: None, - is_active: true, + is_offline: false, swap_version: SwapVersion::default(), }; let request = TakerRequest { @@ -404,7 +404,7 @@ fn test_maker_order_available_amount() { base_orderbook_ticker: None, rel_orderbook_ticker: None, p2p_privkey: None, - is_active: true, + is_offline: false, swap_version: SwapVersion::default(), }; maker.matches.insert(new_uuid(), MakerMatch { @@ -1025,7 +1025,7 @@ fn prepare_for_cancel_by(ctx: &MmArc) -> mpsc::Receiver { base_orderbook_ticker: None, rel_orderbook_ticker: None, p2p_privkey: None, - is_active: true, + is_offline: false, swap_version: SwapVersion::default(), }, None, @@ -1049,7 +1049,7 @@ fn prepare_for_cancel_by(ctx: &MmArc) -> mpsc::Receiver { base_orderbook_ticker: None, rel_orderbook_ticker: None, p2p_privkey: None, - is_active: true, + is_offline: false, swap_version: SwapVersion::default(), }, None, @@ -1073,7 +1073,7 @@ fn prepare_for_cancel_by(ctx: &MmArc) -> mpsc::Receiver { base_orderbook_ticker: None, rel_orderbook_ticker: None, p2p_privkey: None, - is_active: true, + is_offline: false, swap_version: SwapVersion::default(), }, None, @@ -1266,7 +1266,7 @@ fn test_maker_order_was_updated() { base_orderbook_ticker: None, rel_orderbook_ticker: None, p2p_privkey: None, - is_active: true, + is_offline: false, swap_version: SwapVersion::default(), }; let mut update_msg = MakerOrderUpdated::new(maker_order.uuid); @@ -3277,7 +3277,7 @@ fn test_maker_order_balance_loops() { base_orderbook_ticker: None, rel_orderbook_ticker: None, p2p_privkey: None, - is_active: true, + is_offline: false, swap_version: SwapVersion::default(), }; @@ -3298,7 +3298,7 @@ fn test_maker_order_balance_loops() { base_orderbook_ticker: None, rel_orderbook_ticker: None, p2p_privkey: None, - is_active: true, + is_offline: false, swap_version: SwapVersion::default(), }; @@ -3332,7 +3332,7 @@ fn test_maker_order_balance_loops() { base_orderbook_ticker: None, rel_orderbook_ticker: None, p2p_privkey: None, - is_active: true, + is_offline: false, swap_version: SwapVersion::default(), }; @@ -3371,7 +3371,7 @@ fn test_match_maker_order_and_taker_request_fails_with_not_active() { base_orderbook_ticker: None, rel_orderbook_ticker: None, p2p_privkey: None, - is_active: false, // maker order not active + is_offline: true, // maker order not active swap_version: SwapVersion::default(), }; From d58d2c0c1570f4e756a23c03d2f363e42a76b427 Mon Sep 17 00:00:00 2001 From: Samuel Onoja Date: Mon, 17 Feb 2025 12:16:50 +0100 Subject: [PATCH 10/25] fix cargo clippy --- mm2src/mm2_main/src/lp_ordermatch/my_orders_storage.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mm2src/mm2_main/src/lp_ordermatch/my_orders_storage.rs b/mm2src/mm2_main/src/lp_ordermatch/my_orders_storage.rs index f42c647e5f..2ce76d980b 100644 --- a/mm2src/mm2_main/src/lp_ordermatch/my_orders_storage.rs +++ b/mm2src/mm2_main/src/lp_ordermatch/my_orders_storage.rs @@ -725,7 +725,7 @@ mod tests { base_orderbook_ticker: None, rel_orderbook_ticker: None, p2p_privkey: None, - is_active: true, + is_offline: false, swap_version: SwapVersion::default(), } } From 029c45732134e2d8ad45b1e8cca9e9b154319e3d Mon Sep 17 00:00:00 2001 From: Samuel Onoja Date: Mon, 17 Feb 2025 14:34:13 +0100 Subject: [PATCH 11/25] update order log info for offline orders --- mm2src/mm2_main/src/lp_ordermatch.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mm2src/mm2_main/src/lp_ordermatch.rs b/mm2src/mm2_main/src/lp_ordermatch.rs index b06f92aa7d..0136a7f424 100644 --- a/mm2src/mm2_main/src/lp_ordermatch.rs +++ b/mm2src/mm2_main/src/lp_ordermatch.rs @@ -3715,7 +3715,7 @@ async fn check_balance_for_maker_orders(ctx: MmArc, ordermatch_ctx: &OrdermatchC if is_offline != order.is_offline { order.is_offline = is_offline; info!( - "[{}] Order status updated to `{is_offline}` based on Electrum connection status", + "[{}] Order offline status updated to `{is_offline}` based on Electrum connection status", order.uuid ); } From b7ef6c3defbc3183d2d72eb3c1ef8d56c33086d4 Mon Sep 17 00:00:00 2001 From: Samuel Onoja Date: Wed, 19 Feb 2025 10:57:25 +0100 Subject: [PATCH 12/25] use enum for MakerOrder status --- mm2src/mm2_main/src/lp_ordermatch.rs | 33 +++++++++++++----- .../src/lp_ordermatch/my_orders_storage.rs | 3 +- mm2src/mm2_main/src/ordermatch_tests.rs | 34 +++++++++---------- 3 files changed, 43 insertions(+), 27 deletions(-) diff --git a/mm2src/mm2_main/src/lp_ordermatch.rs b/mm2src/mm2_main/src/lp_ordermatch.rs index 0136a7f424..9fe20fc701 100644 --- a/mm2src/mm2_main/src/lp_ordermatch.rs +++ b/mm2src/mm2_main/src/lp_ordermatch.rs @@ -1691,6 +1691,16 @@ impl TakerOrder { fn p2p_keypair(&self) -> Option<&KeyPair> { self.p2p_privkey.as_ref().map(|key| key.key_pair()) } } +#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] +enum MakerOrderStatus { + Offline, + Online, +} + +impl Default for MakerOrderStatus { + fn default() -> Self { Self::Online } +} + #[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] /// Market maker order /// The "action" is missing here because it's easier to always consider maker order as "sell" @@ -1722,7 +1732,7 @@ pub struct MakerOrder { p2p_privkey: Option, // Indicates whether the maker order is offline hence, it's not eligible for order matching. #[serde(default)] - is_offline: bool, + status: MakerOrderStatus, #[serde(default, skip_serializing_if = "SwapVersion::is_legacy")] pub swap_version: SwapVersion, } @@ -1988,7 +1998,7 @@ impl<'a> MakerOrderBuilder<'a> { base_orderbook_ticker: self.base_orderbook_ticker, rel_orderbook_ticker: self.rel_orderbook_ticker, p2p_privkey, - is_offline: false, + status: MakerOrderStatus::default(), swap_version: SwapVersion::from(self.swap_version), }) } @@ -2014,7 +2024,7 @@ impl<'a> MakerOrderBuilder<'a> { base_orderbook_ticker: None, rel_orderbook_ticker: None, p2p_privkey: None, - is_offline: false, + status: MakerOrderStatus::default(), swap_version: SwapVersion::from(self.swap_version), } } @@ -2046,7 +2056,7 @@ impl MakerOrder { } fn match_with_request(&self, taker: &TakerRequest) -> OrderMatchResult { - if self.is_offline { + if self.status == MakerOrderStatus::Offline { info!( "[{}] Maker order is inactive, skipping order match with taker", self.uuid @@ -2154,7 +2164,7 @@ impl From for MakerOrder { base_orderbook_ticker: taker_order.base_orderbook_ticker, rel_orderbook_ticker: taker_order.rel_orderbook_ticker, p2p_privkey: taker_order.p2p_privkey, - is_offline: false, + status: MakerOrderStatus::default(), swap_version: taker_order.request.swap_version, }, // The "buy" taker order is recreated with reversed pair as Maker order is always considered as "sell" @@ -2178,7 +2188,7 @@ impl From for MakerOrder { base_orderbook_ticker: taker_order.rel_orderbook_ticker, rel_orderbook_ticker: taker_order.base_orderbook_ticker, p2p_privkey: taker_order.p2p_privkey, - is_offline: false, + status: MakerOrderStatus::default(), swap_version: taker_order.request.swap_version, } }, @@ -3712,12 +3722,17 @@ async fn check_balance_for_maker_orders(ctx: MmArc, ordermatch_ctx: &OrdermatchC if let Ok(Some(coin)) = lp_coinfind(&ctx, &order.base).await { // Check if the base coin uses Electrum and update the order's active status only if it has changed if let Some(is_offline) = coin.utxo_in_electrum_mode_is_offline() { - if is_offline != order.is_offline { - order.is_offline = is_offline; + let status = if is_offline { + MakerOrderStatus::Offline + } else { + MakerOrderStatus::Online + }; + if status != order.status { info!( - "[{}] Order offline status updated to `{is_offline}` based on Electrum connection status", + "[{}] Order status updated to `{status:?}` based on Electrum connection status", order.uuid ); + order.status = status; } } }; diff --git a/mm2src/mm2_main/src/lp_ordermatch/my_orders_storage.rs b/mm2src/mm2_main/src/lp_ordermatch/my_orders_storage.rs index 2ce76d980b..a1612a33e4 100644 --- a/mm2src/mm2_main/src/lp_ordermatch/my_orders_storage.rs +++ b/mm2src/mm2_main/src/lp_ordermatch/my_orders_storage.rs @@ -1,5 +1,6 @@ use super::{MakerOrder, MakerOrderCancellationReason, MyOrdersFilter, Order, RecentOrdersSelectResult, TakerOrder, TakerOrderCancellationReason}; +use crate::lp_ordermatch::MakerOrderStatus; use async_trait::async_trait; use common::log::LogOnError; use common::{BoxFut, PagingOptions}; @@ -725,7 +726,7 @@ mod tests { base_orderbook_ticker: None, rel_orderbook_ticker: None, p2p_privkey: None, - is_offline: false, + status: MakerOrderStatus::default(), swap_version: SwapVersion::default(), } } diff --git a/mm2src/mm2_main/src/ordermatch_tests.rs b/mm2src/mm2_main/src/ordermatch_tests.rs index 55c600f7dc..4e6ff5d211 100644 --- a/mm2src/mm2_main/src/ordermatch_tests.rs +++ b/mm2src/mm2_main/src/ordermatch_tests.rs @@ -39,7 +39,7 @@ fn test_match_maker_order_and_taker_request() { base_orderbook_ticker: None, rel_orderbook_ticker: None, p2p_privkey: None, - is_offline: false, + status: MakerOrderStatus::default(), swap_version: SwapVersion::default(), }; @@ -80,7 +80,7 @@ fn test_match_maker_order_and_taker_request() { base_orderbook_ticker: None, rel_orderbook_ticker: None, p2p_privkey: None, - is_offline: false, + status: MakerOrderStatus::default(), swap_version: SwapVersion::default(), }; @@ -121,7 +121,7 @@ fn test_match_maker_order_and_taker_request() { base_orderbook_ticker: None, rel_orderbook_ticker: None, p2p_privkey: None, - is_offline: false, + status: MakerOrderStatus::default(), swap_version: SwapVersion::default(), }; @@ -162,7 +162,7 @@ fn test_match_maker_order_and_taker_request() { base_orderbook_ticker: None, rel_orderbook_ticker: None, p2p_privkey: None, - is_offline: false, + status: MakerOrderStatus::default(), swap_version: SwapVersion::default(), }; @@ -203,7 +203,7 @@ fn test_match_maker_order_and_taker_request() { base_orderbook_ticker: None, rel_orderbook_ticker: None, p2p_privkey: None, - is_offline: false, + status: MakerOrderStatus::default(), swap_version: SwapVersion::default(), }; @@ -244,7 +244,7 @@ fn test_match_maker_order_and_taker_request() { base_orderbook_ticker: None, rel_orderbook_ticker: None, p2p_privkey: None, - is_offline: false, + status: MakerOrderStatus::default(), swap_version: SwapVersion::default(), }; @@ -287,7 +287,7 @@ fn test_match_maker_order_and_taker_request() { base_orderbook_ticker: None, rel_orderbook_ticker: None, p2p_privkey: None, - is_offline: false, + status: MakerOrderStatus::default(), swap_version: SwapVersion::default(), }; let request = TakerRequest { @@ -330,7 +330,7 @@ fn test_match_maker_order_and_taker_request() { base_orderbook_ticker: None, rel_orderbook_ticker: None, p2p_privkey: None, - is_offline: false, + status: MakerOrderStatus::default(), swap_version: SwapVersion::default(), }; let request = TakerRequest { @@ -404,7 +404,7 @@ fn test_maker_order_available_amount() { base_orderbook_ticker: None, rel_orderbook_ticker: None, p2p_privkey: None, - is_offline: false, + status: MakerOrderStatus::default(), swap_version: SwapVersion::default(), }; maker.matches.insert(new_uuid(), MakerMatch { @@ -1025,7 +1025,7 @@ fn prepare_for_cancel_by(ctx: &MmArc) -> mpsc::Receiver { base_orderbook_ticker: None, rel_orderbook_ticker: None, p2p_privkey: None, - is_offline: false, + status: MakerOrderStatus::default(), swap_version: SwapVersion::default(), }, None, @@ -1049,7 +1049,7 @@ fn prepare_for_cancel_by(ctx: &MmArc) -> mpsc::Receiver { base_orderbook_ticker: None, rel_orderbook_ticker: None, p2p_privkey: None, - is_offline: false, + status: MakerOrderStatus::default(), swap_version: SwapVersion::default(), }, None, @@ -1073,7 +1073,7 @@ fn prepare_for_cancel_by(ctx: &MmArc) -> mpsc::Receiver { base_orderbook_ticker: None, rel_orderbook_ticker: None, p2p_privkey: None, - is_offline: false, + status: MakerOrderStatus::default(), swap_version: SwapVersion::default(), }, None, @@ -1266,7 +1266,7 @@ fn test_maker_order_was_updated() { base_orderbook_ticker: None, rel_orderbook_ticker: None, p2p_privkey: None, - is_offline: false, + status: MakerOrderStatus::default(), swap_version: SwapVersion::default(), }; let mut update_msg = MakerOrderUpdated::new(maker_order.uuid); @@ -3277,7 +3277,7 @@ fn test_maker_order_balance_loops() { base_orderbook_ticker: None, rel_orderbook_ticker: None, p2p_privkey: None, - is_offline: false, + status: MakerOrderStatus::default(), swap_version: SwapVersion::default(), }; @@ -3298,7 +3298,7 @@ fn test_maker_order_balance_loops() { base_orderbook_ticker: None, rel_orderbook_ticker: None, p2p_privkey: None, - is_offline: false, + status: MakerOrderStatus::default(), swap_version: SwapVersion::default(), }; @@ -3332,7 +3332,7 @@ fn test_maker_order_balance_loops() { base_orderbook_ticker: None, rel_orderbook_ticker: None, p2p_privkey: None, - is_offline: false, + status: MakerOrderStatus::default(), swap_version: SwapVersion::default(), }; @@ -3371,7 +3371,7 @@ fn test_match_maker_order_and_taker_request_fails_with_not_active() { base_orderbook_ticker: None, rel_orderbook_ticker: None, p2p_privkey: None, - is_offline: true, // maker order not active + status: MakerOrderStatus::Offline, // maker order not active swap_version: SwapVersion::default(), }; From e18f60b3190cbdc17986b89dbae883bc56f8e017 Mon Sep 17 00:00:00 2001 From: Samuel Onoja Date: Wed, 19 Feb 2025 12:42:35 +0100 Subject: [PATCH 13/25] fix clippy warnings --- mm2src/mm2_main/src/lp_ordermatch/my_orders_storage.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mm2src/mm2_main/src/lp_ordermatch/my_orders_storage.rs b/mm2src/mm2_main/src/lp_ordermatch/my_orders_storage.rs index a1612a33e4..f5e12f8e59 100644 --- a/mm2src/mm2_main/src/lp_ordermatch/my_orders_storage.rs +++ b/mm2src/mm2_main/src/lp_ordermatch/my_orders_storage.rs @@ -1,6 +1,5 @@ use super::{MakerOrder, MakerOrderCancellationReason, MyOrdersFilter, Order, RecentOrdersSelectResult, TakerOrder, TakerOrderCancellationReason}; -use crate::lp_ordermatch::MakerOrderStatus; use async_trait::async_trait; use common::log::LogOnError; use common::{BoxFut, PagingOptions}; @@ -13,6 +12,8 @@ use uuid::Uuid; pub type MyOrdersResult = Result>; +#[cfg(target_arch = "wasm32")] +use crate::lp_ordermatch::MakerOrderStatus; #[cfg(target_arch = "wasm32")] pub use wasm_impl::MyOrdersStorage; From 44ce1a93910a66d9251d4534698490310f52570c Mon Sep 17 00:00:00 2001 From: Samuel Onoja Date: Wed, 19 Feb 2025 13:56:42 +0100 Subject: [PATCH 14/25] rename MakerOrderStatus enum variants --- mm2src/mm2_main/src/lp_ordermatch.rs | 20 +++++------ .../src/lp_ordermatch/my_orders_storage.rs | 2 +- mm2src/mm2_main/src/ordermatch_tests.rs | 34 +++++++++---------- 3 files changed, 28 insertions(+), 28 deletions(-) diff --git a/mm2src/mm2_main/src/lp_ordermatch.rs b/mm2src/mm2_main/src/lp_ordermatch.rs index 9fe20fc701..14a3c0808e 100644 --- a/mm2src/mm2_main/src/lp_ordermatch.rs +++ b/mm2src/mm2_main/src/lp_ordermatch.rs @@ -1693,12 +1693,12 @@ impl TakerOrder { #[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] enum MakerOrderStatus { - Offline, - Online, + RpcClientsUnavailable, + Active, } impl Default for MakerOrderStatus { - fn default() -> Self { Self::Online } + fn default() -> Self { Self::Active } } #[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] @@ -1998,7 +1998,7 @@ impl<'a> MakerOrderBuilder<'a> { base_orderbook_ticker: self.base_orderbook_ticker, rel_orderbook_ticker: self.rel_orderbook_ticker, p2p_privkey, - status: MakerOrderStatus::default(), + status: MakerOrderStatus::Active, swap_version: SwapVersion::from(self.swap_version), }) } @@ -2024,7 +2024,7 @@ impl<'a> MakerOrderBuilder<'a> { base_orderbook_ticker: None, rel_orderbook_ticker: None, p2p_privkey: None, - status: MakerOrderStatus::default(), + status: MakerOrderStatus::Active, swap_version: SwapVersion::from(self.swap_version), } } @@ -2056,7 +2056,7 @@ impl MakerOrder { } fn match_with_request(&self, taker: &TakerRequest) -> OrderMatchResult { - if self.status == MakerOrderStatus::Offline { + if self.status == MakerOrderStatus::RpcClientsUnavailable { info!( "[{}] Maker order is inactive, skipping order match with taker", self.uuid @@ -2164,7 +2164,7 @@ impl From for MakerOrder { base_orderbook_ticker: taker_order.base_orderbook_ticker, rel_orderbook_ticker: taker_order.rel_orderbook_ticker, p2p_privkey: taker_order.p2p_privkey, - status: MakerOrderStatus::default(), + status: MakerOrderStatus::Active, swap_version: taker_order.request.swap_version, }, // The "buy" taker order is recreated with reversed pair as Maker order is always considered as "sell" @@ -2188,7 +2188,7 @@ impl From for MakerOrder { base_orderbook_ticker: taker_order.rel_orderbook_ticker, rel_orderbook_ticker: taker_order.base_orderbook_ticker, p2p_privkey: taker_order.p2p_privkey, - status: MakerOrderStatus::default(), + status: MakerOrderStatus::Active, swap_version: taker_order.request.swap_version, } }, @@ -3723,9 +3723,9 @@ async fn check_balance_for_maker_orders(ctx: MmArc, ordermatch_ctx: &OrdermatchC // Check if the base coin uses Electrum and update the order's active status only if it has changed if let Some(is_offline) = coin.utxo_in_electrum_mode_is_offline() { let status = if is_offline { - MakerOrderStatus::Offline + MakerOrderStatus::RpcClientsUnavailable } else { - MakerOrderStatus::Online + MakerOrderStatus::Active }; if status != order.status { info!( diff --git a/mm2src/mm2_main/src/lp_ordermatch/my_orders_storage.rs b/mm2src/mm2_main/src/lp_ordermatch/my_orders_storage.rs index f5e12f8e59..8941820c08 100644 --- a/mm2src/mm2_main/src/lp_ordermatch/my_orders_storage.rs +++ b/mm2src/mm2_main/src/lp_ordermatch/my_orders_storage.rs @@ -727,7 +727,7 @@ mod tests { base_orderbook_ticker: None, rel_orderbook_ticker: None, p2p_privkey: None, - status: MakerOrderStatus::default(), + status: MakerOrderStatus::Active, swap_version: SwapVersion::default(), } } diff --git a/mm2src/mm2_main/src/ordermatch_tests.rs b/mm2src/mm2_main/src/ordermatch_tests.rs index 4e6ff5d211..0edd47de5e 100644 --- a/mm2src/mm2_main/src/ordermatch_tests.rs +++ b/mm2src/mm2_main/src/ordermatch_tests.rs @@ -39,7 +39,7 @@ fn test_match_maker_order_and_taker_request() { base_orderbook_ticker: None, rel_orderbook_ticker: None, p2p_privkey: None, - status: MakerOrderStatus::default(), + status: MakerOrderStatus::Active, swap_version: SwapVersion::default(), }; @@ -80,7 +80,7 @@ fn test_match_maker_order_and_taker_request() { base_orderbook_ticker: None, rel_orderbook_ticker: None, p2p_privkey: None, - status: MakerOrderStatus::default(), + status: MakerOrderStatus::Active, swap_version: SwapVersion::default(), }; @@ -121,7 +121,7 @@ fn test_match_maker_order_and_taker_request() { base_orderbook_ticker: None, rel_orderbook_ticker: None, p2p_privkey: None, - status: MakerOrderStatus::default(), + status: MakerOrderStatus::Active, swap_version: SwapVersion::default(), }; @@ -162,7 +162,7 @@ fn test_match_maker_order_and_taker_request() { base_orderbook_ticker: None, rel_orderbook_ticker: None, p2p_privkey: None, - status: MakerOrderStatus::default(), + status: MakerOrderStatus::Active, swap_version: SwapVersion::default(), }; @@ -203,7 +203,7 @@ fn test_match_maker_order_and_taker_request() { base_orderbook_ticker: None, rel_orderbook_ticker: None, p2p_privkey: None, - status: MakerOrderStatus::default(), + status: MakerOrderStatus::Active, swap_version: SwapVersion::default(), }; @@ -244,7 +244,7 @@ fn test_match_maker_order_and_taker_request() { base_orderbook_ticker: None, rel_orderbook_ticker: None, p2p_privkey: None, - status: MakerOrderStatus::default(), + status: MakerOrderStatus::Active, swap_version: SwapVersion::default(), }; @@ -287,7 +287,7 @@ fn test_match_maker_order_and_taker_request() { base_orderbook_ticker: None, rel_orderbook_ticker: None, p2p_privkey: None, - status: MakerOrderStatus::default(), + status: MakerOrderStatus::Active, swap_version: SwapVersion::default(), }; let request = TakerRequest { @@ -330,7 +330,7 @@ fn test_match_maker_order_and_taker_request() { base_orderbook_ticker: None, rel_orderbook_ticker: None, p2p_privkey: None, - status: MakerOrderStatus::default(), + status: MakerOrderStatus::Active, swap_version: SwapVersion::default(), }; let request = TakerRequest { @@ -404,7 +404,7 @@ fn test_maker_order_available_amount() { base_orderbook_ticker: None, rel_orderbook_ticker: None, p2p_privkey: None, - status: MakerOrderStatus::default(), + status: MakerOrderStatus::Active, swap_version: SwapVersion::default(), }; maker.matches.insert(new_uuid(), MakerMatch { @@ -1025,7 +1025,7 @@ fn prepare_for_cancel_by(ctx: &MmArc) -> mpsc::Receiver { base_orderbook_ticker: None, rel_orderbook_ticker: None, p2p_privkey: None, - status: MakerOrderStatus::default(), + status: MakerOrderStatus::Active, swap_version: SwapVersion::default(), }, None, @@ -1049,7 +1049,7 @@ fn prepare_for_cancel_by(ctx: &MmArc) -> mpsc::Receiver { base_orderbook_ticker: None, rel_orderbook_ticker: None, p2p_privkey: None, - status: MakerOrderStatus::default(), + status: MakerOrderStatus::Active, swap_version: SwapVersion::default(), }, None, @@ -1073,7 +1073,7 @@ fn prepare_for_cancel_by(ctx: &MmArc) -> mpsc::Receiver { base_orderbook_ticker: None, rel_orderbook_ticker: None, p2p_privkey: None, - status: MakerOrderStatus::default(), + status: MakerOrderStatus::Active, swap_version: SwapVersion::default(), }, None, @@ -1266,7 +1266,7 @@ fn test_maker_order_was_updated() { base_orderbook_ticker: None, rel_orderbook_ticker: None, p2p_privkey: None, - status: MakerOrderStatus::default(), + status: MakerOrderStatus::Active, swap_version: SwapVersion::default(), }; let mut update_msg = MakerOrderUpdated::new(maker_order.uuid); @@ -3277,7 +3277,7 @@ fn test_maker_order_balance_loops() { base_orderbook_ticker: None, rel_orderbook_ticker: None, p2p_privkey: None, - status: MakerOrderStatus::default(), + status: MakerOrderStatus::Active, swap_version: SwapVersion::default(), }; @@ -3298,7 +3298,7 @@ fn test_maker_order_balance_loops() { base_orderbook_ticker: None, rel_orderbook_ticker: None, p2p_privkey: None, - status: MakerOrderStatus::default(), + status: MakerOrderStatus::Active, swap_version: SwapVersion::default(), }; @@ -3332,7 +3332,7 @@ fn test_maker_order_balance_loops() { base_orderbook_ticker: None, rel_orderbook_ticker: None, p2p_privkey: None, - status: MakerOrderStatus::default(), + status: MakerOrderStatus::Active, swap_version: SwapVersion::default(), }; @@ -3371,7 +3371,7 @@ fn test_match_maker_order_and_taker_request_fails_with_not_active() { base_orderbook_ticker: None, rel_orderbook_ticker: None, p2p_privkey: None, - status: MakerOrderStatus::Offline, // maker order not active + status: MakerOrderStatus::RpcClientsUnavailable, // maker order not active swap_version: SwapVersion::default(), }; From 94c5111ecfa7683393f2cb371ffa38b4d8ebadfc Mon Sep 17 00:00:00 2001 From: Samuel Onoja Date: Thu, 20 Feb 2025 00:29:05 +0100 Subject: [PATCH 15/25] update docs --- mm2src/mm2_main/src/lp_ordermatch.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/mm2src/mm2_main/src/lp_ordermatch.rs b/mm2src/mm2_main/src/lp_ordermatch.rs index 14a3c0808e..221f0ef3f1 100644 --- a/mm2src/mm2_main/src/lp_ordermatch.rs +++ b/mm2src/mm2_main/src/lp_ordermatch.rs @@ -1730,7 +1730,9 @@ pub struct MakerOrder { /// A custom priv key for more privacy to prevent linking orders of the same node between each other /// Commonly used with privacy coins (ARRR, ZCash, etc.) p2p_privkey: Option, - // Indicates whether the maker order is offline hence, it's not eligible for order matching. + /// Indicates the current status of the maker order. When the status is `RpcClientsUnavailable`, + /// the order is not eligible for matching due to RPC client connectivity issues. `Active` status + /// means the order is available for matching. #[serde(default)] status: MakerOrderStatus, #[serde(default, skip_serializing_if = "SwapVersion::is_legacy")] From eedc9b951d520bc224b558d00b5f940af083520f Mon Sep 17 00:00:00 2001 From: Samuel Onoja Date: Mon, 3 Mar 2025 01:07:47 +0100 Subject: [PATCH 16/25] cancel order, refactor save_my_t/maker_order --- mm2src/mm2_main/src/lp_ordermatch.rs | 133 ++++++------------ .../src/lp_ordermatch/my_orders_storage.rs | 126 +++++++---------- mm2src/mm2_main/src/ordermatch_tests.rs | 86 +++-------- 3 files changed, 113 insertions(+), 232 deletions(-) diff --git a/mm2src/mm2_main/src/lp_ordermatch.rs b/mm2src/mm2_main/src/lp_ordermatch.rs index 221f0ef3f1..8f1a87bf11 100644 --- a/mm2src/mm2_main/src/lp_ordermatch.rs +++ b/mm2src/mm2_main/src/lp_ordermatch.rs @@ -1151,9 +1151,7 @@ impl BalanceTradeFeeUpdatedHandler for BalanceUpdateOrdermatchHandler { order.clone(), MakerOrderCancellationReason::InsufficientBalance, ) - .compat() - .await - .ok(); + .await; continue; } } @@ -1691,16 +1689,6 @@ impl TakerOrder { fn p2p_keypair(&self) -> Option<&KeyPair> { self.p2p_privkey.as_ref().map(|key| key.key_pair()) } } -#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] -enum MakerOrderStatus { - RpcClientsUnavailable, - Active, -} - -impl Default for MakerOrderStatus { - fn default() -> Self { Self::Active } -} - #[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] /// Market maker order /// The "action" is missing here because it's easier to always consider maker order as "sell" @@ -1730,11 +1718,6 @@ pub struct MakerOrder { /// A custom priv key for more privacy to prevent linking orders of the same node between each other /// Commonly used with privacy coins (ARRR, ZCash, etc.) p2p_privkey: Option, - /// Indicates the current status of the maker order. When the status is `RpcClientsUnavailable`, - /// the order is not eligible for matching due to RPC client connectivity issues. `Active` status - /// means the order is available for matching. - #[serde(default)] - status: MakerOrderStatus, #[serde(default, skip_serializing_if = "SwapVersion::is_legacy")] pub swap_version: SwapVersion, } @@ -2000,7 +1983,6 @@ impl<'a> MakerOrderBuilder<'a> { base_orderbook_ticker: self.base_orderbook_ticker, rel_orderbook_ticker: self.rel_orderbook_ticker, p2p_privkey, - status: MakerOrderStatus::Active, swap_version: SwapVersion::from(self.swap_version), }) } @@ -2026,7 +2008,6 @@ impl<'a> MakerOrderBuilder<'a> { base_orderbook_ticker: None, rel_orderbook_ticker: None, p2p_privkey: None, - status: MakerOrderStatus::Active, swap_version: SwapVersion::from(self.swap_version), } } @@ -2058,14 +2039,6 @@ impl MakerOrder { } fn match_with_request(&self, taker: &TakerRequest) -> OrderMatchResult { - if self.status == MakerOrderStatus::RpcClientsUnavailable { - info!( - "[{}] Maker order is inactive, skipping order match with taker", - self.uuid - ); - return OrderMatchResult::NotMatched; - } - let taker_base_amount = taker.get_base_amount(); let taker_rel_amount = taker.get_rel_amount(); @@ -2166,7 +2139,6 @@ impl From for MakerOrder { base_orderbook_ticker: taker_order.base_orderbook_ticker, rel_orderbook_ticker: taker_order.rel_orderbook_ticker, p2p_privkey: taker_order.p2p_privkey, - status: MakerOrderStatus::Active, swap_version: taker_order.request.swap_version, }, // The "buy" taker order is recreated with reversed pair as Maker order is always considered as "sell" @@ -2190,7 +2162,6 @@ impl From for MakerOrder { base_orderbook_ticker: taker_order.rel_orderbook_ticker, rel_orderbook_ticker: taker_order.base_orderbook_ticker, p2p_privkey: taker_order.p2p_privkey, - status: MakerOrderStatus::Active, swap_version: taker_order.request.swap_version, } }, @@ -3616,9 +3587,7 @@ pub async fn lp_ordermatch_loop(ctx: MmArc) { order.clone(), MakerOrderCancellationReason::InsufficientBalance, ) - .compat() - .await - .ok(); + .await; } } } @@ -3663,19 +3632,13 @@ async fn handle_timed_out_taker_orders(ctx: MmArc, ordermatch_ctx: &OrdermatchCo } if !order.matches.is_empty() || order.order_type != OrderType::GoodTillCancelled { - delete_my_taker_order(ctx.clone(), order, TakerOrderCancellationReason::TimedOut) - .compat() - .await - .ok(); + delete_my_taker_order(ctx.clone(), order, TakerOrderCancellationReason::TimedOut).await; continue; } // transform the timed out taker order to maker - delete_my_taker_order(ctx.clone(), order.clone(), TakerOrderCancellationReason::ToMaker) - .compat() - .await - .ok(); + delete_my_taker_order(ctx.clone(), order.clone(), TakerOrderCancellationReason::ToMaker).await; let maker_order: MakerOrder = order.into(); ordermatch_ctx .maker_orders_ctx @@ -3714,7 +3677,7 @@ async fn check_balance_for_maker_orders(ctx: MmArc, ordermatch_ctx: &OrdermatchC let my_maker_orders = ordermatch_ctx.maker_orders_ctx.lock().orders.clone(); for (uuid, order) in my_maker_orders { - let mut order = order.lock().await; + let order = order.lock().await; if order.available_amount() >= order.min_base_vol || order.has_ongoing_matches() { if order.has_ongoing_matches() { @@ -3722,22 +3685,32 @@ async fn check_balance_for_maker_orders(ctx: MmArc, ordermatch_ctx: &OrdermatchC } if let Ok(Some(coin)) = lp_coinfind(&ctx, &order.base).await { - // Check if the base coin uses Electrum and update the order's active status only if it has changed - if let Some(is_offline) = coin.utxo_in_electrum_mode_is_offline() { - let status = if is_offline { - MakerOrderStatus::RpcClientsUnavailable - } else { - MakerOrderStatus::Active - }; - if status != order.status { - info!( - "[{}] Order status updated to `{status:?}` based on Electrum connection status", - order.uuid - ); - order.status = status; - } + // Check if the base coin uses Electrum and cancel order if it has no active electrums connection. + let Some(true) = coin.utxo_in_electrum_mode_is_offline() else { + continue; + }; + + if !order.is_cancellable() { + info!( + "Down electrum: Unable to cancel maker_order:[{}] because it's not cancellable", + order.uuid + ); + continue; } - }; + + let removed_order_mutex = ordermatch_ctx.maker_orders_ctx.lock().remove_order(&order.uuid); + if removed_order_mutex.is_some() { + maker_order_cancelled_p2p_notify(&ctx, &order); + delete_my_maker_order( + ctx.clone(), + order.clone(), + MakerOrderCancellationReason::NoActiveElectrumConnection, + ) + .await; + } + + info!("[{}] Maker Order cancelled due to no active electrums.", order.uuid); + } continue; } @@ -3751,10 +3724,7 @@ async fn check_balance_for_maker_orders(ctx: MmArc, ordermatch_ctx: &OrdermatchC // This checks that the order hasn't been removed by another process if removed_order_mutex.is_some() { maker_order_cancelled_p2p_notify(&ctx, &order); - delete_my_maker_order(ctx.clone(), order.clone(), reason) - .compat() - .await - .ok(); + delete_my_maker_order(ctx.clone(), order.clone(), reason).await; } } } @@ -3948,10 +3918,7 @@ async fn process_maker_connected(ctx: MmArc, from_pubkey: PublicKey, connected: ); // remove the matched order immediately let order = my_order_entry.remove(); - delete_my_taker_order(ctx, order, TakerOrderCancellationReason::Fulfilled) - .compat() - .await - .ok(); + delete_my_taker_order(ctx, order, TakerOrderCancellationReason::Fulfilled).await; } async fn process_taker_request(ctx: MmArc, from_pubkey: H256Json, taker_request: TakerRequest) { @@ -5096,10 +5063,7 @@ async fn cancel_previous_maker_orders( // This checks that the uuid, &order.base hasn't been removed by another process if removed_order_mutex.is_some() { maker_order_cancelled_p2p_notify(ctx, &order); - delete_my_maker_order(ctx.clone(), order.clone(), MakerOrderCancellationReason::Cancelled) - .compat() - .await - .ok(); + delete_my_maker_order(ctx.clone(), order.clone(), MakerOrderCancellationReason::Cancelled).await; } } } @@ -5311,6 +5275,7 @@ pub enum MakerOrderCancellationReason { Fulfilled, InsufficientBalance, Cancelled, + NoActiveElectrumConnection, } #[derive(Display)] @@ -5499,10 +5464,7 @@ pub async fn cancel_order(ctx: MmArc, req: CancelOrderReq) -> Result Result Result> // This checks that the order hasn't been removed by another process if removed_order_mutex.is_some() { maker_order_cancelled_p2p_notify(&ctx, &order); - delete_my_maker_order(ctx, order.clone(), MakerOrderCancellationReason::Cancelled) - .compat() - .await - .ok(); + delete_my_maker_order(ctx, order.clone(), MakerOrderCancellationReason::Cancelled).await; } let res = json!({ "result": "success" @@ -5564,10 +5520,7 @@ pub async fn cancel_order_rpc(ctx: MmArc, req: Json) -> Result> return ERR!("Order {} is being matched now, can't cancel", req.uuid); } let order = order.remove(); - delete_my_taker_order(ctx, order, TakerOrderCancellationReason::Cancelled) - .compat() - .await - .ok(); + delete_my_taker_order(ctx, order, TakerOrderCancellationReason::Cancelled).await; let res = json!({ "result": "success" }); @@ -5897,16 +5850,10 @@ pub async fn cancel_orders_by(ctx: &MmArc, cancel_by: CancelBy) -> Result<(Vec = Result>; -#[cfg(target_arch = "wasm32")] -use crate::lp_ordermatch::MakerOrderStatus; #[cfg(target_arch = "wasm32")] pub use wasm_impl::MyOrdersStorage; @@ -74,71 +71,63 @@ pub async fn save_maker_order_on_update(ctx: MmArc, order: &MakerOrder) -> MyOrd } #[cfg_attr(test, mockable)] -pub fn delete_my_taker_order(ctx: MmArc, order: TakerOrder, reason: TakerOrderCancellationReason) -> BoxFut<(), ()> { - let fut = async move { - let uuid = order.request.uuid; - let save_in_history = order.save_in_history; +pub async fn delete_my_taker_order(ctx: MmArc, order: TakerOrder, reason: TakerOrderCancellationReason) { + let uuid = order.request.uuid; + let save_in_history = order.save_in_history; + + let storage = MyOrdersStorage::new(ctx); + storage + .delete_active_taker_order(uuid) + .await + .error_log_with_msg("!delete_active_taker_order"); + + match reason { + TakerOrderCancellationReason::ToMaker => (), + _ => { + if save_in_history { + storage + .save_order_in_history(&Order::Taker(order)) + .await + .error_log_with_msg("!save_order_in_history"); + } + }, + } - let storage = MyOrdersStorage::new(ctx); + if save_in_history { storage - .delete_active_taker_order(uuid) + .update_order_status_in_filtering_history(uuid, reason.to_string()) .await - .error_log_with_msg("!delete_active_taker_order"); - - match reason { - TakerOrderCancellationReason::ToMaker => (), - _ => { - if save_in_history { - storage - .save_order_in_history(&Order::Taker(order)) - .await - .error_log_with_msg("!save_order_in_history"); - } - }, - } - - if save_in_history { - storage - .update_order_status_in_filtering_history(uuid, reason.to_string()) - .await - .error_log_with_msg("!update_order_status_in_filtering_history"); - } - Ok(()) - }; - Box::new(fut.boxed().compat()) + .error_log_with_msg("!update_order_status_in_filtering_history"); + } } #[cfg_attr(test, mockable)] -pub fn delete_my_maker_order(ctx: MmArc, order: MakerOrder, reason: MakerOrderCancellationReason) -> BoxFut<(), ()> { - let fut = async move { - let mut order_to_save = order; - let uuid = order_to_save.uuid; - let save_in_history = order_to_save.save_in_history; - - let storage = MyOrdersStorage::new(ctx); - if order_to_save.was_updated() { - if let Ok(order_from_file) = storage.load_active_maker_order(order_to_save.uuid).await { - order_to_save = order_from_file; - } +pub async fn delete_my_maker_order(ctx: MmArc, order: MakerOrder, reason: MakerOrderCancellationReason) { + let mut order_to_save = order; + let uuid = order_to_save.uuid; + let save_in_history = order_to_save.save_in_history; + + let storage = MyOrdersStorage::new(ctx); + if order_to_save.was_updated() { + if let Ok(order_from_file) = storage.load_active_maker_order(order_to_save.uuid).await { + order_to_save = order_from_file; } + } + storage + .delete_active_maker_order(uuid) + .await + .error_log_with_msg("!delete_active_maker_order"); + + if save_in_history { storage - .delete_active_maker_order(uuid) + .save_order_in_history(&Order::Maker(order_to_save.clone())) .await - .error_log_with_msg("!delete_active_maker_order"); - - if save_in_history { - storage - .save_order_in_history(&Order::Maker(order_to_save.clone())) - .await - .error_log_with_msg("!save_order_in_history"); - storage - .update_order_status_in_filtering_history(uuid, reason.to_string()) - .await - .error_log_with_msg("!update_order_status_in_filtering_history"); - } - Ok(()) - }; - Box::new(fut.boxed().compat()) + .error_log_with_msg("!save_order_in_history"); + storage + .update_order_status_in_filtering_history(uuid, reason.to_string()) + .await + .error_log_with_msg("!update_order_status_in_filtering_history"); + } } #[async_trait] @@ -297,7 +286,7 @@ mod native_impl { impl MyOrdersHistory for MyOrdersStorage { async fn save_order_in_history(&self, order: &Order) -> MyOrdersResult<()> { let path = my_order_history_file_path(&self.ctx, &order.uuid()); - write_json(order, &path, USE_TMP_FILE).await?; + write_json(&order, &path, USE_TMP_FILE).await?; Ok(()) } @@ -727,7 +716,6 @@ mod tests { base_orderbook_ticker: None, rel_orderbook_ticker: None, p2p_privkey: None, - status: MakerOrderStatus::Active, swap_version: SwapVersion::default(), } } @@ -791,9 +779,7 @@ mod tests { maker1.clone(), MakerOrderCancellationReason::InsufficientBalance, ) - .compat() - .await - .unwrap(); + .await; let actual_active_maker_orders = storage .load_active_taker_orders() @@ -827,10 +813,7 @@ mod tests { // The order has to be saved in history table. save_my_new_taker_order(ctx.clone(), &taker1).await.unwrap(); - delete_my_taker_order(ctx.clone(), taker1.clone(), TakerOrderCancellationReason::TimedOut) - .compat() - .await - .unwrap(); + delete_my_taker_order(ctx.clone(), taker1.clone(), TakerOrderCancellationReason::TimedOut).await; let actual_active_taker_orders = storage .load_active_taker_orders() @@ -851,10 +834,7 @@ mod tests { // The order hasn't to be saved in history as it's assumed to be active as a `MakerOrder`. save_my_new_taker_order(ctx.clone(), &taker2).await.unwrap(); - delete_my_taker_order(ctx.clone(), taker2.clone(), TakerOrderCancellationReason::ToMaker) - .compat() - .await - .unwrap(); + delete_my_taker_order(ctx.clone(), taker2.clone(), TakerOrderCancellationReason::ToMaker).await; let actual_active_taker_orders = storage .load_active_taker_orders() diff --git a/mm2src/mm2_main/src/ordermatch_tests.rs b/mm2src/mm2_main/src/ordermatch_tests.rs index 0edd47de5e..57fe694c8a 100644 --- a/mm2src/mm2_main/src/ordermatch_tests.rs +++ b/mm2src/mm2_main/src/ordermatch_tests.rs @@ -39,7 +39,7 @@ fn test_match_maker_order_and_taker_request() { base_orderbook_ticker: None, rel_orderbook_ticker: None, p2p_privkey: None, - status: MakerOrderStatus::Active, + swap_version: SwapVersion::default(), }; @@ -80,7 +80,7 @@ fn test_match_maker_order_and_taker_request() { base_orderbook_ticker: None, rel_orderbook_ticker: None, p2p_privkey: None, - status: MakerOrderStatus::Active, + swap_version: SwapVersion::default(), }; @@ -121,7 +121,7 @@ fn test_match_maker_order_and_taker_request() { base_orderbook_ticker: None, rel_orderbook_ticker: None, p2p_privkey: None, - status: MakerOrderStatus::Active, + swap_version: SwapVersion::default(), }; @@ -162,7 +162,7 @@ fn test_match_maker_order_and_taker_request() { base_orderbook_ticker: None, rel_orderbook_ticker: None, p2p_privkey: None, - status: MakerOrderStatus::Active, + swap_version: SwapVersion::default(), }; @@ -203,7 +203,7 @@ fn test_match_maker_order_and_taker_request() { base_orderbook_ticker: None, rel_orderbook_ticker: None, p2p_privkey: None, - status: MakerOrderStatus::Active, + swap_version: SwapVersion::default(), }; @@ -244,7 +244,7 @@ fn test_match_maker_order_and_taker_request() { base_orderbook_ticker: None, rel_orderbook_ticker: None, p2p_privkey: None, - status: MakerOrderStatus::Active, + swap_version: SwapVersion::default(), }; @@ -287,7 +287,7 @@ fn test_match_maker_order_and_taker_request() { base_orderbook_ticker: None, rel_orderbook_ticker: None, p2p_privkey: None, - status: MakerOrderStatus::Active, + swap_version: SwapVersion::default(), }; let request = TakerRequest { @@ -330,7 +330,7 @@ fn test_match_maker_order_and_taker_request() { base_orderbook_ticker: None, rel_orderbook_ticker: None, p2p_privkey: None, - status: MakerOrderStatus::Active, + swap_version: SwapVersion::default(), }; let request = TakerRequest { @@ -404,7 +404,7 @@ fn test_maker_order_available_amount() { base_orderbook_ticker: None, rel_orderbook_ticker: None, p2p_privkey: None, - status: MakerOrderStatus::Active, + swap_version: SwapVersion::default(), }; maker.matches.insert(new_uuid(), MakerMatch { @@ -1025,7 +1025,7 @@ fn prepare_for_cancel_by(ctx: &MmArc) -> mpsc::Receiver { base_orderbook_ticker: None, rel_orderbook_ticker: None, p2p_privkey: None, - status: MakerOrderStatus::Active, + swap_version: SwapVersion::default(), }, None, @@ -1049,7 +1049,7 @@ fn prepare_for_cancel_by(ctx: &MmArc) -> mpsc::Receiver { base_orderbook_ticker: None, rel_orderbook_ticker: None, p2p_privkey: None, - status: MakerOrderStatus::Active, + swap_version: SwapVersion::default(), }, None, @@ -1073,7 +1073,7 @@ fn prepare_for_cancel_by(ctx: &MmArc) -> mpsc::Receiver { base_orderbook_ticker: None, rel_orderbook_ticker: None, p2p_privkey: None, - status: MakerOrderStatus::Active, + swap_version: SwapVersion::default(), }, None, @@ -1118,8 +1118,8 @@ fn test_cancel_by_single_coin() { .set(Arc::new(Mutex::new(connection))) .map_err(|_| "Already Initialized".to_string()); - delete_my_maker_order.mock_safe(|_, _, _| MockResult::Return(Box::new(futures01::future::ok(())))); - delete_my_taker_order.mock_safe(|_, _, _| MockResult::Return(Box::new(futures01::future::ok(())))); + delete_my_maker_order.mock_safe(|_, _, _| MockResult::Return(Box::pin(std::future::ready(())))); + delete_my_taker_order.mock_safe(|_, _, _| MockResult::Return(Box::pin(std::future::ready(())))); let (cancelled, _) = block_on(cancel_orders_by(&ctx, CancelBy::Coin { ticker: "RICK".into() })).unwrap(); block_on(rx.take(2).collect::>()); @@ -1140,8 +1140,8 @@ fn test_cancel_by_pair() { .set(Arc::new(Mutex::new(connection))) .map_err(|_| "Already Initialized".to_string()); - delete_my_maker_order.mock_safe(|_, _, _| MockResult::Return(Box::new(futures01::future::ok(())))); - delete_my_taker_order.mock_safe(|_, _, _| MockResult::Return(Box::new(futures01::future::ok(())))); + delete_my_maker_order.mock_safe(|_, _, _| MockResult::Return(Box::pin(std::future::ready(())))); + delete_my_taker_order.mock_safe(|_, _, _| MockResult::Return(Box::pin(std::future::ready(())))); let (cancelled, _) = block_on(cancel_orders_by(&ctx, CancelBy::Pair { base: "RICK".into(), @@ -1166,8 +1166,8 @@ fn test_cancel_by_all() { .set(Arc::new(Mutex::new(connection))) .map_err(|_| "Already Initialized".to_string()); - delete_my_maker_order.mock_safe(|_, _, _| MockResult::Return(Box::new(futures01::future::ok(())))); - delete_my_taker_order.mock_safe(|_, _, _| MockResult::Return(Box::new(futures01::future::ok(())))); + delete_my_maker_order.mock_safe(|_, _, _| MockResult::Return(Box::pin(std::future::ready(())))); + delete_my_taker_order.mock_safe(|_, _, _| MockResult::Return(Box::pin(std::future::ready(())))); let (cancelled, _) = block_on(cancel_orders_by(&ctx, CancelBy::All)).unwrap(); block_on(rx.take(3).collect::>()); @@ -1266,7 +1266,7 @@ fn test_maker_order_was_updated() { base_orderbook_ticker: None, rel_orderbook_ticker: None, p2p_privkey: None, - status: MakerOrderStatus::Active, + swap_version: SwapVersion::default(), }; let mut update_msg = MakerOrderUpdated::new(maker_order.uuid); @@ -3277,7 +3277,7 @@ fn test_maker_order_balance_loops() { base_orderbook_ticker: None, rel_orderbook_ticker: None, p2p_privkey: None, - status: MakerOrderStatus::Active, + swap_version: SwapVersion::default(), }; @@ -3298,7 +3298,6 @@ fn test_maker_order_balance_loops() { base_orderbook_ticker: None, rel_orderbook_ticker: None, p2p_privkey: None, - status: MakerOrderStatus::Active, swap_version: SwapVersion::default(), }; @@ -3332,7 +3331,6 @@ fn test_maker_order_balance_loops() { base_orderbook_ticker: None, rel_orderbook_ticker: None, p2p_privkey: None, - status: MakerOrderStatus::Active, swap_version: SwapVersion::default(), }; @@ -3351,47 +3349,3 @@ fn test_maker_order_balance_loops() { assert!(!maker_orders_ctx.balance_loop_exists(morty_ticker)); assert_eq!(*maker_orders_ctx.count_by_tickers.get(morty_ticker).unwrap(), 0); } - -#[test] -fn test_match_maker_order_and_taker_request_fails_with_not_active() { - let maker = MakerOrder { - base: "BASE".into(), - rel: "REL".into(), - created_at: now_ms(), - updated_at: Some(now_ms()), - max_base_vol: 10.into(), - min_base_vol: 0.into(), - price: 1.into(), - matches: HashMap::new(), - started_swaps: Vec::new(), - uuid: new_uuid(), - conf_settings: None, - changes_history: None, - save_in_history: false, - base_orderbook_ticker: None, - rel_orderbook_ticker: None, - p2p_privkey: None, - status: MakerOrderStatus::RpcClientsUnavailable, // maker order not active - swap_version: SwapVersion::default(), - }; - - let request = TakerRequest { - base: "BASE".into(), - rel: "REL".into(), - uuid: new_uuid(), - dest_pub_key: H256Json::default(), - sender_pubkey: H256Json::default(), - base_amount: 10.into(), - rel_amount: 20.into(), - action: TakerAction::Buy, - match_by: MatchBy::Any, - conf_settings: None, - base_protocol_info: None, - rel_protocol_info: None, - swap_version: SwapVersion::default(), - }; - - let actual = maker.match_with_request(&request); - let expected = OrderMatchResult::NotMatched; - assert_eq!(expected, actual); -} From e598eb2d567f54d42b83d4f10d02c9b4b8753b39 Mon Sep 17 00:00:00 2001 From: Samuel Onoja Date: Thu, 6 Mar 2025 03:23:58 +0100 Subject: [PATCH 17/25] improve order cancelling logic, cover all coin/protocols and improve tendermint rpc_client storage --- mm2src/coins/lightning.rs | 1 + mm2src/coins/lp_coins.rs | 32 +++++---- mm2src/coins/siacoin.rs | 6 ++ mm2src/coins/tendermint/tendermint_coin.rs | 33 ++++++--- mm2src/coins/utxo/rpc_clients.rs | 9 +++ .../utxo/rpc_clients/electrum_rpc/client.rs | 2 + .../connection_manager/manager.rs | 11 +++ mm2src/mm2_main/src/lp_ordermatch.rs | 69 +++++++++++-------- .../src/lp_ordermatch/my_orders_storage.rs | 2 +- 9 files changed, 114 insertions(+), 51 deletions(-) diff --git a/mm2src/coins/lightning.rs b/mm2src/coins/lightning.rs index c94215be9b..ed85df9817 100644 --- a/mm2src/coins/lightning.rs +++ b/mm2src/coins/lightning.rs @@ -283,6 +283,7 @@ impl LightningCoin { { return false; } + // Checking if funding_tx is some and not equal if filter.funding_tx.is_some() && channel_details.funding_tx != filter.funding_tx { return false; diff --git a/mm2src/coins/lp_coins.rs b/mm2src/coins/lp_coins.rs index cf744c9334..45a602d6ae 100644 --- a/mm2src/coins/lp_coins.rs +++ b/mm2src/coins/lp_coins.rs @@ -260,7 +260,7 @@ pub mod utxo; use utxo::bch::{bch_coin_with_policy, BchActivationRequest, BchCoin}; use utxo::qtum::{self, qtum_coin_with_policy, Qrc20AddressError, QtumCoin, QtumDelegationOps, QtumDelegationRequest, QtumStakingInfosDetails, ScriptHashTypeNotSupported}; -use utxo::rpc_clients::{UtxoRpcClientEnum, UtxoRpcError}; +use utxo::rpc_clients::UtxoRpcError; use utxo::slp::SlpToken; use utxo::slp::{slp_addr_from_pubkey_str, SlpFeeDetails}; use utxo::utxo_common::{big_decimal_from_sat_unsigned, payment_script, WaitForOutputSpendErr}; @@ -3632,20 +3632,24 @@ impl MmCoinEnum { fn is_platform_coin(&self) -> bool { self.ticker() == self.platform_ticker() } - pub fn utxo_in_electrum_mode_is_offline(&self) -> Option { - if let UtxoRpcClientEnum::Electrum(c) = match self { - MmCoinEnum::UtxoCoin(c) => &c.as_ref().rpc_client, - MmCoinEnum::QtumCoin(c) => &c.as_ref().rpc_client, - MmCoinEnum::Qrc20Coin(c) => &c.as_ref().rpc_client, - MmCoinEnum::ZCoin(c) => &c.as_ref().rpc_client, - MmCoinEnum::Bch(c) => &c.as_ref().rpc_client, - MmCoinEnum::SlpToken(c) => &c.as_ref().rpc_client, - _ => return None, - } { - return Some(c.connection_manager.get_active_connections().is_empty()); + /// Check if coin server connection is offline. + pub async fn is_offline(&self) -> bool { + match self { + MmCoinEnum::Bch(c) => c.as_ref().rpc_client.is_native(), + MmCoinEnum::EthCoin(c) => c.get_live_client().await.is_err(), + MmCoinEnum::QtumCoin(c) => c.as_ref().rpc_client.is_offline(), + MmCoinEnum::Qrc20Coin(c) => c.as_ref().rpc_client.is_offline(), + MmCoinEnum::SlpToken(c) => c.as_ref().rpc_client.is_offline(), + MmCoinEnum::Tendermint(c) => c.get_live_client().await.is_err(), + MmCoinEnum::TendermintToken(c) => c.platform_coin.get_live_client().await.is_err(), + MmCoinEnum::UtxoCoin(c) => c.as_ref().rpc_client.is_offline(), + MmCoinEnum::ZCoin(c) => c.as_ref().rpc_client.is_offline(), + #[cfg(feature = "enable-sia")] + MmCoinEnum::SiaCoin(c) => c.is_offline().await, + #[cfg(not(target_arch = "wasm32"))] + MmCoinEnum::LightningCoin(c) => c.platform_coin().as_ref().rpc_client.is_offline(), + MmCoinEnum::Test(_) => true, } - - None } /// Determines the secret hash algorithm for a coin, prioritizing specific algorithms for certain protocols. diff --git a/mm2src/coins/siacoin.rs b/mm2src/coins/siacoin.rs index 28055b4e7f..031409e8c6 100644 --- a/mm2src/coins/siacoin.rs +++ b/mm2src/coins/siacoin.rs @@ -28,6 +28,7 @@ pub mod sia_hd_wallet; #[derive(Clone)] pub struct SiaCoin(SiaArc); + #[derive(Clone)] pub struct SiaArc(Arc); @@ -204,6 +205,11 @@ impl SiaArc { #[derive(Clone, Debug, Serialize, Deserialize)] pub struct SiaCoinProtocolInfo; +impl SiaCoin { + /// Checks if `SiaCoin` api client is offline. + pub async fn is_offline(&self) -> bool { self.0.http_client.current_height().await.is_err() } +} + #[async_trait] impl MmCoin for SiaCoin { fn is_asset_chain(&self) -> bool { false } diff --git a/mm2src/coins/tendermint/tendermint_coin.rs b/mm2src/coins/tendermint/tendermint_coin.rs index 2b5439c6d4..2326a8eb4e 100644 --- a/mm2src/coins/tendermint/tendermint_coin.rs +++ b/mm2src/coins/tendermint/tendermint_coin.rs @@ -73,7 +73,7 @@ use primitives::hash::H256; use regex::Regex; use rpc::v1::types::Bytes as BytesJson; use serde_json::{self as json, Value as Json}; -use std::collections::HashMap; +use std::collections::{HashMap, VecDeque}; use std::convert::{TryFrom, TryInto}; use std::io; use std::num::NonZeroU32; @@ -325,7 +325,14 @@ impl TendermintActivationPolicy { struct TendermintRpcClient(AsyncMutex); struct TendermintRpcClientImpl { - rpc_clients: Vec, + /// Using `VecDeque` instead of `Vec` for several performance reasons: + /// 1. O(1) operations for adding/removing clients at both ends (vs O(n) for `Vec.rotate_left()`) + /// 2. More efficient for the round-robin client selection pattern we use + /// 3. Better handling of client rotation without needing to clone the entire collection + /// + /// This approach improves performance in high-frequency scenarios where we need to + /// try multiple RPC nodes quickly to find a responsive one. + rpc_clients: VecDeque, } #[async_trait] @@ -335,22 +342,31 @@ impl RpcCommonOps for TendermintCoin { async fn get_live_client(&self) -> Result { let mut client_impl = self.client.0.lock().await; + let client_count = client_impl.rpc_clients.len(); + // try to find first live client - for (i, client) in client_impl.rpc_clients.clone().into_iter().enumerate() { + for _ in 0..client_count { + // SAFETY: Safe because we know the count and avoid bound check. + let client = client_impl.rpc_clients.pop_front().unwrap(); match client.perform(HealthRequest).timeout(Duration::from_secs(15)).await { Ok(Ok(_)) => { // Bring the live client to the front of rpc_clients - client_impl.rpc_clients.rotate_left(i); + client_impl.rpc_clients.push_front(client.clone()); return Ok(client); }, Ok(Err(rpc_error)) => { debug!("Could not perform healthcheck on: {:?}. Error: {}", &client, rpc_error); + // Put the failed client at the back of the queue + client_impl.rpc_clients.push_back(client); }, Err(timeout_error) => { debug!("Healthcheck timeout exceed on: {:?}. Error: {}", &client, timeout_error); + // Put the failed client at the back of the queue + client_impl.rpc_clients.push_back(client); }, }; } + return Err(TendermintCoinRpcError::RpcClientError( "All the current rpc nodes are unavailable.".to_string(), )); @@ -2470,7 +2486,7 @@ impl TendermintCoin { } } -fn clients_from_urls(ctx: &MmArc, nodes: Vec) -> MmResult, TendermintInitErrorKind> { +fn clients_from_urls(ctx: &MmArc, nodes: Vec) -> MmResult, TendermintInitErrorKind> { if nodes.is_empty() { return MmError::err(TendermintInitErrorKind::EmptyRpcUrls); } @@ -2482,20 +2498,21 @@ fn clients_from_urls(ctx: &MmArc, nodes: Vec) -> MmResult clients.push(client), + Ok(client) => clients.push_back(client), Err(e) => errors.push(format!("Url {} is invalid, got error {}", node.url, e)), } } drop_mutability!(clients); drop_mutability!(errors); + if !errors.is_empty() { let errors: String = errors.into_iter().join(", "); return MmError::err(TendermintInitErrorKind::RpcClientInitError(errors)); diff --git a/mm2src/coins/utxo/rpc_clients.rs b/mm2src/coins/utxo/rpc_clients.rs index fce6afa82a..3d36358811 100644 --- a/mm2src/coins/utxo/rpc_clients.rs +++ b/mm2src/coins/utxo/rpc_clients.rs @@ -186,6 +186,15 @@ impl UtxoRpcClientEnum { UtxoRpcClientEnum::Electrum(_) => false, } } + + /// Checks if all `ElectrumClient` servers are offline. + pub fn is_offline(&self) -> bool { + if let UtxoRpcClientEnum::Electrum(client) = self { + client.is_offline() + } else { + true + } + } } /// Generic unspent info required to build transactions, we need this separate type because native diff --git a/mm2src/coins/utxo/rpc_clients/electrum_rpc/client.rs b/mm2src/coins/utxo/rpc_clients/electrum_rpc/client.rs index 84e39997e4..21654e192a 100644 --- a/mm2src/coins/utxo/rpc_clients/electrum_rpc/client.rs +++ b/mm2src/coins/utxo/rpc_clients/electrum_rpc/client.rs @@ -793,6 +793,8 @@ impl ElectrumClient { Box::new(fut.boxed().compat()) } + + pub fn is_offline(&self) -> bool { self.connection_manager.is_completely_offline() } } // if mockable is placed before async_trait there is `munmap_chunk(): invalid pointer` error on async fn mocking attempt diff --git a/mm2src/coins/utxo/rpc_clients/electrum_rpc/connection_manager/manager.rs b/mm2src/coins/utxo/rpc_clients/electrum_rpc/connection_manager/manager.rs index b06628fd60..a17efee63b 100644 --- a/mm2src/coins/utxo/rpc_clients/electrum_rpc/connection_manager/manager.rs +++ b/mm2src/coins/utxo/rpc_clients/electrum_rpc/connection_manager/manager.rs @@ -312,6 +312,17 @@ impl ConnectionManager { self.write_connections().remove(server_address); Ok(connection) } + + /// Checks if there are no live server connections available. + pub fn is_completely_offline(&self) -> bool { + for server in self.read_maintained_connections().iter() { + if self.get_connection(server.1).is_some() { + return false; + }; + } + + true + } } // Background tasks. diff --git a/mm2src/mm2_main/src/lp_ordermatch.rs b/mm2src/mm2_main/src/lp_ordermatch.rs index 8f1a87bf11..14da9abe0e 100644 --- a/mm2src/mm2_main/src/lp_ordermatch.rs +++ b/mm2src/mm2_main/src/lp_ordermatch.rs @@ -3081,6 +3081,13 @@ fn lp_connect_start_bob(ctx: MmArc, maker_match: MakerMatch, maker_order: MakerO }, }; + let ordermatch_ctx = OrdermatchContext::from_ctx(&ctx).unwrap(); + // cancel order if coin server status is offline before proceeding. + if cancel_maker_order_if_coin_offline(&ctx, &ordermatch_ctx, &maker_order).await { + log::info!("cancelled-maker-order: All maker coin RPC servers are offline"); + return; + }; + let alice_swap_v = maker_match.request.swap_version; let bob_swap_v = maker_order.swap_version; @@ -3684,33 +3691,7 @@ async fn check_balance_for_maker_orders(ctx: MmArc, ordermatch_ctx: &OrdermatchC continue; } - if let Ok(Some(coin)) = lp_coinfind(&ctx, &order.base).await { - // Check if the base coin uses Electrum and cancel order if it has no active electrums connection. - let Some(true) = coin.utxo_in_electrum_mode_is_offline() else { - continue; - }; - - if !order.is_cancellable() { - info!( - "Down electrum: Unable to cancel maker_order:[{}] because it's not cancellable", - order.uuid - ); - continue; - } - - let removed_order_mutex = ordermatch_ctx.maker_orders_ctx.lock().remove_order(&order.uuid); - if removed_order_mutex.is_some() { - maker_order_cancelled_p2p_notify(&ctx, &order); - delete_my_maker_order( - ctx.clone(), - order.clone(), - MakerOrderCancellationReason::NoActiveElectrumConnection, - ) - .await; - } - - info!("[{}] Maker Order cancelled due to no active electrums.", order.uuid); - } + cancel_maker_order_if_coin_offline(&ctx, ordermatch_ctx, &order).await; continue; } @@ -3729,6 +3710,36 @@ async fn check_balance_for_maker_orders(ctx: MmArc, ordermatch_ctx: &OrdermatchC } } +/// Cancel maker order if coin is offline and return true if cancelled. +async fn cancel_maker_order_if_coin_offline( + ctx: &MmArc, + ordermatch_ctx: &OrdermatchContext, + order: &MakerOrder, +) -> bool { + if let Ok(Some(coin)) = lp_coinfind(ctx, &order.base).await { + if !coin.is_offline().await { + return false; + } + + let uuid = order.uuid; + let removed_order_mutex = ordermatch_ctx.maker_orders_ctx.lock().remove_order(&uuid); + if removed_order_mutex.is_some() { + maker_order_cancelled_p2p_notify(ctx, order); + delete_my_maker_order( + ctx.clone(), + order.clone(), + MakerOrderCancellationReason::OfflineMakerCoin, + ) + .await; + } + + info!("[{uuid}] Maker Order cancelled due to inactive rpc clients."); + return true; + } + + false +} + /// Removes timed out unfinished matches to unlock the reserved amount. /// /// # Safety @@ -4058,6 +4069,7 @@ async fn process_taker_connect(ctx: MmArc, sender_pubkey: PublicKey, connect_msg } }; let mut my_order = order_mutex.lock().await; + let order_match = match my_order.matches.get_mut(&connect_msg.taker_order_uuid) { Some(o) => o, None => { @@ -4081,6 +4093,7 @@ async fn process_taker_connect(ctx: MmArc, sender_pubkey: PublicKey, connect_msg maker_order_uuid: connect_msg.maker_order_uuid, method: "connected".into(), }; + order_match.connect = Some(connect_msg); order_match.connected = Some(connected.clone()); let order_match = order_match.clone(); @@ -5275,7 +5288,7 @@ pub enum MakerOrderCancellationReason { Fulfilled, InsufficientBalance, Cancelled, - NoActiveElectrumConnection, + OfflineMakerCoin, } #[derive(Display)] diff --git a/mm2src/mm2_main/src/lp_ordermatch/my_orders_storage.rs b/mm2src/mm2_main/src/lp_ordermatch/my_orders_storage.rs index 2c8f7c8a7a..f0fffaa766 100644 --- a/mm2src/mm2_main/src/lp_ordermatch/my_orders_storage.rs +++ b/mm2src/mm2_main/src/lp_ordermatch/my_orders_storage.rs @@ -120,7 +120,7 @@ pub async fn delete_my_maker_order(ctx: MmArc, order: MakerOrder, reason: MakerO if save_in_history { storage - .save_order_in_history(&Order::Maker(order_to_save.clone())) + .save_order_in_history(&Order::Maker(order_to_save)) .await .error_log_with_msg("!save_order_in_history"); storage From bfa772029aaf141e5344eef0e0a59b5a76fefa9f Mon Sep 17 00:00:00 2001 From: Samuel Onoja Date: Thu, 6 Mar 2025 06:46:38 +0100 Subject: [PATCH 18/25] fix bug --- mm2src/coins/lp_coins.rs | 4 ++-- mm2src/coins/utxo/rpc_clients.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/mm2src/coins/lp_coins.rs b/mm2src/coins/lp_coins.rs index 45a602d6ae..db59e16c10 100644 --- a/mm2src/coins/lp_coins.rs +++ b/mm2src/coins/lp_coins.rs @@ -3635,7 +3635,7 @@ impl MmCoinEnum { /// Check if coin server connection is offline. pub async fn is_offline(&self) -> bool { match self { - MmCoinEnum::Bch(c) => c.as_ref().rpc_client.is_native(), + MmCoinEnum::Bch(c) => c.as_ref().rpc_client.get_live_client().await.is_err(), MmCoinEnum::EthCoin(c) => c.get_live_client().await.is_err(), MmCoinEnum::QtumCoin(c) => c.as_ref().rpc_client.is_offline(), MmCoinEnum::Qrc20Coin(c) => c.as_ref().rpc_client.is_offline(), @@ -3648,7 +3648,7 @@ impl MmCoinEnum { MmCoinEnum::SiaCoin(c) => c.is_offline().await, #[cfg(not(target_arch = "wasm32"))] MmCoinEnum::LightningCoin(c) => c.platform_coin().as_ref().rpc_client.is_offline(), - MmCoinEnum::Test(_) => true, + MmCoinEnum::Test(_) => false, } } diff --git a/mm2src/coins/utxo/rpc_clients.rs b/mm2src/coins/utxo/rpc_clients.rs index 3d36358811..5d2e64b3f9 100644 --- a/mm2src/coins/utxo/rpc_clients.rs +++ b/mm2src/coins/utxo/rpc_clients.rs @@ -192,7 +192,7 @@ impl UtxoRpcClientEnum { if let UtxoRpcClientEnum::Electrum(client) = self { client.is_offline() } else { - true + false } } } From fb2b4fee383e1b3d4a508873f0772c9904c8cb65 Mon Sep 17 00:00:00 2001 From: Samuel Onoja Date: Thu, 6 Mar 2025 09:58:11 +0100 Subject: [PATCH 19/25] fix bch --- mm2src/coins/lp_coins.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/mm2src/coins/lp_coins.rs b/mm2src/coins/lp_coins.rs index db59e16c10..7824c40c94 100644 --- a/mm2src/coins/lp_coins.rs +++ b/mm2src/coins/lp_coins.rs @@ -3635,15 +3635,15 @@ impl MmCoinEnum { /// Check if coin server connection is offline. pub async fn is_offline(&self) -> bool { match self { - MmCoinEnum::Bch(c) => c.as_ref().rpc_client.get_live_client().await.is_err(), - MmCoinEnum::EthCoin(c) => c.get_live_client().await.is_err(), + MmCoinEnum::Bch(c) => c.as_ref().rpc_client.is_offline(), MmCoinEnum::QtumCoin(c) => c.as_ref().rpc_client.is_offline(), MmCoinEnum::Qrc20Coin(c) => c.as_ref().rpc_client.is_offline(), MmCoinEnum::SlpToken(c) => c.as_ref().rpc_client.is_offline(), - MmCoinEnum::Tendermint(c) => c.get_live_client().await.is_err(), - MmCoinEnum::TendermintToken(c) => c.platform_coin.get_live_client().await.is_err(), MmCoinEnum::UtxoCoin(c) => c.as_ref().rpc_client.is_offline(), MmCoinEnum::ZCoin(c) => c.as_ref().rpc_client.is_offline(), + MmCoinEnum::Tendermint(c) => c.get_live_client().await.is_err(), + MmCoinEnum::EthCoin(c) => c.get_live_client().await.is_err(), + MmCoinEnum::TendermintToken(c) => c.platform_coin.get_live_client().await.is_err(), #[cfg(feature = "enable-sia")] MmCoinEnum::SiaCoin(c) => c.is_offline().await, #[cfg(not(target_arch = "wasm32"))] From be73fa3a59cd11b22bdd03ab51522de80c7ddfbc Mon Sep 17 00:00:00 2001 From: Samuel Onoja Date: Thu, 6 Mar 2025 10:47:00 +0100 Subject: [PATCH 20/25] fix z_coin_cache db path in best_orders_tests --- mm2src/mm2_main/tests/mm2_tests/best_orders_tests.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/mm2src/mm2_main/tests/mm2_tests/best_orders_tests.rs b/mm2src/mm2_main/tests/mm2_tests/best_orders_tests.rs index f1149c15f3..0b743bfeea 100644 --- a/mm2src/mm2_main/tests/mm2_tests/best_orders_tests.rs +++ b/mm2src/mm2_main/tests/mm2_tests/best_orders_tests.rs @@ -615,7 +615,15 @@ fn zhtlc_best_orders() { let rmd = rmd160_from_passphrase(&bob_passphrase); let bob_zombie_cache_path = mm_bob.folder.join("DB").join(hex::encode(rmd)).join("ZOMBIE_CACHE.db"); log!("bob_zombie_cache_path {}", bob_zombie_cache_path.display()); - std::fs::copy("./mm2src/coins/for_tests/ZOMBIE_CACHE.db", bob_zombie_cache_path).unwrap(); + let project_root = { + let mut current_dir = std::env::current_dir().unwrap(); + current_dir.pop(); + current_dir.pop(); + current_dir + }; + let z_cache_root = project_root.join("mm2src/coins/for_tests/ZOMBIE_CACHE.db"); + assert!(z_cache_root.exists()); + std::fs::copy(z_cache_root, bob_zombie_cache_path).unwrap(); block_on(enable_electrum_json(&mm_bob, "RICK", false, doc_electrums())); block_on(enable_z_coin(&mm_bob, "ZOMBIE")); From 37ae831a0dd61d0ed15841a3e0c29a5fa95d2c4b Mon Sep 17 00:00:00 2001 From: Samuel Onoja Date: Mon, 17 Mar 2025 11:29:03 +0100 Subject: [PATCH 21/25] use current_block to check eth server status --- mm2src/coins/lp_coins.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mm2src/coins/lp_coins.rs b/mm2src/coins/lp_coins.rs index 7824c40c94..2fefae72a2 100644 --- a/mm2src/coins/lp_coins.rs +++ b/mm2src/coins/lp_coins.rs @@ -3642,7 +3642,7 @@ impl MmCoinEnum { MmCoinEnum::UtxoCoin(c) => c.as_ref().rpc_client.is_offline(), MmCoinEnum::ZCoin(c) => c.as_ref().rpc_client.is_offline(), MmCoinEnum::Tendermint(c) => c.get_live_client().await.is_err(), - MmCoinEnum::EthCoin(c) => c.get_live_client().await.is_err(), + MmCoinEnum::EthCoin(c) => c.current_block().compat().await.is_err(), MmCoinEnum::TendermintToken(c) => c.platform_coin.get_live_client().await.is_err(), #[cfg(feature = "enable-sia")] MmCoinEnum::SiaCoin(c) => c.is_offline().await, From 928520e30cc54d820562f43a1bbc8e6493966070 Mon Sep 17 00:00:00 2001 From: Samuel Onoja Date: Mon, 24 Mar 2025 08:47:31 +0100 Subject: [PATCH 22/25] remove unnecessary line breaks --- mm2src/mm2_main/src/ordermatch_tests.rs | 9 --------- 1 file changed, 9 deletions(-) diff --git a/mm2src/mm2_main/src/ordermatch_tests.rs b/mm2src/mm2_main/src/ordermatch_tests.rs index 57fe694c8a..c4de3e1317 100644 --- a/mm2src/mm2_main/src/ordermatch_tests.rs +++ b/mm2src/mm2_main/src/ordermatch_tests.rs @@ -39,7 +39,6 @@ fn test_match_maker_order_and_taker_request() { base_orderbook_ticker: None, rel_orderbook_ticker: None, p2p_privkey: None, - swap_version: SwapVersion::default(), }; @@ -80,7 +79,6 @@ fn test_match_maker_order_and_taker_request() { base_orderbook_ticker: None, rel_orderbook_ticker: None, p2p_privkey: None, - swap_version: SwapVersion::default(), }; @@ -121,7 +119,6 @@ fn test_match_maker_order_and_taker_request() { base_orderbook_ticker: None, rel_orderbook_ticker: None, p2p_privkey: None, - swap_version: SwapVersion::default(), }; @@ -162,7 +159,6 @@ fn test_match_maker_order_and_taker_request() { base_orderbook_ticker: None, rel_orderbook_ticker: None, p2p_privkey: None, - swap_version: SwapVersion::default(), }; @@ -203,7 +199,6 @@ fn test_match_maker_order_and_taker_request() { base_orderbook_ticker: None, rel_orderbook_ticker: None, p2p_privkey: None, - swap_version: SwapVersion::default(), }; @@ -244,7 +239,6 @@ fn test_match_maker_order_and_taker_request() { base_orderbook_ticker: None, rel_orderbook_ticker: None, p2p_privkey: None, - swap_version: SwapVersion::default(), }; @@ -287,7 +281,6 @@ fn test_match_maker_order_and_taker_request() { base_orderbook_ticker: None, rel_orderbook_ticker: None, p2p_privkey: None, - swap_version: SwapVersion::default(), }; let request = TakerRequest { @@ -330,7 +323,6 @@ fn test_match_maker_order_and_taker_request() { base_orderbook_ticker: None, rel_orderbook_ticker: None, p2p_privkey: None, - swap_version: SwapVersion::default(), }; let request = TakerRequest { @@ -404,7 +396,6 @@ fn test_maker_order_available_amount() { base_orderbook_ticker: None, rel_orderbook_ticker: None, p2p_privkey: None, - swap_version: SwapVersion::default(), }; maker.matches.insert(new_uuid(), MakerMatch { From 5ef385804db10f9d4759ba8aac42ca4a16680a2a Mon Sep 17 00:00:00 2001 From: Samuel Onoja Date: Thu, 17 Apr 2025 12:57:25 +0100 Subject: [PATCH 23/25] fix review notes --- mm2src/coins/lp_coins.rs | 1 + .../coins/utxo/rpc_clients/electrum_rpc/connection.rs | 2 +- .../electrum_rpc/connection_manager/manager.rs | 8 +++++--- mm2src/mm2_main/src/lp_ordermatch/my_orders_storage.rs | 2 +- mm2src/mm2_main/src/ordermatch_tests.rs | 5 ----- mm2src/mm2_main/tests/mm2_tests/best_orders_tests.rs | 10 +--------- 6 files changed, 9 insertions(+), 19 deletions(-) diff --git a/mm2src/coins/lp_coins.rs b/mm2src/coins/lp_coins.rs index f85b24fb19..7cbd7084a4 100644 --- a/mm2src/coins/lp_coins.rs +++ b/mm2src/coins/lp_coins.rs @@ -3708,6 +3708,7 @@ impl MmCoinEnum { MmCoinEnum::SiaCoin(c) => c.is_offline().await, #[cfg(not(target_arch = "wasm32"))] MmCoinEnum::LightningCoin(c) => c.platform_coin().as_ref().rpc_client.is_offline(), + #[cfg(any(test, feature = "for-tests"))] MmCoinEnum::Test(_) => false, } } diff --git a/mm2src/coins/utxo/rpc_clients/electrum_rpc/connection.rs b/mm2src/coins/utxo/rpc_clients/electrum_rpc/connection.rs index 3b234dc51f..9cebf50a5e 100644 --- a/mm2src/coins/utxo/rpc_clients/electrum_rpc/connection.rs +++ b/mm2src/coins/utxo/rpc_clients/electrum_rpc/connection.rs @@ -188,7 +188,7 @@ impl ElectrumConnection { fn weak_spawner(&self) -> WeakSpawner { self.abortable_system.weak_spawner() } - fn is_connected(&self) -> bool { self.tx.lock().unwrap().is_some() } + pub(crate) fn is_connected(&self) -> bool { self.tx.lock().unwrap().is_some() } fn set_protocol_version(&self, version: f32) { let mut protocol_version = self.protocol_version.lock().unwrap(); diff --git a/mm2src/coins/utxo/rpc_clients/electrum_rpc/connection_manager/manager.rs b/mm2src/coins/utxo/rpc_clients/electrum_rpc/connection_manager/manager.rs index a17efee63b..a221a90583 100644 --- a/mm2src/coins/utxo/rpc_clients/electrum_rpc/connection_manager/manager.rs +++ b/mm2src/coins/utxo/rpc_clients/electrum_rpc/connection_manager/manager.rs @@ -315,9 +315,11 @@ impl ConnectionManager { /// Checks if there are no live server connections available. pub fn is_completely_offline(&self) -> bool { - for server in self.read_maintained_connections().iter() { - if self.get_connection(server.1).is_some() { - return false; + for server_address in self.read_maintained_connections().values() { + if let Some(connection) = self.get_connection(server_address) { + if connection.is_connected() { + return false; + } }; } diff --git a/mm2src/mm2_main/src/lp_ordermatch/my_orders_storage.rs b/mm2src/mm2_main/src/lp_ordermatch/my_orders_storage.rs index f0fffaa766..8bf4e9ad66 100644 --- a/mm2src/mm2_main/src/lp_ordermatch/my_orders_storage.rs +++ b/mm2src/mm2_main/src/lp_ordermatch/my_orders_storage.rs @@ -286,7 +286,7 @@ mod native_impl { impl MyOrdersHistory for MyOrdersStorage { async fn save_order_in_history(&self, order: &Order) -> MyOrdersResult<()> { let path = my_order_history_file_path(&self.ctx, &order.uuid()); - write_json(&order, &path, USE_TMP_FILE).await?; + write_json(order, &path, USE_TMP_FILE).await?; Ok(()) } diff --git a/mm2src/mm2_main/src/ordermatch_tests.rs b/mm2src/mm2_main/src/ordermatch_tests.rs index c4de3e1317..054ec0e593 100644 --- a/mm2src/mm2_main/src/ordermatch_tests.rs +++ b/mm2src/mm2_main/src/ordermatch_tests.rs @@ -1016,7 +1016,6 @@ fn prepare_for_cancel_by(ctx: &MmArc) -> mpsc::Receiver { base_orderbook_ticker: None, rel_orderbook_ticker: None, p2p_privkey: None, - swap_version: SwapVersion::default(), }, None, @@ -1040,7 +1039,6 @@ fn prepare_for_cancel_by(ctx: &MmArc) -> mpsc::Receiver { base_orderbook_ticker: None, rel_orderbook_ticker: None, p2p_privkey: None, - swap_version: SwapVersion::default(), }, None, @@ -1064,7 +1062,6 @@ fn prepare_for_cancel_by(ctx: &MmArc) -> mpsc::Receiver { base_orderbook_ticker: None, rel_orderbook_ticker: None, p2p_privkey: None, - swap_version: SwapVersion::default(), }, None, @@ -1257,7 +1254,6 @@ fn test_maker_order_was_updated() { base_orderbook_ticker: None, rel_orderbook_ticker: None, p2p_privkey: None, - swap_version: SwapVersion::default(), }; let mut update_msg = MakerOrderUpdated::new(maker_order.uuid); @@ -3268,7 +3264,6 @@ fn test_maker_order_balance_loops() { base_orderbook_ticker: None, rel_orderbook_ticker: None, p2p_privkey: None, - swap_version: SwapVersion::default(), }; diff --git a/mm2src/mm2_main/tests/mm2_tests/best_orders_tests.rs b/mm2src/mm2_main/tests/mm2_tests/best_orders_tests.rs index 0b743bfeea..f1149c15f3 100644 --- a/mm2src/mm2_main/tests/mm2_tests/best_orders_tests.rs +++ b/mm2src/mm2_main/tests/mm2_tests/best_orders_tests.rs @@ -615,15 +615,7 @@ fn zhtlc_best_orders() { let rmd = rmd160_from_passphrase(&bob_passphrase); let bob_zombie_cache_path = mm_bob.folder.join("DB").join(hex::encode(rmd)).join("ZOMBIE_CACHE.db"); log!("bob_zombie_cache_path {}", bob_zombie_cache_path.display()); - let project_root = { - let mut current_dir = std::env::current_dir().unwrap(); - current_dir.pop(); - current_dir.pop(); - current_dir - }; - let z_cache_root = project_root.join("mm2src/coins/for_tests/ZOMBIE_CACHE.db"); - assert!(z_cache_root.exists()); - std::fs::copy(z_cache_root, bob_zombie_cache_path).unwrap(); + std::fs::copy("./mm2src/coins/for_tests/ZOMBIE_CACHE.db", bob_zombie_cache_path).unwrap(); block_on(enable_electrum_json(&mm_bob, "RICK", false, doc_electrums())); block_on(enable_z_coin(&mm_bob, "ZOMBIE")); From f49e339ba949c49895339335121c1f793c4e2424 Mon Sep 17 00:00:00 2001 From: Samuel Onoja Date: Thu, 17 Apr 2025 13:15:43 +0100 Subject: [PATCH 24/25] nits --- mm2src/mm2_main/src/lp_ordermatch.rs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/mm2src/mm2_main/src/lp_ordermatch.rs b/mm2src/mm2_main/src/lp_ordermatch.rs index 94636d1adc..7933b1e8ce 100644 --- a/mm2src/mm2_main/src/lp_ordermatch.rs +++ b/mm2src/mm2_main/src/lp_ordermatch.rs @@ -3692,13 +3692,12 @@ async fn check_balance_for_maker_orders(ctx: MmArc, ordermatch_ctx: &OrdermatchC for (uuid, order) in my_maker_orders { let order = order.lock().await; - if order.available_amount() >= order.min_base_vol || order.has_ongoing_matches() { - if order.has_ongoing_matches() { - continue; - } + if order.has_ongoing_matches() { + continue; + } + if order.available_amount() >= order.min_base_vol { cancel_maker_order_if_coin_offline(&ctx, ordermatch_ctx, &order).await; - continue; } From 7c7f3708b8b302c66ef3fc79a7f4301eeecaadec Mon Sep 17 00:00:00 2001 From: shamardy Date: Thu, 24 Jul 2025 20:46:59 +0300 Subject: [PATCH 25/25] post merge fix --- mm2src/mm2_main/src/lp_ordermatch.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/mm2src/mm2_main/src/lp_ordermatch.rs b/mm2src/mm2_main/src/lp_ordermatch.rs index 79d5353643..d52a533551 100644 --- a/mm2src/mm2_main/src/lp_ordermatch.rs +++ b/mm2src/mm2_main/src/lp_ordermatch.rs @@ -3599,10 +3599,7 @@ pub async fn lp_ordermatch_loop(ctx: MmArc) { let order = order_mutex.lock().await; maker_order_cancelled_p2p_notify(&ctx, &order); - delete_my_maker_order(ctx.clone(), order.clone(), MakerOrderCancellationReason::Expired) - .compat() - .await - .ok(); + delete_my_maker_order(ctx.clone(), order.clone(), MakerOrderCancellationReason::Expired).await; } {