Skip to content

Commit 98f53cc

Browse files
committed
pause maker others from matching if coin relies on electrum conns
1 parent d2b8cff commit 98f53cc

4 files changed

Lines changed: 86 additions & 120 deletions

File tree

mm2src/coins/lp_coins.rs

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -261,7 +261,7 @@ pub mod utxo;
261261
use utxo::bch::{bch_coin_with_policy, BchActivationRequest, BchCoin};
262262
use utxo::qtum::{self, qtum_coin_with_policy, Qrc20AddressError, QtumCoin, QtumDelegationOps, QtumDelegationRequest,
263263
QtumStakingInfosDetails, ScriptHashTypeNotSupported};
264-
use utxo::rpc_clients::{ElectrumClient, UtxoRpcClientEnum, UtxoRpcError};
264+
use utxo::rpc_clients::{UtxoRpcClientEnum, UtxoRpcError};
265265
use utxo::slp::SlpToken;
266266
use utxo::slp::{slp_addr_from_pubkey_str, SlpFeeDetails};
267267
use utxo::utxo_common::{big_decimal_from_sat_unsigned, payment_script, WaitForOutputSpendErr};
@@ -3566,22 +3566,24 @@ impl MmCoinEnum {
35663566

35673567
fn is_platform_coin(&self) -> bool { self.ticker() == self.platform_ticker() }
35683568

3569-
pub fn electrum_client(&self) -> Option<ElectrumClient> {
3570-
let maybe_client = match self {
3569+
pub fn utxo_in_electrum_mode_has_active_connection(&self) -> Option<bool> {
3570+
if let UtxoRpcClientEnum::Electrum(c) = match self {
35713571
MmCoinEnum::UtxoCoin(c) => &c.as_ref().rpc_client,
35723572
MmCoinEnum::QtumCoin(c) => &c.as_ref().rpc_client,
35733573
MmCoinEnum::Qrc20Coin(c) => &c.as_ref().rpc_client,
35743574
MmCoinEnum::ZCoin(c) => &c.as_ref().rpc_client,
35753575
MmCoinEnum::Bch(c) => &c.as_ref().rpc_client,
35763576
MmCoinEnum::SlpToken(c) => &c.as_ref().rpc_client,
35773577
_ => return None,
3578-
};
3579-
3580-
if let UtxoRpcClientEnum::Electrum(c) = maybe_client {
3581-
Some(c.clone())
3582-
} else {
3583-
None
3578+
} {
3579+
if c.connection_manager.get_active_connections().is_empty() {
3580+
return Some(false);
3581+
} else {
3582+
return Some(true);
3583+
}
35843584
}
3585+
3586+
None
35853587
}
35863588
}
35873589

mm2src/mm2_main/src/lp_native_dex.rs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,7 @@ use crate::lp_healthcheck::peer_healthcheck_topic;
5151
use crate::lp_message_service::{init_message_service, InitMessageServiceError};
5252
use crate::lp_network::{lp_network_ports, p2p_event_process_loop, subscribe_to_topic, NetIdError};
5353
use crate::lp_ordermatch::{broadcast_maker_orders_keep_alive_loop, clean_memory_loop, init_ordermatch_context,
54-
lp_ordermatch_loop, monitor_electrum_and_cancel_orders, orders_kick_start,
55-
BalanceUpdateOrdermatchHandler, OrdermatchInitError};
54+
lp_ordermatch_loop, orders_kick_start, BalanceUpdateOrdermatchHandler, OrdermatchInitError};
5655
use crate::lp_swap;
5756
use crate::lp_swap::swap_kick_starts;
5857
use crate::lp_wallet::{initialize_wallet_passphrase, WalletInitError};
@@ -492,8 +491,6 @@ pub async fn lp_init_continue(ctx: MmArc) -> MmInitResult<()> {
492491

493492
ctx.spawner().spawn(broadcast_maker_orders_keep_alive_loop(ctx.clone()));
494493

495-
ctx.spawner().spawn(monitor_electrum_and_cancel_orders(ctx.clone()));
496-
497494
#[cfg(target_arch = "wasm32")]
498495
init_wasm_event_streaming(&ctx);
499496

mm2src/mm2_main/src/lp_ordermatch.rs

Lines changed: 32 additions & 107 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,11 @@ use async_trait::async_trait;
2424
use blake2::digest::{Update, VariableOutput};
2525
use blake2::Blake2bVar;
2626
use coins::utxo::{compressed_pub_key_from_priv_raw, ChecksumType, UtxoAddressFormat};
27-
use coins::{coin_conf, find_pair, lp_coinfind, lp_coinfind_or_err, BalanceTradeFeeUpdatedHandler, CoinProtocol,
28-
CoinsContext, FeeApproxStage, MarketCoinOps, MmCoinEnum};
27+
use coins::{coin_conf, find_pair, lp_coinfind, BalanceTradeFeeUpdatedHandler, CoinProtocol, CoinsContext,
28+
FeeApproxStage, MarketCoinOps, MmCoinEnum};
2929
use common::executor::{simple_map::AbortableSimpleMap, AbortSettings, AbortableSystem, AbortedError, SpawnAbortable,
3030
SpawnFuture, Timer};
31-
use common::log::{debug, error, info, warn, LogOnError};
31+
use common::log::{error, info, warn, LogOnError};
3232
use common::{bits256, log, new_uuid, now_ms, now_sec};
3333
use crypto::privkey::SerializableSecp256k1Keypair;
3434
use crypto::{CryptoCtx, CryptoCtxError};
@@ -59,10 +59,9 @@ use rpc::v1::types::H256 as H256Json;
5959
use serde_json::{self as json, Value as Json};
6060
use sp_trie::{delta_trie_root, MemoryDB, Trie, TrieConfiguration, TrieDB, TrieDBMut, TrieHash, TrieMut};
6161
use std::collections::hash_map::{Entry, HashMap, RawEntryMut};
62-
use std::collections::{BTreeSet, HashSet, VecDeque};
62+
use std::collections::{BTreeSet, HashSet};
6363
use std::convert::TryInto;
6464
use std::fmt;
65-
use std::iter::FromIterator;
6665
use std::ops::Deref;
6766
use std::path::PathBuf;
6867
use std::sync::Arc;
@@ -132,7 +131,6 @@ const TRIE_STATE_HISTORY_TIMEOUT: u64 = 3;
132131
const TRIE_ORDER_HISTORY_TIMEOUT: u64 = 300;
133132
#[cfg(test)]
134133
const TRIE_ORDER_HISTORY_TIMEOUT: u64 = 3;
135-
const MONITOR_ELECTRUM_CLIENT_INTERVAL: f64 = 30.;
136134

137135
pub type OrderbookP2PHandlerResult = Result<(), MmError<OrderbookP2PHandlerError>>;
138136

@@ -1691,7 +1689,7 @@ pub struct MakerOrder {
16911689
/// A custom priv key for more privacy to prevent linking orders of the same node between each other
16921690
/// Commonly used with privacy coins (ARRR, ZCash, etc.)
16931691
p2p_privkey: Option<SerializableSecp256k1Keypair>,
1694-
// Signal for maker orders that should be ordermatched.
1692+
// Indicates whether the maker order is eligible for order matching.
16951693
is_active: bool,
16961694
}
16971695

@@ -2004,8 +2002,14 @@ impl MakerOrder {
20042002
}
20052003

20062004
fn match_with_request(&self, taker: &TakerRequest) -> OrderMatchResult {
2007-
// TODO: only match with taker assuming our coin relies on electrum connections
2008-
// and there's an atleast 1 active connection.
2005+
if !self.is_active {
2006+
info!(
2007+
"[{}] Maker order is inactive, skipping order match with taker",
2008+
self.uuid
2009+
);
2010+
return OrderMatchResult::NotMatched;
2011+
}
2012+
20092013
let taker_base_amount = taker.get_base_amount();
20102014
let taker_rel_amount = taker.get_rel_amount();
20112015

@@ -2083,8 +2087,6 @@ impl MakerOrder {
20832087
fn was_updated(&self) -> bool { self.updated_at != Some(self.created_at) }
20842088

20852089
fn p2p_keypair(&self) -> Option<&KeyPair> { self.p2p_privkey.as_ref().map(|key| key.key_pair()) }
2086-
2087-
fn is_active(&self) -> bool { self.is_active }
20882090
}
20892091

20902092
impl From<TakerOrder> for MakerOrder {
@@ -2332,97 +2334,6 @@ fn broadcast_ordermatch_message(
23322334
broadcast_p2p_msg(ctx, topic, encoded_msg, peer_id);
23332335
}
23342336

2335-
pub async fn monitor_electrum_and_cancel_orders(ctx: MmArc) {
2336-
info!("Monitor electrum connection and cancel orders loop running!");
2337-
while !ctx.is_stopping() {
2338-
let ordermatch_ctx = OrdermatchContext::from_ctx(&ctx).expect("from_ctx failed");
2339-
let my_maker_orders = ordermatch_ctx.maker_orders_ctx.lock().orders.clone();
2340-
let mut order_queue = VecDeque::from_iter(my_maker_orders);
2341-
2342-
while let Some((uuid, my_order)) = order_queue.pop_front() {
2343-
let order = my_order.lock().await;
2344-
if !order.is_cancellable() {
2345-
continue;
2346-
}
2347-
let Ok(coin) = lp_coinfind_or_err(&ctx, &order.base).await else {
2348-
debug!("[{uuid}] Maker order coin {} not activated yet, will check back in {MONITOR_ELECTRUM_CLIENT_INTERVAL}s", order.base);
2349-
drop(order);
2350-
order_queue.push_back((uuid, my_order));
2351-
continue;
2352-
};
2353-
if let Some(c) = coin.electrum_client() {
2354-
if !c.deref().connection_manager.get_active_connections().is_empty() {
2355-
continue;
2356-
}
2357-
let removed_order_mutex = ordermatch_ctx.maker_orders_ctx.lock().remove_order(&uuid);
2358-
if removed_order_mutex.is_some() {
2359-
maker_order_cancelled_p2p_notify(&ctx, &order);
2360-
delete_my_maker_order(
2361-
ctx.clone(),
2362-
order.clone(),
2363-
MakerOrderCancellationReason::ElectrumServersOffline,
2364-
)
2365-
.compat()
2366-
.await
2367-
.ok();
2368-
info!(
2369-
"[{}]: Maker order cancelled - reason: {}",
2370-
uuid,
2371-
MakerOrderCancellationReason::ElectrumServersOffline
2372-
);
2373-
};
2374-
};
2375-
}
2376-
// Taker order.
2377-
let mut my_taker_orders_queue = VecDeque::from_iter(
2378-
ordermatch_ctx
2379-
.my_taker_orders
2380-
.lock()
2381-
.await
2382-
.clone()
2383-
.into_iter()
2384-
.map(|(uuid, order)| (uuid, order.base_orderbook_ticker().to_owned()))
2385-
.collect::<Vec<_>>(),
2386-
);
2387-
while let Some((uuid, ticker)) = my_taker_orders_queue.pop_front() {
2388-
let Ok(coin) = lp_coinfind_or_err(&ctx, &ticker).await else {
2389-
debug!("[{uuid}] Taker order coin {ticker} not activated yet, will check back in {MONITOR_ELECTRUM_CLIENT_INTERVAL}s");
2390-
my_taker_orders_queue.push_back((uuid, ticker));
2391-
continue;
2392-
};
2393-
if let Some(c) = coin.electrum_client() {
2394-
if !c.deref().connection_manager.get_active_connections().is_empty() {
2395-
continue;
2396-
}
2397-
let mut taker_orders = ordermatch_ctx.my_taker_orders.lock().await;
2398-
match taker_orders.entry(uuid) {
2399-
Entry::Occupied(order) => {
2400-
if !order.get().is_cancellable() {
2401-
continue;
2402-
}
2403-
delete_my_taker_order(
2404-
ctx.clone(),
2405-
order.remove(),
2406-
TakerOrderCancellationReason::ElectrumServersOffline,
2407-
)
2408-
.compat()
2409-
.await
2410-
.ok();
2411-
info!(
2412-
"[{}]: Taker order cancelled - reason: {}",
2413-
uuid,
2414-
TakerOrderCancellationReason::ElectrumServersOffline
2415-
);
2416-
},
2417-
// error is returned
2418-
Entry::Vacant(_) => (),
2419-
}
2420-
};
2421-
}
2422-
Timer::sleep(MONITOR_ELECTRUM_CLIENT_INTERVAL).await;
2423-
}
2424-
}
2425-
24262337
/// The order is ordered by [`OrderbookItem::price`] and [`OrderbookItem::uuid`].
24272338
#[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
24282339
struct OrderedByPriceOrder {
@@ -3554,15 +3465,29 @@ async fn check_balance_for_maker_orders(ctx: MmArc, ordermatch_ctx: &OrdermatchC
35543465
let my_maker_orders = ordermatch_ctx.maker_orders_ctx.lock().orders.clone();
35553466

35563467
for (uuid, order) in my_maker_orders {
3557-
let order = order.lock().await;
3468+
let mut order = order.lock().await;
3469+
35583470
if order.available_amount() >= order.min_base_vol || order.has_ongoing_matches() {
3471+
if order.has_ongoing_matches() {
3472+
continue;
3473+
}
3474+
3475+
if let Ok(Some(coin)) = lp_coinfind(&ctx, &order.base).await {
3476+
// Check if the base coin uses Electrum and update the order's active status only if it has changed
3477+
if let Some(is_active) = coin.utxo_in_electrum_mode_has_active_connection() {
3478+
if is_active != order.is_active {
3479+
order.is_active = is_active;
3480+
info!(
3481+
"[{}] Order status updated to `{is_active}` based on Electrum connection status",
3482+
order.uuid
3483+
);
3484+
}
3485+
}
3486+
};
3487+
35593488
continue;
35603489
}
35613490

3562-
// TODO: check coin depends on electrum and check their connection status.
3563-
// if connection status to all electrum client for this coin is down,
3564-
// change maker_order.is_active to false.
3565-
35663491
let reason = if order.matches.is_empty() {
35673492
MakerOrderCancellationReason::InsufficientBalance
35683493
} else {

mm2src/mm2_main/src/ordermatch_tests.rs

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3299,3 +3299,45 @@ fn test_maker_order_balance_loops() {
32993299
assert!(!maker_orders_ctx.balance_loop_exists(morty_ticker));
33003300
assert_eq!(*maker_orders_ctx.count_by_tickers.get(morty_ticker).unwrap(), 0);
33013301
}
3302+
3303+
#[test]
3304+
fn test_match_maker_order_and_taker_request_fails_with_not_active() {
3305+
let maker = MakerOrder {
3306+
base: "BASE".into(),
3307+
rel: "REL".into(),
3308+
created_at: now_ms(),
3309+
updated_at: Some(now_ms()),
3310+
max_base_vol: 10.into(),
3311+
min_base_vol: 0.into(),
3312+
price: 1.into(),
3313+
matches: HashMap::new(),
3314+
started_swaps: Vec::new(),
3315+
uuid: new_uuid(),
3316+
conf_settings: None,
3317+
changes_history: None,
3318+
save_in_history: false,
3319+
base_orderbook_ticker: None,
3320+
rel_orderbook_ticker: None,
3321+
p2p_privkey: None,
3322+
is_active: false, // maker order not active
3323+
};
3324+
3325+
let request = TakerRequest {
3326+
base: "BASE".into(),
3327+
rel: "REL".into(),
3328+
uuid: new_uuid(),
3329+
dest_pub_key: H256Json::default(),
3330+
sender_pubkey: H256Json::default(),
3331+
base_amount: 10.into(),
3332+
rel_amount: 20.into(),
3333+
action: TakerAction::Buy,
3334+
match_by: MatchBy::Any,
3335+
conf_settings: None,
3336+
base_protocol_info: None,
3337+
rel_protocol_info: None,
3338+
};
3339+
3340+
let actual = maker.match_with_request(&request);
3341+
let expected = OrderMatchResult::NotMatched;
3342+
assert_eq!(expected, actual);
3343+
}

0 commit comments

Comments
 (0)