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

Get token first trade block API #3197

Merged
merged 9 commits into from
Jan 6, 2025
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 52 additions & 0 deletions crates/database/src/trades.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,31 @@ AND t.log_index BETWEEN (SELECT * from previous_settlement) AND $2
.await
}

pub async fn token_first_trade_block(
ex: &mut PgConnection,
token: Address,
) -> Result<Option<i64>, sqlx::Error> {
const QUERY: &str = r#"
SELECT MIN(sub.block_number) AS earliest_block
FROM (
SELECT MIN(t.block_number) AS block_number
FROM trades t
JOIN orders o ON t.order_uid = o.uid
WHERE o.sell_token = $1 OR o.buy_token = $1
MartinquaXD marked this conversation as resolved.
Show resolved Hide resolved

UNION ALL
m-lord-renkse marked this conversation as resolved.
Show resolved Hide resolved

SELECT MIN(t.block_number) AS block_number
FROM trades t
JOIN jit_orders j ON t.order_uid = j.uid
WHERE j.sell_token = $1 OR j.buy_token = $1
) AS sub
"#;

let (block_number,) = sqlx::query_as(QUERY).bind(token).fetch_one(ex).await?;
Ok(block_number)
}

#[cfg(test)]
mod tests {
use {
Expand Down Expand Up @@ -579,4 +604,31 @@ mod tests {
}]
);
}

#[tokio::test]
#[ignore]
async fn postgres_token_first_trade_block() {
let mut db = PgConnection::connect("postgresql://").await.unwrap();
let mut db = db.begin().await.unwrap();
crate::clear_DANGER_(&mut db).await.unwrap();

let token = Default::default();
assert_eq!(token_first_trade_block(&mut db, token).await.unwrap(), None);

let (owners, order_ids) = generate_owners_and_order_ids(2, 2).await;
let event_index_a = EventIndex {
block_number: 123,
log_index: 0,
};
let event_index_b = EventIndex {
block_number: 124,
log_index: 0,
};
add_order_and_trade(&mut db, owners[0], order_ids[0], event_index_a, None, None).await;
add_order_and_trade(&mut db, owners[1], order_ids[1], event_index_b, None, None).await;
assert_eq!(
token_first_trade_block(&mut db, token).await.unwrap(),
Some(123)
);
}
}
9 changes: 8 additions & 1 deletion crates/orderbook/src/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ mod get_order_by_uid;
mod get_order_status;
mod get_orders_by_tx;
mod get_solver_competition;
mod get_token_first_trade_block;
mod get_total_surplus;
mod get_trades;
mod get_user_orders;
Expand Down Expand Up @@ -105,7 +106,13 @@ pub fn handle_all_routes(
),
(
"v1/get_total_surplus",
box_filter(get_total_surplus::get(database)),
box_filter(get_total_surplus::get(database.clone())),
),
(
"v1/get_token_first_trade_block",
box_filter(get_token_first_trade_block::get_token_first_trade_block(
database,
)),
),
];

Expand Down
43 changes: 43 additions & 0 deletions crates/orderbook/src/api/get_token_first_trade_block.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
use {
crate::database::Postgres,
anyhow::Context,
hyper::StatusCode,
primitive_types::H160,
std::convert::Infallible,
warp::{
reply::{json, with_status},
Filter,
Rejection,
},
};

fn get_native_prices_request() -> impl Filter<Extract = (H160,), Error = Rejection> + Clone {
warp::path!("v1" / "token" / H160 / "first_trade_block").and(warp::get())
}

pub fn get_token_first_trade_block(
db: Postgres,
) -> impl Filter<Extract = (super::ApiReply,), Error = Rejection> + Clone {
get_native_prices_request().and_then(move |token: H160| {
let db = db.clone();
async move {
Result::<_, Infallible>::Ok(
match db
.token_first_trade_block(&token)
.await
.context("get_token_first_trade_block error")
{
Ok(Some(block)) => with_status(json(&block), StatusCode::OK),
Ok(None) => with_status(
super::error("NotFound", "no trade for token exists"),
StatusCode::NOT_FOUND,
),
Err(err) => {
tracing::error!(?err, ?token, "Failed to fetch token's first trade block");
crate::api::internal_error_reply()
}
},
)
}
})
}
19 changes: 19 additions & 0 deletions crates/orderbook/src/database/orders.rs
Original file line number Diff line number Diff line change
Expand Up @@ -492,6 +492,25 @@ impl Postgres {
.map(full_order_into_model_order)
.collect::<Result<Vec<_>>>()
}

pub async fn token_first_trade_block(&self, token: &H160) -> Result<Option<u32>> {
let timer = super::Metrics::get()
.database_queries
.with_label_values(&["token_first_trade_block"])
.start_timer();

let mut ex = self.pool.acquire().await?;
let block_number = database::trades::token_first_trade_block(&mut ex, ByteArray(token.0))
.await
.map_err(anyhow::Error::from)?
.map(u32::try_from)
.transpose()
.map_err(anyhow::Error::from)?;

timer.stop_and_record();

Ok(block_number)
}
}

#[async_trait]
Expand Down
3 changes: 3 additions & 0 deletions database/sql/V077__orders_token_indexes.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
CREATE INDEX orders_sell_buy_tokens ON orders (sell_token, buy_token);
Copy link
Contributor Author

@squadgazzz squadgazzz Dec 31, 2024

Choose a reason for hiding this comment

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

A similar composite index already exists:

create index order_quoting_parameters
    on orders (sell_token, buy_token, sell_amount);

But after adding a separate (sell_token, buy_token) index, the execution time improved more than twice.

Copy link
Contributor

Choose a reason for hiding this comment

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

Could you please check how 2 indices (one for sell_token and one for buy_token) behaves?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

There is almost no difference between separate indexes or completely without them.

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 we might have enough indices already to write a fast query for this request.

Copy link
Contributor Author

Choose a reason for hiding this comment

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


CREATE INDEX jit_orders_sell_buy_tokens ON jit_orders (sell_token, buy_token);
Loading