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

Fetch solver that created settlement transaction #3003

Merged
merged 14 commits into from
Sep 26, 2024
1 change: 0 additions & 1 deletion crates/autopilot/src/database.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ pub mod fee_policies;
pub mod onchain_order_events;
pub mod order_events;
mod quotes;
pub mod recent_settlements;

#[derive(Debug, Clone)]
pub struct Config {
Expand Down
19 changes: 0 additions & 19 deletions crates/autopilot/src/database/recent_settlements.rs

This file was deleted.

30 changes: 18 additions & 12 deletions crates/autopilot/src/infra/persistence/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -179,20 +179,26 @@ impl Persistence {
ex.commit().await.context("commit")
}

/// For a given auction, finds all settlements and returns their transaction
/// hashes.
pub async fn find_settlement_transactions(
/// For a given auction and solver, tries to find the settlement
/// transaction.
pub async fn find_settlement_transaction(
&self,
auction_id: i64,
) -> Result<Vec<eth::TxId>, DatabaseError> {
Ok(self
.postgres
.find_settlement_transactions(auction_id)
.await
.map_err(DatabaseError)?
.into_iter()
.map(eth::TxId)
.collect())
solver: eth::Address,
) -> Result<Option<eth::TxId>, DatabaseError> {
let _timer = Metrics::get()
.database_queries
.with_label_values(&["find_settlement_transaction"])
.start_timer();

let mut ex = self.postgres.pool.acquire().await.context("acquire")?;
Ok(database::settlements::find_settlement_transaction(
&mut ex,
auction_id,
ByteArray(solver.0 .0),
)
.await?
.map(|hash| H256(hash.0).into()))
}

/// Checks if an auction already has an accociated settlement.
Expand Down
75 changes: 37 additions & 38 deletions crates/autopilot/src/run_loop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,7 @@ impl RunLoop {
.extend(solved_order_uids.clone());

let solution_id = solution.id();
let solver = solution.solver();
let self_ = self.clone();
let driver_ = driver.clone();

Expand All @@ -298,14 +299,15 @@ impl RunLoop {
&driver_,
solution_id,
solved_order_uids,
solver,
auction_id,
block_deadline,
)
.await
{
Ok(tx_hash) => {
Metrics::settle_ok(&driver_, submission_start.elapsed());
tracing::debug!(?tx_hash, driver = %driver_.name, "solution settled");
tracing::debug!(?tx_hash, driver = %driver_.name, ?solver, "solution settled");
}
Err(err) => {
Metrics::settle_err(&driver_, submission_start.elapsed(), &err);
Expand Down Expand Up @@ -751,14 +753,35 @@ impl RunLoop {
driver: &infra::Driver,
solution_id: u64,
solved_order_uids: HashSet<OrderUid>,
solver: eth::Address,
auction_id: i64,
submission_deadline_latest_block: u64,
) -> Result<TxId, SettleError> {
let request = settle::Request {
solution_id,
submission_deadline_latest_block,
};
let result = self.wait_for_settlement(driver, auction_id, request).await;

// Wait for either the settlement transaction to be mined or the driver returned
// a result.
let result = match futures::future::select(
Copy link
Contributor

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

Choose a reason for hiding this comment

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

why to move it out of the function? if so, please, conserve the function comment as this code is not trivial

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I felt like settle function is too short and there is a point in inlining the wait_for_settlement.

This becomes painful when we forward bunch of arguments to inner functions.

Box::pin(self.wait_for_settlement_transaction(
auction_id,
self.config.submission_deadline,
solver,
)),
Box::pin(driver.settle(&request, self.config.max_settlement_transaction_wait)),
)
.await
{
futures::future::Either::Left((res, _)) => res,
futures::future::Either::Right((driver_result, wait_for_settlement_transaction)) => {
match driver_result {
Ok(_) => wait_for_settlement_transaction.await,
Err(err) => Err(SettleError::Failure(err)),
}
}
};

// Clean up the in-flight orders regardless the result.
self.in_flight_orders
Expand All @@ -769,41 +792,16 @@ impl RunLoop {
result
}

/// Wait for either the settlement transaction to be mined or the driver
/// returned a result.
async fn wait_for_settlement(
&self,
driver: &infra::Driver,
auction_id: i64,
request: settle::Request,
) -> Result<eth::TxId, SettleError> {
match futures::future::select(
Box::pin(
self.wait_for_settlement_transaction(auction_id, self.config.submission_deadline),
),
Box::pin(driver.settle(&request, self.config.max_settlement_transaction_wait)),
)
.await
{
futures::future::Either::Left((res, _)) => res,
futures::future::Either::Right((driver_result, onchain_task)) => {
driver_result.map_err(|err| {
tracing::warn!(?err, "driver settle request failed");
SettleError::Failure(err)
})?;
onchain_task.await
}
}
}

/// Tries to find a `settle` contract call with calldata ending in `tag`.
/// Tries to find a `settle` contract call with calldata ending in `tag` and
/// originated from the `solver`.
///
/// Returns None if no transaction was found within the deadline or the task
/// is cancelled.
async fn wait_for_settlement_transaction(
&self,
auction_id: i64,
max_blocks_wait: u64,
solver: eth::Address,
) -> Result<eth::TxId, SettleError> {
let current = self.eth.current_block().borrow().number;
let deadline = current.saturating_add(max_blocks_wait);
Expand All @@ -816,17 +814,18 @@ impl RunLoop {

match self
.persistence
.find_settlement_transactions(auction_id)
.find_settlement_transaction(auction_id, solver)
.await
{
Ok(hashes) if hashes.is_empty() => {}
Ok(hashes) => {
if let Some(hash) = hashes.into_iter().next() {
return Ok(hash);
}
}
Ok(Some(transaction)) => return Ok(transaction),
Ok(None) => {}
Err(err) => {
tracing::warn!(?err, "failed to fetch recent settlement tx hashes");
tracing::warn!(
?err,
?auction_id,
?solver,
"failed to find settlement transaction"
);
}
}
if block.number >= deadline {
Expand Down
33 changes: 10 additions & 23 deletions crates/database/src/settlements.rs
Original file line number Diff line number Diff line change
@@ -1,37 +1,24 @@
use {
crate::{events::EventIndex, PgTransaction, TransactionHash},
crate::{Address, PgTransaction, TransactionHash},
sqlx::{Executor, PgConnection},
};

pub async fn get_hash_by_event(
ex: &mut PgConnection,
event: &EventIndex,
) -> Result<TransactionHash, sqlx::Error> {
const QUERY: &str = r#"
SELECT tx_hash
FROM settlements
WHERE
block_number = $1 AND
log_index = $2
"#;
sqlx::query_scalar::<_, TransactionHash>(QUERY)
.bind(event.block_number)
.bind(event.log_index)
.fetch_one(ex)
.await
}

pub async fn get_hashes_by_auction_id(
pub async fn find_settlement_transaction(
ex: &mut PgConnection,
auction_id: i64,
) -> Result<Vec<TransactionHash>, sqlx::Error> {
solver: Address,
) -> Result<Option<TransactionHash>, sqlx::Error> {
const QUERY: &str = r#"
SELECT tx_hash
FROM settlements
WHERE
auction_id = $1
auction_id = $1 AND solver = $2
"#;
sqlx::query_as(QUERY).bind(auction_id).fetch_all(ex).await
sqlx::query_as(QUERY)
.bind(auction_id)
.bind(solver)
.fetch_optional(ex)
.await
}

#[derive(Debug, sqlx::FromRow)]
Expand Down
Loading