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

Separate insufficient balance by balance and allowance #3017

Closed
wants to merge 3 commits into from

Conversation

m-lord-renkse
Copy link
Contributor

Description

At the moment we don't differentiate between missing balances and missing allowances and always report insufficient_balance.

Changes

  • Create a new type Balance which contains the balance and allowance
  • Propagate the new type as a result of balance fetching
  • Differentiate errors between insufficient balance and insufficient allowance

How to test

  1. Regression tests
  2. Unit test

Related Issues

Fixes #2886

@m-lord-renkse m-lord-renkse marked this pull request as ready for review September 26, 2024 13:49
@m-lord-renkse m-lord-renkse requested a review from a team as a code owner September 26, 2024 13:49
crates/autopilot/src/solvable_orders.rs Outdated Show resolved Hide resolved
crates/shared/src/order_quoting.rs Outdated Show resolved Hide resolved

/// Removes orders that can't possibly be settled because the allowance is not
/// enough
fn orders_with_allowance(mut orders: Vec<Order>, balances: &Balances) -> Vec<Order> {
Copy link
Contributor

Choose a reason for hiding this comment

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

These functions are on the hot path and are now iterating over the majority of orders twice and doing a hashmap lookup for each one when it could happen in one sweep.
This also results in an almost exactly duplicated function.
Did you already check how you could avoid that?

I believe you could pass in the OrderFilterCounter and use checkpoint_by_invalid_orders() inside by collecting missing balances uids and missing allowance uids into 2 separate vectors.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@MartinquaXD Iterating over orders to match a field should be relatively fast, and without much overhead. I agree it is sub-optimal. I will give it a thought and make it with one iteration. But being that the case, we could also try to make all the checks within one iteration though 🤔 I will draft a proposal. I'll think about it.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

My point is, that we already iterate multiple times over all the orders, and it is more of a general issue rather than an issue of this PR (which is not helping it, since it is adding one iteration more...). But I 100 % agree with you, and this is a good opportunity to come up with something to mitigate it.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@MartinquaXD I wrote a draft proposal (tests are failing on purpose, I would need to clean it up a bit). If you like it/agree, after cleaning it up, rework comments and merged. I can do another PR to apply this to the rest of the filtering, avoiding doing many iterations over the orders, and scratching some time that hopefully one day will come in handy.

@m-lord-renkse m-lord-renkse force-pushed the 2886/filter-order-by-allowance branch from 218468c to a540000 Compare September 27, 2024 13:18
return true;
// The order of checks impacts the order of what we want to filter first / with
// more priority
if invalid_balance(order, balances) {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

We can add here everything which is pre-"price fetching", even the checks which require async functions (like signature check). Eventually this can be an async iterator in which we wait concurrently for the results. Instead of doing each check individually by each check iterating over the orders, we could iterate once and do all the check per order.

By doing it like this, we don't only avoid doing all the iterations for each check, but also all the iterations we do for the counter.checkpoint().

Ultimately we can have another check for the post-"price fetched" checks.

}

/// Returns true if the allowance is invalid for the given order
fn invalid_allowance(order: &Order, balances: &Balances) -> bool {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

we could have all these functions in a different file for better grouping

};
balance >= needed_balance
if invalid_allowance(order, balances) {
filtered_orders.push(("insufficient_allowance", order.metadata.uid));
Copy link
Contributor Author

Choose a reason for hiding this comment

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

we can delegate this action to the functions (invalid_allowance in this case), for a cleaner function body here.

@@ -837,6 +874,39 @@ impl OrderFilterCounter {
filtered_orders.into_keys().collect()
}

/// Creates a new checkpoint based on the found multiply invalid orders.
fn checkpoint_by_multiple_invalid_orders(
Copy link
Contributor Author

Choose a reason for hiding this comment

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

With this function, we just need to iterate over the invalid orders once.

let orders = orders_with_balance(orders, &balances);
let removed = counter.checkpoint("insufficient_balance", &orders);
invalid_order_uids.extend(removed);
let filtered_orders = filter_orders_with_balance(&mut orders, &balances);
Copy link
Contributor Author

@m-lord-renkse m-lord-renkse Sep 27, 2024

Choose a reason for hiding this comment

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

changed the function signature to filter by taking a mutable reference, this way it can returned the filtered order. I am open to make it as before and then return both: filtered orders and orders.

@MartinquaXD
Copy link
Contributor

Seems like we'll remove the balance filtering from the autopilot altogether. Conceptually the autopilot should not filter any orders to not have a centralized judge deciding early which orders are worth spending time on.
This was the case from the start but when we added support for long standing limit orders the orderbook grew a lot. That was problematic because at the time we were not able to keep all the relevant native prices up to date. This changed since then so we should be able to remove this filtering in the autopilot altogether.
In reality this will likely result in us moving the logic into the driver because some sort of filtering/prioritization mechanism still makes sense but not at the core protocol level.

@m-lord-renkse
Copy link
Contributor Author

Seems like we'll remove the balance filtering from the autopilot altogether. Conceptually the autopilot should not filter any orders to not have a centralized judge deciding early which orders are worth spending time on. This was the case from the start but when we added support for long standing limit orders the orderbook grew a lot. That was problematic because at the time we were not able to keep all the relevant native prices up to date. This changed since then so we should be able to remove this filtering in the autopilot altogether. In reality this will likely result in us moving the logic into the driver because some sort of filtering/prioritization mechanism still makes sense but not at the core protocol level.

@MartinquaXD thank you for the detailed explanation. Closing this PR. I can revive part of the code if we plan to move it to the driver in the future.

@github-actions github-actions bot locked and limited conversation to collaborators Oct 3, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

chore: More detailed logs why an order got filtered out
3 participants