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

[ON HOLD] Reject solution containing outside-of-auction order #2712

Closed
wants to merge 4 commits into from

Conversation

sunce86
Copy link
Contributor

@sunce86 sunce86 commented May 9, 2024

ON HOLD since I want to get back to this once I work more on fetching the offchain data from db that will be used in OnSettlementEventUpdater. I already see that I will need a different variation of the orders_do_not_exist functionality for that as well.

Description

Implements first part of the #2667 (comment)

Rejects the winning solution if it contains an order that is not part of the auction. Since JIT orders do not satisfy this condition, we also need to make sure that those that are not in the auction, are also not in the database.

How to test

e2e tests

@sunce86 sunce86 added the E:7.1 Ext. solvers operating driver See https://github.com/cowprotocol/pm/issues/57 for details label May 9, 2024
@sunce86 sunce86 requested a review from a team as a code owner May 9, 2024 15:41
Copy link
Contributor

@MartinquaXD MartinquaXD left a comment

Choose a reason for hiding this comment

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

This concept of this change makes sense to me (prepare data that is needed by circuit breaker to remove winning solver) but I think it's currently susceptible to malicious solvers interfering.

let mut ex = self
.postgres
.pool
.begin()
Copy link
Contributor

Choose a reason for hiding this comment

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

There is only a single DB call so we don't need a transaction here.

Suggested change
.begin()
.acquire()

@@ -755,6 +755,27 @@ pub async fn user_orders_with_quote(
.await
}

pub async fn orders_do_not_exist(
ex: &mut PgConnection,
uids: &[OrderUid],
Copy link
Contributor

Choose a reason for hiding this comment

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

Could take an impl IntoIterator<Item = OrderUid> instead to avoid double allocating the orders vector.

Comment on lines +769 to +773
let mut separated = query_builder.separated(", ");
for value_type in uids {
separated.push_bind(value_type);
}
separated.push_unseparated(")) ");
Copy link
Contributor

Choose a reason for hiding this comment

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

Looks other than the usual query builder code. Is the explicit use of .separated() and push_unseparated() here necessary because we push into the inner query here?


if !self.validate_settlement(&auction, &settlement).await {
tracing::error!(driver = %driver.name, "invalid settlement");
return;
Copy link
Contributor

Choose a reason for hiding this comment

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

Shouldn't we still store all the relevant data for this competition when the solution fails some checks?

.orders_do_not_exist(&non_auction_orders)
.await
.unwrap_or_else(|err| {
tracing::warn!(?err, "failed to check if all orders exist");
Copy link
Contributor

Choose a reason for hiding this comment

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

These checks are pretty important so they should fail loudly IMO (e.g. tracing::error!)

Suggested change
tracing::warn!(?err, "failed to check if all orders exist");
tracing::warn!(?err, "failed to check if all unexpected orders are JIT orders");

}
};

if !self.validate_settlement(&auction, &settlement).await {
Copy link
Contributor

Choose a reason for hiding this comment

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

I think before we enforce any checks like this we should ensure that we await the correct settlement transaction. It's possible that a malicious losing solver would settle a solution with the expected auction_id out of competition.
Currently we just await the next tx that has the expected auction_id attached to its calldata. What we should probably do instead is to make it so that we only await a solution with the expected auction_id that also came from the winning solver.
That way this verification always applies to "real" solution and a malicious solver can't disrupt the main loop.
This disrupting solver would then easily be removed from the next competitions by the circuit breaker. Unfortunately this likely requires a change in the DB because we have a 1:1 mapping between tx_hash and auction_id at the moment whereas it should probably be a 1:1 mapping between tx_hash and (auction_id, solver).

@sunce86 sunce86 self-assigned this May 13, 2024
@sunce86 sunce86 changed the title Reject solution containing outside-of-auction order [ON HOLD] Reject solution containing outside-of-auction order May 13, 2024
Copy link

This pull request has been marked as stale because it has been inactive a while. Please update this pull request or it will be automatically closed.

@github-actions github-actions bot added the stale label May 21, 2024
@github-actions github-actions bot closed this May 29, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
E:7.1 Ext. solvers operating driver See https://github.com/cowprotocol/pm/issues/57 for details
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants