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

[r2r] Zhtlc orders is_mine bug #1489

Merged
merged 35 commits into from
Oct 18, 2022
Merged

[r2r] Zhtlc orders is_mine bug #1489

merged 35 commits into from
Oct 18, 2022

Conversation

laruh
Copy link
Member

@laruh laruh commented Oct 3, 2022

ZHTLC orders have ismine:false #1461

"is_mine":true for orderbooks with ZHTLC coins when we use methods: setprice, sell, buy.

Deadlock could appear even, when we have one order with ZHTLC coin.
When deadlock happens, we can not sell ZHTLC or buy other coin with ZHTLC. We can use sell or setprice for other coin with rel ZOMBIE and buy ZOMBIE. However, in other cases nothing happens, command just doesn't fail or pass.
For me deadlock happened after 2.5 hours after ZOMBIE activation.
After deadlock we cannot enable ZOMBIE again, it stucks on UpdatingBlocksCache stage (InProgress issue). We have to delete DB cache from folder to fix it.

@laruh laruh changed the title [wip] Zhtlc orders is_mine bug [r2r] Zhtlc orders is_mine bug Oct 4, 2022
@laruh laruh requested a review from artemii235 October 4, 2022 09:06
Copy link
Member

@artemii235 artemii235 left a comment

Choose a reason for hiding this comment

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

It also turns out that OnCompactBlockFn doesn't have to be Sync, so blocks_db doesn't need to be wrapped in Mutex. Please add this diff to the current PR: bea93bc

mm2src/mm2_main/src/lp_ordermatch/orderbook_rpc.rs Outdated Show resolved Hide resolved
@laruh laruh changed the title [r2r] Zhtlc orders is_mine bug [wip] Zhtlc orders is_mine bug Oct 5, 2022
@laruh laruh changed the title [wip] Zhtlc orders is_mine bug [r2r] Zhtlc orders is_mine bug Oct 11, 2022
Copy link
Member

@artemii235 artemii235 left a comment

Choose a reason for hiding this comment

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

Next review iteration 🙂

mm2src/mm2_main/src/lp_ordermatch/orderbook_rpc.rs Outdated Show resolved Hide resolved
mm2src/mm2_main/src/lp_ordermatch/orderbook_rpc.rs Outdated Show resolved Hide resolved
mm2src/mm2_main/src/lp_ordermatch/orderbook_rpc.rs Outdated Show resolved Hide resolved
Copy link
Member

@artemii235 artemii235 left a comment

Choose a reason for hiding this comment

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

Few more notes.

mm2src/mm2_main/src/lp_ordermatch.rs Outdated Show resolved Hide resolved
mm2src/mm2_main/src/lp_ordermatch.rs Outdated Show resolved Hide resolved
mm2src/mm2_main/src/lp_ordermatch.rs Outdated Show resolved Hide resolved
mm2src/mm2_main/src/lp_ordermatch.rs Outdated Show resolved Hide resolved
mm2src/mm2_main/src/lp_ordermatch.rs Outdated Show resolved Hide resolved
mm2src/mm2_main/src/lp_ordermatch.rs Outdated Show resolved Hide resolved
artemii235
artemii235 previously approved these changes Oct 13, 2022
Copy link
Member

@artemii235 artemii235 left a comment

Choose a reason for hiding this comment

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

Thanks for the fixes, great work!

@artemii235
Copy link
Member

@ozkanonur Could you take a look too, please?

Copy link
Member

@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.

Thanks for the fix!

Only one blocker.

