Skip to content

Conversation

@borngraced
Copy link

@borngraced borngraced commented Feb 12, 2025

fix: #2281
handle maker order matching by checking coin connection status and cancel orders it all coin servers are down.

@borngraced borngraced self-assigned this Feb 12, 2025
@borngraced borngraced force-pushed the cancel-offline-electrum-orders branch from b704ba0 to 98f53cc Compare February 12, 2025 23:29
Copy link
Collaborator

@onur-ozkan onur-ozkan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2 nits, LGTM otherwise

@shamardy
Copy link
Collaborator

shamardy commented Feb 27, 2025

@borngraced We need to also broadcast cancellation message when electrum is down and broadcast order created/updated message when the electrum is back again but the fix here #2232 will make this process complicated. So I'm proposing a simpler and probably safer solution.

The proposed solution differs from what @cipig suggested in #2281 (comment). I think it makes more sense to just cancel the orders when electrums are down and the maker can place them again themselves, if electrums are down similar to what happened in a recent swap, it's not safe for the order to go back online automatically leading to a swap with an unstable electrum.

smk762
smk762 previously approved these changes Apr 2, 2025
Copy link
Collaborator

@mariocynicys mariocynicys left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

/// 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() {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this will always return Some. the maintained_connections set is always a subset of all_connection.

u wanna get such a connection and check connection.is_connected() (here)

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@smk762 could u explain what was the test scenario in here: #2357 (comment)

i might be missing something here

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ahaaa, i didn't formulate this correctly in my head. thought this will always return false (so never offline).

but if read_maintained_connections() returns an empty list, then this will return true (all electrums offline). and in fact, checking that read_maintained_connections() is not empty is enough to know that we are connected, i.e. u don't have to check connection.is_connected(), as any maintained connection must be connected (when it disconnects it gets removed from the maintained connections set).

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@smk762 could u explain what was the test scenario in here: #2357 (comment)

i might be missing something here

  1. Launch kdf,
  2. activate coins as usual.
  3. Create a setprice order as maker with an unattractive price so it stays on book.
  4. Check my_orders and confirm presence of the order.
  5. Add node/electrum url to pihole blocklist (temporarily) to mimic a lost connection. Turning off wifi for a bit would likely also work if not using pihole.
  6. Re-check my_orders, and confirm order was auto-cancelled.
  7. Repeat steps 1-5 for other coin types.


