Skip to content

Commit 04f4e63

Browse files
MartinquaXDm-szsquadgazzz
authored
Make metrics based bad order detection order specific (#4021)
# Description Currently the bad token detection assumes that we are perfectly able to detect "broken" orders and only orders that trade specific tokens that a particular solver is not able to handle cause problems. However this assumption does not work well with the increasing complexity of new order types that can suddenly start failing for any number of reasons. The most prominent recent example were flashloan orders where the EIP 1271 signature verified correctly but transferring the tokens into the settlement contract failed because the user's Aave debt position was not healthy enough. Our current logic caused a lot of collateral damage because such orders could cause many reasonable tokens to be flagged as unsupported although the tokens themselves were perfectly fine and only that particular order was problematic. # Changes To address this this PR change the metrics based detection mechanism to only flag on an order by order basis instead flagging all orders trading specific tokens. The change itself is relatively simple (collect metrics keyed by `Uid` instead of token`) but came with a few related changes: * the name `bad_token_detection` is now incorrect in most (but not all!) cases so many things were renamed * this includes a few config parameters so they must be updated in the infra repo as well! * caching uids has a lot more potential to bloat the cache so a cache eviction task was introduced, this required 2 new config parameters (max_age, gc_interval) ## How to test - adjusted existing unit to make sure the metrics logic still works correctly with `Uid` - added a new unit test for the cache eviction ## Related issues Fixes #4019 --------- Co-authored-by: Marcin Szymczak <mail@marszy.com> Co-authored-by: ilya <ilya@cow.fi>
1 parent 1cb027a commit 04f4e63

File tree

18 files changed

+456
-287
lines changed

18 files changed

+456
-287
lines changed

crates/driver/src/domain/competition/bad_tokens/metrics.rs

Lines changed: 0 additions & 175 deletions
This file was deleted.

crates/driver/src/domain/competition/mod.rs

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,9 @@ use {
3737
};
3838

3939
pub mod auction;
40-
pub mod bad_tokens;
4140
pub mod order;
4241
mod pre_processing;
42+
pub mod risk_detector;
4343
pub mod solution;
4444
pub mod sorting;
4545

@@ -65,7 +65,8 @@ pub struct Competition {
6565
pub mempools: Mempools,
6666
/// Cached solutions with the most recent solutions at the front.
6767
pub settlements: Mutex<VecDeque<Settlement>>,
68-
pub bad_tokens: Arc<bad_tokens::Detector>,
68+
/// bad token and orders detector
69+
pub risk_detector: Arc<risk_detector::Detector>,
6970
fetcher: Arc<pre_processing::DataAggregator>,
7071
settle_queue: mpsc::Sender<SettleRequest>,
7172
order_sorting_strategies: Vec<Arc<dyn sorting::SortingStrategy>>,
@@ -80,7 +81,7 @@ impl Competition {
8081
liquidity_sources_notifier: infra::notify::liquidity_sources::Notifier,
8182
simulator: Simulator,
8283
mempools: Mempools,
83-
bad_tokens: Arc<bad_tokens::Detector>,
84+
risk_detector: Arc<risk_detector::Detector>,
8485
fetcher: Arc<DataAggregator>,
8586
order_sorting_strategies: Vec<Arc<dyn sorting::SortingStrategy>>,
8687
) -> Arc<Self> {
@@ -95,7 +96,7 @@ impl Competition {
9596
mempools,
9697
settlements: Default::default(),
9798
settle_queue: settle_sender,
98-
bad_tokens,
99+
risk_detector,
99100
fetcher,
100101
order_sorting_strategies,
101102
});
@@ -233,7 +234,10 @@ impl Competition {
233234
.into_iter()
234235
.map(|solution| async move {
235236
let id = solution.id().clone();
236-
let token_pairs = solution.token_pairs();
237+
let orders: Vec<_> = solution
238+
.user_trades()
239+
.map(|trade| trade.order().uid)
240+
.collect();
237241
observe::encoding(&id);
238242
let settlement = solution
239243
.encode(
@@ -243,19 +247,19 @@ impl Competition {
243247
self.solver.solver_native_token(),
244248
)
245249
.await;
246-
(id, token_pairs, settlement)
250+
(id, orders, settlement)
247251
})
248252
.collect::<FuturesUnordered<_>>()
249-
.filter_map(|(id, token_pairs, result)| async move {
253+
.filter_map(|(id, orders, result)| async move {
250254
match result {
251255
Ok(solution) => {
252-
self.bad_tokens.encoding_succeeded(&token_pairs);
256+
self.risk_detector.encoding_succeeded(&orders);
253257
Some(solution)
254258
}
255259
// don't report on errors coming from solution merging
256260
Err(_err) if id.solutions().len() > 1 => None,
257261
Err(err) => {
258-
self.bad_tokens.encoding_failed(&token_pairs);
262+
self.risk_detector.encoding_failed(&orders);
259263
observe::encoding_failed(self.solver.name(), &id, &err);
260264
notify::encoding_failed(&self.solver, auction.id(), &id, &err);
261265
None
@@ -741,7 +745,7 @@ impl Competition {
741745
if !self.solver.config().flashloans_enabled {
742746
auction.orders.retain(|o| o.app_data.flashloan().is_none());
743747
}
744-
self.bad_tokens
748+
self.risk_detector
745749
.filter_unsupported_orders_in_auction(auction)
746750
.await
747751
}

crates/driver/src/domain/competition/order/mod.rs

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -208,16 +208,32 @@ impl From<&solvers_dto::solution::OrderUid> for Uid {
208208
}
209209

210210
impl Uid {
211+
pub fn from_parts(order_hash: eth::B256, owner: eth::Address, valid_to: u32) -> Self {
212+
let mut bytes = [0; UID_LEN];
213+
bytes[0..32].copy_from_slice(order_hash.as_slice());
214+
bytes[32..52].copy_from_slice(owner.as_slice());
215+
bytes[52..56].copy_from_slice(&valid_to.to_be_bytes());
216+
Self(Bytes(bytes))
217+
}
218+
219+
/// Address that authorized the order. Sell tokens will be taken
220+
/// from that address.
211221
pub fn owner(&self) -> eth::Address {
212222
self.parts().1
213223
}
214224

225+
/// Returns a UNIX timestamp after which the settlement
226+
/// contract will not allow the order to be settled anymore.
227+
pub fn valid_to(&self) -> u32 {
228+
self.parts().2
229+
}
230+
215231
/// Splits an order UID into its parts.
216232
fn parts(&self) -> (eth::B256, eth::Address, u32) {
217233
(
218234
eth::B256::from_slice(&self.0.0[0..32]),
219235
eth::Address::from_slice(&self.0.0[32..52]),
220-
u32::from_le_bytes(self.0.0[52..].try_into().unwrap()),
236+
u32::from_be_bytes(self.0.0[52..].try_into().unwrap()),
221237
)
222238
}
223239
}

0 commit comments

Comments
 (0)