// 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.
// We can compare pubkeys from maker_orders and from asks or bids, to find our order.
pub fn is_my_order(my_orders_pubkeys: &HashSet<String>, my_pub: &Option<String>, order_pubkey: &str) -> bool {
Copy link
Member

Choose a reason for hiding this comment

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

It's only used in the current module, therefore we can avoid defining the function as pub. It could be also great if you can inline this function.

Copy link
Member Author

Choose a reason for hiding this comment

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

oh, I see, this function should be private.
But in this case, its not so necessary to inline private function according to Kladov's explanation and recommendations
As main usage of #[inline] comes from — it enables cross-crate inlining.
it usually isn’t necessary to apply #[inline] to private functions — within a crate, the compiler generally makes good inline decisions.. There’s a joke that LLVM’s heuristic for when the function should be inlined is “yes”.

Please, correct me, if I'm wrong in my understanding.

Copy link
Member

Choose a reason for hiding this comment

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

oh, I see, this function should be private. But in this case, its not so necessary to inline private function according to Kladov's explanation and recommendations As main usage of #[inline] comes from — it enables cross-crate inlining. it usually isn’t necessary to apply #[inline] to private functions — within a crate, the compiler generally makes good inline decisions.. There’s a joke that LLVM’s heuristic for when the function should be inlined is “yes”.

Please, correct me, if I'm wrong in my understanding.

If you want to make an order to compiler that function should be inlined, then you use #[inline(always)].

If you want to suggest to compiler that function should be inlined, then you use #[inline] without any flag.

If you want to make an order to compiler that function should never be inlined, then you use #[inline(never)]

If the function is public, without inline/inline(always) attribute it will never be inlined to external crates unless you are using link time optimizations.
But that doesn't mean all in-crate functions are inlined. Inline attributes are useful even for private functions if needed.

Anyway, in this example because of the function context is all about comparison, I can tell you this function will be inlined by the compiler even if you don't give an attribute.
But I personally start giving inline suggestions(or using always flag for strict order) to compiler for even private functions. Because as I said it might not be inlined without giving attribute, and in case you will need to do some compiler or binary level optimizations, you will have less magical/high-level behaviours from compiler without having any knowladge.

Copy link
Member Author

Choose a reason for hiding this comment

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

Oh, got your point. I added #[inline(always)].

Copy link

@sergeyboyko0791 sergeyboyko0791 left a comment

Choose a reason for hiding this comment

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

Great work!
Just one question and a few minor changes

mm2src/mm2_main/src/lp_ordermatch.rs Outdated Show resolved Hide resolved
@@ -140,6 +144,7 @@ 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 orderbook = ordermatch_ctx.orderbook.lock();
let my_orders_pubkeys = ordermatch_ctx.my_p2p_pubkeys.lock();

Choose a reason for hiding this comment

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

We can clone the my_p2p_pubkeys collection to avoid deadlocks

Copy link
Member

@artemii235 artemii235 Oct 13, 2022

Choose a reason for hiding this comment

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

Cloning can introduce data inconsistency.
As an alternative, we can try moving my_p2p_pubkeys to the orderbook. It will fit the Orderbook structure context.

Copy link
Member

Choose a reason for hiding this comment

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

Cloning MutexGuard should be safe.

If we can do something like:

diff --git a/mm2src/mm2_main/src/lp_ordermatch/orderbook_rpc.rs b/mm2src/mm2_main/src/lp_ordermatch/orderbook_rpc.rs
index dbebf4078..484cc4f9f 100644
--- a/mm2src/mm2_main/src/lp_ordermatch/orderbook_rpc.rs
+++ b/mm2src/mm2_main/src/lp_ordermatch/orderbook_rpc.rs
@@ -311,7 +311,6 @@ pub async fn orderbook_rpc_v2(
         .map_to_mm(OrderbookRpcError::P2PSubscribeError)?;

     let orderbook = ordermatch_ctx.orderbook.lock();
-    let my_orders_pubkeys = ordermatch_ctx.my_p2p_pubkeys.lock();
     let my_pubsecp = ctx.secp256k1_key_pair_as_option().map(|_| {
         CryptoCtx::from_ctx(&ctx)
             .expect("ctx is available")
@@ -337,7 +336,7 @@ pub async fn orderbook_rpc_v2(
                         continue;
                     },
                 };
-                let is_mine = is_my_order(&my_orders_pubkeys, &my_pubsecp, &ask.pubkey);
+                let is_mine = is_my_order(&ordermatch_ctx.my_p2p_pubkeys.lock(), &my_pubsecp, &ask.pubkey);
                 orderbook_entries.push(ask.as_rpc_v2_entry_ask(address, is_mine));
             }
             orderbook_entries
@@ -367,7 +366,7 @@ pub async fn orderbook_rpc_v2(
                         continue;
                     },
                 };
-                let is_mine = is_my_order(&my_orders_pubkeys, &my_pubsecp, &bid.pubkey);
+                let is_mine = is_my_order(&ordermatch_ctx.my_p2p_pubkeys.lock(), &my_pubsecp, &bid.pubkey);
                 orderbook_entries.push(bid.as_rpc_v2_entry_bid(address, is_mine));
             }
             orderbook_entries