/// Checks if there are no live server connections available.
pub fn is_completely_offline(&self) -> bool {
for server in self.read_maintained_connections().iter() {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit:
for (_id, server_address) in maintained_connections { ... }

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

or:
for server_address in maintained_connections.values() { ... }

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?;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

redundant ref on order.

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(_) => false,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should be annotated/cfg-ed for tests only. this breaks cargo check.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done thanks.

base_orderbook_ticker: None,
rel_orderbook_ticker: None,
p2p_privkey: None,

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

an extra line break;
also present in the rest of the file.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks done.

Comment on lines 619 to 622
let mut current_dir = std::env::current_dir().unwrap();
current_dir.pop();
current_dir.pop();
current_dir
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could u write in comments where such current_dir() is.
like:

// this should be: DB_ROOT/x/y/zcash_db/etc..
let mut current_dir = std::env::current_dir().unwrap();
// this is: DB_ROOT/x/y/zcash_db
current_dir.pop();
...

also doesn't this depend on where from these tests are ran?
like, running the tests from the root of the komodo-defi-framework will result in a different current dir than when running from komodo-defi-framework/mm2src/mm2_main or mm2_tests? which would break the .join below?

Copy link
Author

@borngraced borngraced Apr 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

seems like a failed merge conflict.
reverted

Comment on lines 3695 to 3698
if order.available_amount() >= order.min_base_vol || order.has_ongoing_matches() {
if order.has_ongoing_matches() {
continue;
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

has_ongoing_matches is OR-ed in the first if clause and then checked alone in the second.

we could move it out before the available_amount() check.

ordermatch_ctx: &OrdermatchContext,
order: &MakerOrder,
) -> bool {
if let Ok(Some(coin)) = lp_coinfind(ctx, &order.base).await {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think we should also cancel the order if it's not found (tho we also handle it else where i presume). and also cancel it if lp_coinfind errors (just for code simplicity, since we know it shouldn't really error).

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmmm. I believe lp_ordermatch loop will wait till a coin is active before matching etc.

and also cancel it if lp_coinfind errors (just for code simplicity, since we know it shouldn't really error).

And I do not think we want to do this since coin not found seems very different from when it is offline.

@mariocynicys
Copy link
Collaborator

if somebody is using a couple of many unreliable electrums they might lose coin connection for a couple of seconds every now and then. same for when they themselves have unreliable connections.

i would be for just stopping order rebroadcasting and rejecting any taker requests till the coin is back online. removing the orders completely will be some pain in the butt for a maker that went offline for a split second.

@smk762
Copy link

smk762 commented May 7, 2025

if somebody is using a couple of many unreliable electrums they might lose coin connection for a couple of seconds every now and then. same for when they themselves have unreliable connections.

i would be for just stopping order rebroadcasting and rejecting any taker requests till the coin is back online. removing the orders completely will be some pain in the butt for a maker that went offline for a split second.

On the taker side, it is a pain in the butt for a user to match with an order which fails at the negotiation stage. From a guilt/punishment perspective:

  • A coin with unstable electrums imposes negative UX on both maker and taker, and its faults add to support team workload. These should be identified, warned and purged if not up to standard (or replaced with reliable in-house servers if the inclusion of the coin is desirable).
  • A maker with an unstable connection is at fault for their own failure to ensure reliable hardware/isp. If this leads to negotiation fails on a stale order, the taker suffers without contributing to the failure.
  • A taker with an unstable connection selects orders from the book, so cancellation upon connection loss is irrelevant. There is a chance that taker connection interruptions occur while negotiating or performing subsequent swap events, though once a swap is in progress, short connection interruptions generally wont result in a failed swap, assuming connection is active long enough for events / confirmations to be updated (and there is always the watchtowers to help also).

Based on this, IMO auto-cancel on connection loss is justified, though a brief (< 2 sec) window to recheck could be included as a compromise to cover smaller things causing an interruption

@shamardy
Copy link
Collaborator

shamardy commented May 7, 2025

auto-cancel on connection loss is justified, though a brief (< 2 sec) window to recheck could be included as a compromise to cover smaller things causing an interruption

Totally agree to this. Takers order cancelling is no big deal at all as they can place it again straight away and is common even in AMM dexes. For makers, they don't just place orders, they use scripts/tools/bots so auto cancellation is also fine but they should be notified (they probably check order statuses automatically by the script instead) and they will place the orders again later when electrums are back online.

@borngraced
Copy link
Author

if somebody is using a couple of many unreliable electrums they might lose coin connection for a couple of seconds every now and then. same for when they themselves have unreliable connections.
i would be for just stopping order rebroadcasting and rejecting any taker requests till the coin is back online. removing the orders completely will be some pain in the butt for a maker that went offline for a split second.

On the taker side, it is a pain in the butt for a user to match with an order which fails at the negotiation stage. From a guilt/punishment perspective:

* A coin with unstable electrums imposes negative UX on both maker and taker, and its faults add to support team workload. These should be identified, warned and purged if not up to standard (or replaced with reliable in-house servers if the inclusion of the coin is desirable).

* A maker with an unstable connection is at fault for their own failure to ensure reliable hardware/isp. If this leads to negotiation fails on a stale order, the taker suffers without contributing to the failure.

* A taker with an unstable connection selects orders from the book, so cancellation upon connection loss is irrelevant. There is a chance that taker connection interruptions occur while negotiating or performing subsequent swap events, though once a swap is in progress, short connection interruptions generally wont result in a failed swap, assuming connection is active long enough for events / confirmations to be updated (and there is always the watchtowers to help also).

Based on this, IMO auto-cancel on connection loss is justified, though a brief (< 2 sec) window to recheck could be included as a compromise to cover smaller things causing an interruption

I can add retry with sleep which should solve this. cc @shamardy

@smk762
Copy link

smk762 commented Jul 24, 2025

We've been merging dev into this one for a while, and with the current conflict requiring resolution in lp_ordermatch.rs, another one is on the horizon. Is it still on track to be in 2.6.0?

@shamardy
Copy link
Collaborator

We've been merging dev into this one for a while, and with the current conflict requiring resolution in lp_ordermatch.rs, another one is on the horizon. Is it still on track to be in 2.6.0?

Yes, still on track, will give it a look and fix anything myself when I start the finalization of 2.6.0-beta. For now, there will be 2.5.1-beta first for the private key export.

@shamardy shamardy assigned shamardy and unassigned borngraced Jul 30, 2025
@shamardy shamardy marked this pull request as draft July 30, 2025 14:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants