Skip to content

Commit

Permalink
Filter in-flight orders (#2123)
Browse files Browse the repository at this point in the history
# Description
Although the `autopilot` currently waits until the `driver` reports that
the settlement was mined the auction of the next run loop might not yet
be aware that the orders of the previous settlement were solved.
If a solver then tries to solve those orders again it will run into
simulation failures.

# Changes
We now filter out in-flight orders from the auction if it was built
before the block where the in-flight orders were settled.
  • Loading branch information
MartinquaXD authored Dec 5, 2023
1 parent 2a36cf3 commit 593aff3
Show file tree
Hide file tree
Showing 2 changed files with 52 additions and 6 deletions.
1 change: 1 addition & 0 deletions crates/autopilot/src/run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -630,6 +630,7 @@ pub async fn run(args: Arguments) {
score_cap: args.score_cap,
max_settlement_transaction_wait: args.max_settlement_transaction_wait,
solve_deadline: args.solve_deadline,
in_flight_orders: Default::default(),
};
run.run_forever().await;
unreachable!("run loop exited");
Expand Down
57 changes: 51 additions & 6 deletions crates/autopilot/src/run_loop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ use {
model::{
auction::{Auction, AuctionId, AuctionWithId},
interaction::InteractionData,
order::OrderClass,
order::{OrderClass, OrderUid},
solver_competition::{
CompetitionAuction,
Order,
Expand All @@ -30,15 +30,16 @@ use {
},
},
number::nonzero::U256 as NonZeroU256,
primitive_types::{H160, U256},
primitive_types::{H160, H256, U256},
rand::seq::SliceRandom,
shared::{remaining_amounts, token_list::AutoUpdatingTokenList},
std::{
collections::{BTreeMap, HashSet},
sync::Arc,
sync::{Arc, Mutex},
time::{Duration, Instant},
},
tracing::Instrument,
web3::types::TransactionReceipt,
};

pub struct RunLoop {
Expand All @@ -54,6 +55,7 @@ pub struct RunLoop {
pub score_cap: U256,
pub max_settlement_transaction_wait: Duration,
pub solve_deadline: Duration,
pub in_flight_orders: Arc<Mutex<InFlightOrders>>,
}

impl RunLoop {
Expand All @@ -67,7 +69,7 @@ impl RunLoop {
if last_auction_id.replace(id) != Some(id)
|| last_block.replace(current_block) != Some(current_block)
{
self.single_run(id, &auction)
self.single_run(id, auction)
.instrument(tracing::info_span!("auction", id))
.await;
}
Expand Down Expand Up @@ -112,11 +114,13 @@ impl RunLoop {
Some(AuctionWithId { id, auction })
}

async fn single_run(&self, auction_id: AuctionId, auction: &Auction) {
async fn single_run(&self, auction_id: AuctionId, auction: Auction) {
tracing::info!(?auction, "solving");

let auction = self.remove_in_flight_orders(auction).await;

let solutions = {
let mut solutions = self.competition(auction_id, auction).await;
let mut solutions = self.competition(auction_id, &auction).await;
if solutions.is_empty() {
tracing::info!("no solutions for auction");
return;
Expand Down Expand Up @@ -428,6 +432,11 @@ impl RunLoop {
.map_err(SettleError::Failure)?
.tx_hash;

*self.in_flight_orders.lock().unwrap() = InFlightOrders {
tx_hash,
orders: revealed.orders.iter().cloned().collect(),
};

let events = revealed
.orders
.iter()
Expand All @@ -443,6 +452,34 @@ impl RunLoop {
async fn save_competition(&self, competition: &Competition) -> Result<()> {
self.database.save_competition(competition).await
}

/// Removes orders that are currently being settled to avoid solvers trying
/// to fill an order a second time.
async fn remove_in_flight_orders(&self, mut auction: Auction) -> Auction {
let prev_settlement = self.in_flight_orders.lock().unwrap().tx_hash;
let tx_receipt = self.web3.eth().transaction_receipt(prev_settlement).await;

let prev_settlement_block = match tx_receipt {
Ok(Some(TransactionReceipt {
block_number: Some(number),
..
})) => number.0[0],
// Could not find the block of the previous settlement, let's be
// conservative and assume all orders are still in-flight.
_ => u64::MAX,
};

if auction.latest_settlement_block < prev_settlement_block {
// Auction was built before the in-flight orders were processed.
let in_flight_orders = self.in_flight_orders.lock().unwrap();
auction
.orders
.retain(|o| !in_flight_orders.orders.contains(&o.metadata.uid));
tracing::debug!(orders = ?in_flight_orders.orders, "filtered out in-flight orders");
}

auction
}
}

pub fn solve_request(
Expand Down Expand Up @@ -524,6 +561,14 @@ pub fn solve_request(
}
}

/// Orders settled in the previous auction that might still be in-flight.
#[derive(Default)]
pub struct InFlightOrders {
/// The transaction that these orders where settled in.
tx_hash: H256,
orders: HashSet<OrderUid>,
}

struct Participant<'a> {
driver: &'a Driver,
solution: Solution,
Expand Down

0 comments on commit 593aff3

Please sign in to comment.