We can avoid leaving my_p2p_pubkeys as locked for longer than we need.

Choose a reason for hiding this comment

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

Since we lock the OrdermatchContext::orderbook mutex, we can be sure that it won't change during this function executes. Hence the my_p2p_pubkeys collection won't change.
Am I missing something?

Cloning can introduce data inconsistency.

Copy link
Member

@artemii235 artemii235 Oct 14, 2022

Choose a reason for hiding this comment

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

@sergeyboyko0791 These mutexes are not locked simultaneously in all cases. For example:
https://github.com/KomodoPlatform/atomicDEX-API/blob/33fdfe8ff64093744454587da5babd9f07019ed1/mm2src/mm2_main/src/lp_ordermatch.rs#L4479-L4490

So here, orderbook is locked in maker_order_created_p2p_notify and a new order is added there. It seems that we already have data inconsistency because there is a time window when order is already in the Orderbook, but its pubkey is not in my_p2p_pubkeys, so we can get a wrong is_mine:false from RPC.

I think it's one more reason to move my_p2p_pubkeys to Orderbook, create fn like

fn insert_or_update_order_my(ctx: &MmArc, item: OrderbookItem, my_order: &MakerOrder) {
    let ordermatch_ctx = OrdermatchContext::from_ctx(ctx).expect("from_ctx failed");
    let mut orderbook = ordermatch_ctx.orderbook.lock();
    orderbook.insert_or_update_order_update_trie(item);
    if let Some(key) = my_order.p2p_privkey {
        orderbook.my_p2p_pubkeys.insert(hex::encode(key.public_slice()));
    }
}

And use it in maker_order_created_p2p_notify.

Choose a reason for hiding this comment

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

Now I see what you meant by data inconsistency!

I like this idea

I think it's one more reason to move my_p2p_pubkeys to Orderbook, create fn like

Copy link
Member

Choose a reason for hiding this comment

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

@laruh could you please implement the forementioned change suggestion? 🙂

Copy link
Member Author

@laruh laruh Oct 16, 2022

Choose a reason for hiding this comment

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

Moved my_p2p_pubkeys to Orderbook.
In accordance with the keys addition in maker_order_created_p2p_notify, we remove pubkeys in maker_order_cancelled_p2p_notify. In addition, I decided to keep adding pubkeys in orders_kick_start function.

Only one moment. In fn lp_ordermatch_loop we use maker_order_created_p2p_notify to notify other nodes, and later we use only delete_my_maker_order function. I think to some extent we could have data inconsistency. But as Sergey said forgetting to delete the data is not as bad as skipping it.

@@ -306,6 +311,7 @@ pub async fn orderbook_rpc_v2(
.map_to_mm(OrderbookRpcError::P2PSubscribeError)?;

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

Choose a reason for hiding this comment

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

Here the same

mm2src/mm2_main/src/mm2_tests.rs Show resolved Hide resolved
Copy link
Member

@artemii235 artemii235 left a comment

Choose a reason for hiding this comment

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

This likely last review iteration 🙂

mm2src/mm2_main/src/lp_ordermatch.rs Outdated Show resolved Hide resolved
@laruh laruh changed the title [r2r] Zhtlc orders is_mine bug [wip] Zhtlc orders is_mine bug Oct 17, 2022
@laruh laruh changed the title [wip] Zhtlc orders is_mine bug [r2r] Zhtlc orders is_mine bug Oct 17, 2022
Copy link
Member

@artemii235 artemii235 left a comment

Choose a reason for hiding this comment

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

Good work, thanks! @sergeyboyko0791 @ozkanonur waiting for your next review iterations 🙂

Copy link

@sergeyboyko0791 sergeyboyko0791 left a comment

Choose a reason for hiding this comment

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

Awesome!

Copy link
Member

@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.

LGTM

@artemii235 artemii235 merged commit 62b1653 into dev Oct 18, 2022
@artemii235 artemii235 deleted the ZHTLC_orders_ismine_bug branch October 18, 2022 12:46
@laruh laruh mentioned this pull request Feb 21, 2023
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.

4 participants