Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(dex-api): best orders proper is_mine provided #1849

Merged
merged 16 commits into from
Jun 15, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 18 additions & 10 deletions mm2src/mm2_main/src/lp_ordermatch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -359,12 +359,12 @@ fn process_maker_order_updated(
// Ok(())
// }

// ZHTLC protocol coin uses random keypair to sign P2P messages per every order.
// So, each ZHTLC order has unique «pubkey» field that doesn’t match node persistent pubkey derived from passphrase.
// Some coins, for example ZHTLC, have privacy features like random keypair to sign P2P messages per every order.
// So, each order of such coin has unique «pubkey» field that doesn’t match node persistent pubkey derived from passphrase.
// We can compare pubkeys from maker_orders and from asks or bids, to find our order.
#[inline(always)]
fn is_my_order(my_orders_pubkeys: &HashSet<String>, my_pub: &Option<String>, order_pubkey: &str) -> bool {
my_pub.as_deref() == Some(order_pubkey) || my_orders_pubkeys.contains(order_pubkey)
fn is_my_order(order_pubkey: &str, my_pub: &Option<String>, my_p2p_pubkeys: &HashSet<String>) -> bool {
my_pub.as_deref() == Some(order_pubkey) || my_p2p_pubkeys.contains(order_pubkey)
}

/// Request best asks and bids for the given `base` and `rel` coins from relays.
Expand Down Expand Up @@ -395,11 +395,7 @@ async fn request_and_fill_orderbook(ctx: &MmArc, base: &str, rel: &str) -> Resul
let ordermatch_ctx = OrdermatchContext::from_ctx(ctx).unwrap();
let mut orderbook = ordermatch_ctx.orderbook.lock();

let my_pubsecp = match CryptoCtx::from_ctx(ctx).discard_mm_trace() {
Ok(crypto_ctx) => Some(crypto_ctx.mm2_internal_pubkey_hex()),
Err(CryptoCtxError::NotInitialized) => None,
Err(other) => return ERR!("{}", other),
};
let my_pubsecp = mm2_internal_pubkey_hex(ctx, String::from).map_err(MmError::into_inner)?;

let alb_pair = alb_ordered_pair(base, rel);
for (pubkey, GetOrderbookPubkeyItem { orders, .. }) in pubkey_orders {
Expand All @@ -411,7 +407,7 @@ async fn request_and_fill_orderbook(ctx: &MmArc, base: &str, rel: &str) -> Resul
},
};

if is_my_order(&orderbook.my_p2p_pubkeys, &my_pubsecp, &pubkey) {
if is_my_order(&pubkey, &my_pubsecp, &orderbook.my_p2p_pubkeys) {
continue;
}

Expand Down Expand Up @@ -473,6 +469,18 @@ fn delete_my_order(ctx: &MmArc, uuid: Uuid, p2p_privkey: Option<SerializableSecp
}
}

pub(crate) fn mm2_internal_pubkey_hex<E, F>(ctx: &MmArc, err_construct: F) -> MmResult<Option<String>, E>
where
E: NotMmError,
F: Fn(String) -> E,
{
match CryptoCtx::from_ctx(ctx).split_mm() {
Ok(crypto_ctx) => Ok(Some(CryptoCtx::mm2_internal_pubkey_hex(crypto_ctx.as_ref()))),
Err((CryptoCtxError::NotInitialized, _)) => Ok(None),
Err((CryptoCtxError::Internal(error), trace)) => MmError::err_with_trace(err_construct(error), trace),
}
}

fn remove_pubkey_pair_orders(orderbook: &mut Orderbook, pubkey: &str, alb_pair: &str) {
let pubkey_state = match orderbook.pubkeys_state.get_mut(pubkey) {
Some(state) => state,
Expand Down
32 changes: 23 additions & 9 deletions mm2src/mm2_main/src/lp_ordermatch/best_orders.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,3 @@
use super::{addr_format_from_protocol_info, BaseRelProtocolInfo, OrderConfirmationsSettings,
OrderbookP2PItemWithProof, OrdermatchContext, OrdermatchRequest};
use crate::mm2::lp_network::{request_any_relay, P2PRequest};
use crate::mm2::lp_ordermatch::{orderbook_address, RpcOrderbookEntryV2};
use coins::{address_by_coin_conf_and_pubkey_str, coin_conf, is_wallet_only_conf, is_wallet_only_ticker};
use common::{log, HttpStatusCode};
use derive_more::Display;
Expand All @@ -14,6 +10,11 @@ use serde_json::{self as json, Value as Json};
use std::collections::{HashMap, HashSet};
use uuid::Uuid;

use super::{addr_format_from_protocol_info, is_my_order, mm2_internal_pubkey_hex, orderbook_address,
BaseRelProtocolInfo, OrderConfirmationsSettings, OrderbookP2PItemWithProof, OrdermatchContext,
OrdermatchRequest, RpcOrderbookEntryV2};
use crate::mm2::lp_network::{request_any_relay, P2PRequest};

#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(rename_all = "lowercase")]
pub enum BestOrdersAction {
Expand Down Expand Up @@ -51,6 +52,8 @@ pub struct BestOrdersRequestV2 {
coin: String,
action: BestOrdersAction,
request_by: RequestBestOrdersBy,
#[serde(default)]
exclude_mine: bool,
}

pub fn process_best_orders_p2p_request(
Expand Down Expand Up @@ -223,6 +226,8 @@ pub async fn best_orders_rpc(ctx: MmArc, req: Json) -> Result<Response<Vec<u8>>,
let mut response = HashMap::new();
if let Some((p2p_response, peer_id)) = best_orders_res {
log::debug!("Got best orders {:?} from peer {}", p2p_response, peer_id);
let my_pubsecp = mm2_internal_pubkey_hex(&ctx, String::from).map_err(MmError::into_inner)?;
let my_p2p_pubkeys = ordermatch_ctx.orderbook.lock().my_p2p_pubkeys.clone();
for (coin, orders_w_proofs) in p2p_response.orders {
let coin_conf = coin_conf(&ctx, &coin);
if coin_conf.is_null() {
Expand Down Expand Up @@ -256,9 +261,10 @@ pub async fn best_orders_rpc(ctx: MmArc, req: Json) -> Result<Response<Vec<u8>>,
},
};
let conf_settings = p2p_response.conf_infos.get(&order.uuid);
let is_mine = is_my_order(&order.pubkey, &my_pubsecp, &my_p2p_pubkeys);
let entry = match req.action {
BestOrdersAction::Buy => order.as_rpc_best_orders_buy(address, conf_settings, false),
BestOrdersAction::Sell => order.as_rpc_best_orders_sell(address, conf_settings, false),
BestOrdersAction::Buy => order.as_rpc_best_orders_buy(address, conf_settings, is_mine),
BestOrdersAction::Sell => order.as_rpc_best_orders_sell(address, conf_settings, is_mine),
};
if let Some(original_tickers) = ordermatch_ctx.original_tickers.get(&coin) {
for ticker in original_tickers {
Expand Down Expand Up @@ -286,13 +292,14 @@ pub async fn best_orders_rpc(ctx: MmArc, req: Json) -> Result<Response<Vec<u8>>,
pub enum BestOrdersRpcError {
CoinIsWalletOnly(String),
P2PError(String),
CtxError(String),
}

impl HttpStatusCode for BestOrdersRpcError {
fn status_code(&self) -> StatusCode {
match self {
BestOrdersRpcError::CoinIsWalletOnly(_) => StatusCode::BAD_REQUEST,
BestOrdersRpcError::P2PError(_) => StatusCode::INTERNAL_SERVER_ERROR,
BestOrdersRpcError::P2PError(_) | BestOrdersRpcError::CtxError(_) => StatusCode::INTERNAL_SERVER_ERROR,
}
}
}
Expand Down Expand Up @@ -330,6 +337,9 @@ pub async fn best_orders_rpc_v2(
let mut orders = HashMap::new();
if let Some((p2p_response, peer_id)) = best_orders_res {
log::debug!("Got best orders {:?} from peer {}", p2p_response, peer_id);
let my_pubsecp = mm2_internal_pubkey_hex(&ctx, BestOrdersRpcError::CtxError)?;
let my_p2p_pubkeys = ordermatch_ctx.orderbook.lock().my_p2p_pubkeys.clone();

for (coin, orders_w_proofs) in p2p_response.orders {
let coin_conf = coin_conf(&ctx, &coin);
if coin_conf.is_null() {
Expand All @@ -345,6 +355,10 @@ pub async fn best_orders_rpc_v2(
}
for order_w_proof in orders_w_proofs {
let order = order_w_proof.order;
let is_mine = is_my_order(&order.pubkey, &my_pubsecp, &my_p2p_pubkeys);
if req.exclude_mine && is_mine {
continue;
}
let empty_proto_info = BaseRelProtocolInfo::default();
let proto_infos = p2p_response
.protocol_infos
Expand All @@ -363,8 +377,8 @@ pub async fn best_orders_rpc_v2(
};
let conf_settings = p2p_response.conf_infos.get(&order.uuid);
let entry = match req.action {
BestOrdersAction::Buy => order.as_rpc_best_orders_buy_v2(address, conf_settings, false),
BestOrdersAction::Sell => order.as_rpc_best_orders_sell_v2(address, conf_settings, false),
BestOrdersAction::Buy => order.as_rpc_best_orders_buy_v2(address, conf_settings, is_mine),
BestOrdersAction::Sell => order.as_rpc_best_orders_sell_v2(address, conf_settings, is_mine),
};
if let Some(original_tickers) = ordermatch_ctx.original_tickers.get(&coin) {
for ticker in original_tickers {
Expand Down
32 changes: 12 additions & 20 deletions mm2src/mm2_main/src/lp_ordermatch/orderbook_rpc.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
use super::{addr_format_from_protocol_info, is_my_order, orderbook_address, subscribe_to_orderbook_topic,
OrdermatchContext, RpcOrderbookEntry, RpcOrderbookEntryV2};
use coins::{address_by_coin_conf_and_pubkey_str, coin_conf, is_wallet_only_conf};
use common::log::warn;
use common::{now_sec, HttpStatusCode};
use crypto::{CryptoCtx, CryptoCtxError};
use derive_more::Display;
use http::{Response, StatusCode};
use mm2_core::mm_ctx::MmArc;
Expand All @@ -12,6 +9,9 @@ use mm2_number::{construct_detailed, BigRational, MmNumber, MmNumberMultiRepr};
use num_traits::Zero;
use serde_json::{self as json, Value as Json};

use super::{addr_format_from_protocol_info, is_my_order, mm2_internal_pubkey_hex, orderbook_address,
subscribe_to_orderbook_topic, OrdermatchContext, RpcOrderbookEntry, RpcOrderbookEntryV2};

#[derive(Deserialize)]
pub struct OrderbookReq {
base: String,
Expand Down Expand Up @@ -136,13 +136,11 @@ pub async fn orderbook_rpc(ctx: MmArc, req: Json) -> Result<Response<Vec<u8>>, S

try_s!(subscribe_to_orderbook_topic(&ctx, &base_ticker, &rel_ticker, request_orderbook).await);

let my_pubsecp = match CryptoCtx::from_ctx(&ctx).discard_mm_trace() {
Ok(crypto_ctx) => Some(crypto_ctx.mm2_internal_pubkey_hex()),
Err(CryptoCtxError::NotInitialized) => None,
Err(other) => return ERR!("{}", other),
};
let my_pubsecp = mm2_internal_pubkey_hex(&ctx, String::from).map_err(MmError::into_inner)?;

let orderbook = ordermatch_ctx.orderbook.lock();
let my_p2p_pubkeys = &orderbook.my_p2p_pubkeys;

let mut asks = match orderbook.unordered.get(&(base_ticker.clone(), rel_ticker.clone())) {
Some(uuids) => {
let mut orderbook_entries = Vec::new();
Expand All @@ -159,7 +157,7 @@ pub async fn orderbook_rpc(ctx: MmArc, req: Json) -> Result<Response<Vec<u8>>, S
&ask.pubkey,
address_format,
));
let is_mine = is_my_order(&orderbook.my_p2p_pubkeys, &my_pubsecp, &ask.pubkey);
let is_mine = is_my_order(&ask.pubkey, &my_pubsecp, my_p2p_pubkeys);
orderbook_entries.push(ask.as_rpc_entry_ask(address, is_mine));
}
orderbook_entries
Expand All @@ -186,7 +184,7 @@ pub async fn orderbook_rpc(ctx: MmArc, req: Json) -> Result<Response<Vec<u8>>, S
&bid.pubkey,
address_format,
));
let is_mine = is_my_order(&orderbook.my_p2p_pubkeys, &my_pubsecp, &bid.pubkey);
let is_mine = is_my_order(&bid.pubkey, &my_pubsecp, my_p2p_pubkeys);
orderbook_entries.push(bid.as_rpc_entry_bid(address, is_mine));
}
orderbook_entries
Expand Down Expand Up @@ -305,15 +303,9 @@ pub async fn orderbook_rpc_v2(
.await
.map_to_mm(OrderbookRpcError::P2PSubscribeError)?;

let my_pubsecp = mm2_internal_pubkey_hex(&ctx, OrderbookRpcError::Internal)?;
let orderbook = ordermatch_ctx.orderbook.lock();

let my_pubsecp = match CryptoCtx::from_ctx(&ctx).split_mm() {
Ok(crypto_ctx) => Some(crypto_ctx.mm2_internal_pubkey_hex()),
Err((CryptoCtxError::NotInitialized, _trace)) => None,
Err((CryptoCtxError::Internal(e), trace)) => {
return MmError::err_with_trace(OrderbookRpcError::Internal(e), trace)
},
};
let my_p2p_pubkeys = &orderbook.my_p2p_pubkeys;

let mut asks = match orderbook.unordered.get(&(base_ticker.clone(), rel_ticker.clone())) {
Some(uuids) => {
Expand All @@ -334,7 +326,7 @@ pub async fn orderbook_rpc_v2(
continue;
},
};
let is_mine = is_my_order(&orderbook.my_p2p_pubkeys, &my_pubsecp, &ask.pubkey);
let is_mine = is_my_order(&ask.pubkey, &my_pubsecp, my_p2p_pubkeys);
orderbook_entries.push(ask.as_rpc_v2_entry_ask(address, is_mine));
}
orderbook_entries
Expand Down Expand Up @@ -364,7 +356,7 @@ pub async fn orderbook_rpc_v2(
continue;
},
};
let is_mine = is_my_order(&orderbook.my_p2p_pubkeys, &my_pubsecp, &bid.pubkey);
let is_mine = is_my_order(&bid.pubkey, &my_pubsecp, my_p2p_pubkeys);
orderbook_entries.push(bid.as_rpc_v2_entry_bid(address, is_mine));
}
orderbook_entries
Expand Down
Loading