Skip to content

Commit 61240bc

Browse files
[PROPOSAL] Correctly label the orderbook orders metric (#2917)
# Description We need to properly adjust the orderbook `orders` metric. The reason is that we got a false alarm alert, because as it is now, everything is a `limit` order, so we got a period of time in which we got orders (real `limit` ones) and no trades (because those orders were out of market). This could be solved in many ways, as discussed with @MartinquaXD , one way could be to only report "market" orders. But after giving it a deep thought, I think this is the best way, because we don't lose any type of order, and we report all of them labelled correctly. # Changes - Since all the orders are `limit` orders, I changed the `OrderClass` of the `orders` metric to reflect real `limit` orders or `user` orders (order not outside the market price). This way we keep all the orders tracked. I meant this class to be exclusively of the metric system, as we don't intent to store `user` order (aka `market` order) in the domain. But it is handy to have it in the metrics. - Use `strum` to serialize properly the enums - Classify the metric's `OrderClass` accordingly to the quote price if present. ## How to test 1. Checking / adjusting the metrics in grafana in staging --------- Co-authored-by: Martin Beckmann <martin.beckmann@protonmail.com>
1 parent b8e6d79 commit 61240bc

File tree

5 files changed

+293
-42
lines changed

5 files changed

+293
-42
lines changed

Cargo.lock

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/database/src/orders.rs

+121
Original file line numberDiff line numberDiff line change
@@ -489,6 +489,18 @@ pub struct FullOrder {
489489
pub full_app_data: Option<Vec<u8>>,
490490
}
491491

492+
#[derive(Debug, sqlx::FromRow)]
493+
pub struct FullOrderWithQuote {
494+
#[sqlx(flatten)]
495+
pub full_order: FullOrder,
496+
pub quote_buy_amount: Option<BigDecimal>,
497+
pub quote_sell_amount: Option<BigDecimal>,
498+
pub quote_gas_amount: Option<f64>,
499+
pub quote_gas_price: Option<f64>,
500+
pub quote_sell_token_price: Option<f64>,
501+
pub solver: Option<Address>,
502+
}
503+
492504
impl FullOrder {
493505
pub fn valid_to(&self) -> i64 {
494506
if let Some((_, valid_to)) = self.ethflow_data {
@@ -567,6 +579,26 @@ pub async fn single_full_order(
567579
sqlx::query_as(QUERY).bind(uid).fetch_optional(ex).await
568580
}
569581

582+
pub async fn single_full_order_with_quote(
583+
ex: &mut PgConnection,
584+
uid: &OrderUid,
585+
) -> Result<Option<FullOrderWithQuote>, sqlx::Error> {
586+
#[rustfmt::skip]
587+
const QUERY: &str = const_format::concatcp!(
588+
"SELECT ", SELECT,
589+
", o_quotes.sell_amount as quote_sell_amount",
590+
", o_quotes.buy_amount as quote_buy_amount",
591+
", o_quotes.gas_amount as quote_gas_amount",
592+
", o_quotes.gas_price as quote_gas_price",
593+
", o_quotes.sell_token_price as quote_sell_token_price",
594+
", o_quotes.solver as solver",
595+
" FROM ", FROM,
596+
" LEFT JOIN order_quotes o_quotes ON o.uid = o_quotes.order_uid",
597+
" WHERE o.uid = $1",
598+
);
599+
sqlx::query_as(QUERY).bind(uid).fetch_optional(ex).await
600+
}
601+
570602
// Partial query for getting the log indices of events of a single settlement.
571603
//
572604
// This will fail if we ever have multiple settlements in the same transaction
@@ -1238,6 +1270,95 @@ mod tests {
12381270
assert_eq!(quote, quote_);
12391271
}
12401272

1273+
#[tokio::test]
1274+
#[ignore]
1275+
async fn postgres_order_with_quote_roundtrip() {
1276+
let mut db = PgConnection::connect("postgresql://").await.unwrap();
1277+
let mut db = db.begin().await.unwrap();
1278+
crate::clear_DANGER_(&mut db).await.unwrap();
1279+
1280+
let full_order = Order::default();
1281+
insert_order(&mut db, &full_order).await.unwrap();
1282+
let quote = Quote {
1283+
order_uid: Default::default(),
1284+
gas_amount: 1.,
1285+
gas_price: 2.,
1286+
sell_token_price: 3.,
1287+
sell_amount: 4.into(),
1288+
buy_amount: 5.into(),
1289+
solver: ByteArray([1; 20]),
1290+
};
1291+
insert_quote(&mut db, &quote).await.unwrap();
1292+
let order_with_quote = single_full_order_with_quote(&mut db, &quote.order_uid)
1293+
.await
1294+
.unwrap()
1295+
.unwrap();
1296+
assert_eq!(order_with_quote.quote_buy_amount.unwrap(), quote.buy_amount);
1297+
assert_eq!(
1298+
order_with_quote.quote_sell_amount.unwrap(),
1299+
quote.sell_amount
1300+
);
1301+
assert_eq!(order_with_quote.quote_gas_amount.unwrap(), quote.gas_amount);
1302+
assert_eq!(order_with_quote.quote_gas_price.unwrap(), quote.gas_price);
1303+
assert_eq!(
1304+
order_with_quote.quote_sell_token_price.unwrap(),
1305+
quote.sell_token_price
1306+
);
1307+
assert_eq!(order_with_quote.full_order.uid, full_order.uid);
1308+
assert_eq!(order_with_quote.full_order.owner, full_order.owner);
1309+
assert_eq!(
1310+
order_with_quote.full_order.creation_timestamp,
1311+
full_order.creation_timestamp
1312+
);
1313+
assert_eq!(
1314+
order_with_quote.full_order.sell_token,
1315+
full_order.sell_token
1316+
);
1317+
assert_eq!(order_with_quote.full_order.buy_token, full_order.buy_token);
1318+
assert_eq!(
1319+
order_with_quote.full_order.sell_amount,
1320+
full_order.sell_amount
1321+
);
1322+
assert_eq!(
1323+
order_with_quote.full_order.buy_amount,
1324+
full_order.buy_amount
1325+
);
1326+
assert_eq!(order_with_quote.full_order.valid_to, full_order.valid_to);
1327+
assert_eq!(order_with_quote.full_order.app_data, full_order.app_data);
1328+
assert_eq!(
1329+
order_with_quote.full_order.fee_amount,
1330+
full_order.fee_amount
1331+
);
1332+
assert_eq!(
1333+
order_with_quote.full_order.full_fee_amount,
1334+
full_order.full_fee_amount
1335+
);
1336+
assert_eq!(order_with_quote.full_order.kind, full_order.kind);
1337+
assert_eq!(order_with_quote.full_order.class, full_order.class);
1338+
assert_eq!(
1339+
order_with_quote.full_order.partially_fillable,
1340+
full_order.partially_fillable
1341+
);
1342+
assert_eq!(order_with_quote.full_order.signature, full_order.signature);
1343+
assert_eq!(order_with_quote.full_order.receiver, full_order.receiver);
1344+
assert_eq!(
1345+
order_with_quote.full_order.signing_scheme,
1346+
full_order.signing_scheme
1347+
);
1348+
assert_eq!(
1349+
order_with_quote.full_order.settlement_contract,
1350+
full_order.settlement_contract
1351+
);
1352+
assert_eq!(
1353+
order_with_quote.full_order.sell_token_balance,
1354+
full_order.sell_token_balance
1355+
);
1356+
assert_eq!(
1357+
order_with_quote.full_order.buy_token_balance,
1358+
full_order.buy_token_balance
1359+
);
1360+
}
1361+
12411362
#[tokio::test]
12421363
#[ignore]
12431364
async fn postgres_cancel_order() {

crates/orderbook/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ serde = { workspace = true }
4848
serde_json = { workspace = true }
4949
serde_with = { workspace = true }
5050
shared = { path = "../shared" }
51+
strum_macros = "0.26.4"
5152
sqlx = { workspace = true }
5253
thiserror = { workspace = true }
5354
tokio = { workspace = true, features = ["macros", "rt-multi-thread", "signal", "sync", "time"] }

crates/orderbook/src/database/orders.rs

+89-2
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use {
77
database::{
88
byte_array::ByteArray,
99
order_events::{insert_order_event, OrderEvent, OrderEventLabel},
10-
orders::{FullOrder, OrderKind as DbOrderKind},
10+
orders::{self, FullOrder, OrderKind as DbOrderKind},
1111
},
1212
ethcontract::H256,
1313
futures::{stream::TryStreamExt, FutureExt, StreamExt},
@@ -76,13 +76,36 @@ pub trait OrderStoring: Send + Sync {
7676
limit: Option<u64>,
7777
) -> Result<Vec<Order>>;
7878
async fn latest_order_event(&self, order_uid: &OrderUid) -> Result<Option<OrderEvent>>;
79+
async fn single_order_with_quote(&self, uid: &OrderUid) -> Result<Option<OrderWithQuote>>;
7980
}
8081

8182
pub struct SolvableOrders {
8283
pub orders: Vec<Order>,
8384
pub latest_settlement_block: u64,
8485
}
8586

87+
pub struct OrderWithQuote {
88+
pub order: Order,
89+
pub quote: Option<orders::Quote>,
90+
}
91+
92+
impl OrderWithQuote {
93+
pub fn new(order: Order, quote: Option<Quote>) -> Self {
94+
Self {
95+
quote: quote.map(|quote| orders::Quote {
96+
order_uid: ByteArray(order.metadata.uid.0),
97+
gas_amount: quote.data.fee_parameters.gas_amount,
98+
gas_price: quote.data.fee_parameters.gas_price,
99+
sell_token_price: quote.data.fee_parameters.sell_token_price,
100+
sell_amount: u256_to_big_decimal(&quote.sell_amount),
101+
buy_amount: u256_to_big_decimal(&quote.buy_amount),
102+
solver: ByteArray(quote.data.solver.0),
103+
}),
104+
order,
105+
}
106+
}
107+
}
108+
86109
#[derive(Debug)]
87110
pub enum InsertionError {
88111
DuplicatedRecord,
@@ -323,6 +346,51 @@ impl OrderStoring for Postgres {
323346
order.map(full_order_into_model_order).transpose()
324347
}
325348

349+
async fn single_order_with_quote(&self, uid: &OrderUid) -> Result<Option<OrderWithQuote>> {
350+
let _timer = super::Metrics::get()
351+
.database_queries
352+
.with_label_values(&["single_order_with_quote"])
353+
.start_timer();
354+
355+
let mut ex = self.pool.acquire().await?;
356+
let order = orders::single_full_order_with_quote(&mut ex, &ByteArray(uid.0)).await?;
357+
order
358+
.map(|order_with_quote| {
359+
let quote = match (
360+
order_with_quote.quote_buy_amount,
361+
order_with_quote.quote_sell_amount,
362+
order_with_quote.quote_gas_amount,
363+
order_with_quote.quote_gas_price,
364+
order_with_quote.quote_sell_token_price,
365+
order_with_quote.solver,
366+
) {
367+
(
368+
Some(buy_amount),
369+
Some(sell_amount),
370+
Some(gas_amount),
371+
Some(gas_price),
372+
Some(sell_token_price),
373+
Some(solver),
374+
) => Some(orders::Quote {
375+
order_uid: order_with_quote.full_order.uid,
376+
gas_amount,
377+
gas_price,
378+
sell_token_price,
379+
sell_amount,
380+
buy_amount,
381+
solver,
382+
}),
383+
_ => None,
384+
};
385+
386+
Ok(OrderWithQuote {
387+
order: full_order_into_model_order(order_with_quote.full_order)?,
388+
quote,
389+
})
390+
})
391+
.transpose()
392+
}
393+
326394
async fn orders_for_tx(&self, tx_hash: &H256) -> Result<Vec<Order>> {
327395
tokio::try_join!(
328396
self.user_order_for_tx(tx_hash),
@@ -599,6 +667,7 @@ mod tests {
599667
order::{Order, OrderData, OrderMetadata, OrderStatus, OrderUid},
600668
signature::{Signature, SigningScheme},
601669
},
670+
primitive_types::U256,
602671
std::sync::atomic::{AtomicI64, Ordering},
603672
};
604673

@@ -1078,9 +1147,27 @@ mod tests {
10781147
..Default::default()
10791148
};
10801149

1081-
db.insert_order(&order, None).await.unwrap();
1150+
let quote = Quote {
1151+
id: Some(5),
1152+
sell_amount: U256::from(1),
1153+
buy_amount: U256::from(2),
1154+
..Default::default()
1155+
};
1156+
db.insert_order(&order, Some(quote.clone())).await.unwrap();
10821157

10831158
let interactions = db.single_order(&uid).await.unwrap().unwrap().interactions;
10841159
assert_eq!(interactions, order.interactions);
1160+
1161+
// Test `single_order_with_quote`
1162+
let single_order_with_quote = db.single_order_with_quote(&uid).await.unwrap().unwrap();
1163+
assert_eq!(single_order_with_quote.order, order);
1164+
assert_eq!(
1165+
single_order_with_quote.quote.clone().unwrap().sell_amount,
1166+
u256_to_big_decimal(&quote.sell_amount)
1167+
);
1168+
assert_eq!(
1169+
single_order_with_quote.quote.unwrap().buy_amount,
1170+
u256_to_big_decimal(&quote.buy_amount)
1171+
);
10851172
}
10861173
}

0 commit comments

Comments
 (0)