From 31b76418ce8a427294558581b086c2fd4a2d6508 Mon Sep 17 00:00:00 2001 From: Martin Beckmann Date: Tue, 2 Apr 2024 08:20:23 +0200 Subject: [PATCH] Avoid building 2 auctions after restart (#2580) # Description The autopilot periodically builds new auctions via a background task that gets [spawned](https://github.com/cowprotocol/services/blob/main/crates/autopilot/src/solvable_orders.rs#L126-L129) immediately after starting the autopilot. However, it also ["manually"](https://github.com/cowprotocol/services/blob/main/crates/autopilot/src/run.rs#L564-L567) builds 1 auction right at the start. This leads to 2 auctions being built in parallel whenever we restart the autopilot. # Changes Delete "manual" auction building process to do less work on restarts. ## How to test e2e tests --- crates/autopilot/src/run.rs | 5 ---- crates/autopilot/src/solvable_orders.rs | 2 +- crates/e2e/src/setup/services.rs | 26 ++++++++++++++++--- crates/e2e/tests/e2e/buffers.rs | 29 ++++++++++++---------- crates/e2e/tests/e2e/order_cancellation.rs | 15 ++++++----- crates/e2e/tests/e2e/protocol_fee.rs | 2 +- crates/e2e/tests/e2e/solver_competition.rs | 2 +- 7 files changed, 50 insertions(+), 31 deletions(-) diff --git a/crates/autopilot/src/run.rs b/crates/autopilot/src/run.rs index 974eb4e2da..f45fb0925e 100644 --- a/crates/autopilot/src/run.rs +++ b/crates/autopilot/src/run.rs @@ -541,7 +541,6 @@ pub async fn run(args: Arguments) { let persistence = infra::persistence::Persistence::new(args.s3.into().unwrap(), Arc::new(db.clone())).await; - let block = eth.current_block().borrow().number; let solvable_orders_cache = SolvableOrdersCache::new( args.min_order_validity_period, persistence.clone(), @@ -561,10 +560,6 @@ pub async fn run(args: Arguments) { .expect("limit order price factor can't be converted to BigDecimal"), domain::ProtocolFees::new(&args.fee_policies, args.fee_policy_max_partner_fee), ); - solvable_orders_cache - .update(block) - .await - .expect("failed to perform initial solvable orders update"); let liveness = Arc::new(Liveness::new(args.max_auction_age)); shared::metrics::serve_metrics(liveness.clone(), args.metrics_address); diff --git a/crates/autopilot/src/solvable_orders.rs b/crates/autopilot/src/solvable_orders.rs index 083b29e7e7..f88626bbd9 100644 --- a/crates/autopilot/src/solvable_orders.rs +++ b/crates/autopilot/src/solvable_orders.rs @@ -140,7 +140,7 @@ impl SolvableOrdersCache { /// Usually this method is called from update_task. If it isn't, which is /// the case in unit tests, then concurrent calls might overwrite each /// other's results. - pub async fn update(&self, block: u64) -> Result<()> { + async fn update(&self, block: u64) -> Result<()> { let min_valid_to = now_in_epoch_seconds() + self.min_order_validity_period.as_secs() as u32; let db_solvable_orders = self.persistence.solvable_orders(min_valid_to).await?; diff --git a/crates/e2e/src/setup/services.rs b/crates/e2e/src/setup/services.rs index 88374ab9a7..8ee581c965 100644 --- a/crates/e2e/src/setup/services.rs +++ b/crates/e2e/src/setup/services.rs @@ -18,7 +18,7 @@ use { }, reqwest::{Client, StatusCode, Url}, sqlx::Connection, - std::time::Duration, + std::{ops::DerefMut, time::Duration}, }; pub const API_HOST: &str = "http://127.0.0.1:8080"; @@ -127,7 +127,7 @@ impl<'a> Services<'a> { /// (note: specifying a larger solve deadline will impact test times as the /// driver delays the submission of the solution until shortly before the /// deadline in case the solution would start to revert at some point) - pub fn start_autopilot(&self, solve_deadline: Option, extra_args: Vec) { + pub async fn start_autopilot(&self, solve_deadline: Option, extra_args: Vec) { let solve_deadline = solve_deadline.unwrap_or(Duration::from_secs(2)); let args = [ @@ -144,6 +144,7 @@ impl<'a> Services<'a> { let args = autopilot::arguments::Arguments::try_parse_from(args).unwrap(); tokio::task::spawn(autopilot::run(args)); + self.wait_until_autopilot_ready().await; } /// Start the api service in a background tasks. @@ -195,7 +196,8 @@ impl<'a> Services<'a> { args.autopilot, ] .concat(), - ); + ) + .await; self.start_api( [ vec![ @@ -262,7 +264,8 @@ impl<'a> Services<'a> { colocation::start_driver(self.contracts, solvers); - self.start_autopilot(Some(Duration::from_secs(11)), autopilot_args); + self.start_autopilot(Some(Duration::from_secs(11)), autopilot_args) + .await; self.start_api(api_args).await; } @@ -279,6 +282,21 @@ impl<'a> Services<'a> { .expect("waiting for API timed out"); } + async fn wait_until_autopilot_ready(&self) { + let is_up = || async { + let mut db = self.db.acquire().await.unwrap(); + const QUERY: &str = "SELECT COUNT(*) FROM auctions"; + let count: i64 = sqlx::query_scalar(QUERY) + .fetch_one(db.deref_mut()) + .await + .unwrap(); + count > 0 + }; + wait_for_condition(TIMEOUT, is_up) + .await + .expect("waiting for autopilot timed out"); + } + pub async fn get_auction(&self) -> dto::AuctionWithId { let response = self .http diff --git a/crates/e2e/tests/e2e/buffers.rs b/crates/e2e/tests/e2e/buffers.rs index 97f632bc79..6df32152a9 100644 --- a/crates/e2e/tests/e2e/buffers.rs +++ b/crates/e2e/tests/e2e/buffers.rs @@ -54,19 +54,22 @@ async fn onchain_settlement_without_liquidity(web3: Web3) { }], ); let services = Services::new(onchain.contracts()).await; - services.start_autopilot( - None, - vec![ - format!( - "--trusted-tokens={weth:#x},{token_a:#x},{token_b:#x}", - weth = onchain.contracts().weth.address(), - token_a = token_a.address(), - token_b = token_b.address() - ), - "--drivers=test_solver|http://localhost:11088/test_solver".to_string(), - "--price-estimation-drivers=test_quoter|http://localhost:11088/test_solver".to_string(), - ], - ); + services + .start_autopilot( + None, + vec![ + format!( + "--trusted-tokens={weth:#x},{token_a:#x},{token_b:#x}", + weth = onchain.contracts().weth.address(), + token_a = token_a.address(), + token_b = token_b.address() + ), + "--drivers=test_solver|http://localhost:11088/test_solver".to_string(), + "--price-estimation-drivers=test_quoter|http://localhost:11088/test_solver" + .to_string(), + ], + ) + .await; services .start_api(vec![ "--price-estimation-drivers=test_quoter|http://localhost:11088/test_solver".to_string(), diff --git a/crates/e2e/tests/e2e/order_cancellation.rs b/crates/e2e/tests/e2e/order_cancellation.rs index b56778dcdd..ced0e7751a 100644 --- a/crates/e2e/tests/e2e/order_cancellation.rs +++ b/crates/e2e/tests/e2e/order_cancellation.rs @@ -57,12 +57,15 @@ async fn order_cancellation(web3: Web3) { endpoint: solver_endpoint, }], ); - services.start_autopilot( - None, - vec![ - "--price-estimation-drivers=test_quoter|http://localhost:11088/test_solver".to_string(), - ], - ); + services + .start_autopilot( + None, + vec![ + "--price-estimation-drivers=test_quoter|http://localhost:11088/test_solver" + .to_string(), + ], + ) + .await; services .start_api(vec![ "--price-estimation-drivers=test_quoter|http://localhost:11088/test_solver".to_string(), diff --git a/crates/e2e/tests/e2e/protocol_fee.rs b/crates/e2e/tests/e2e/protocol_fee.rs index 5792773824..3ecabffd47 100644 --- a/crates/e2e/tests/e2e/protocol_fee.rs +++ b/crates/e2e/tests/e2e/protocol_fee.rs @@ -495,7 +495,7 @@ async fn execute_test( "--price-estimation-drivers=test_quoter|http://localhost:11088/test_solver".to_string(), ]; config.extend(autopilot_config.iter().map(ToString::to_string)); - services.start_autopilot(None, config); + services.start_autopilot(None, config).await; services .start_api(vec![ "--price-estimation-drivers=test_quoter|http://localhost:11088/test_solver".to_string(), diff --git a/crates/e2e/tests/e2e/solver_competition.rs b/crates/e2e/tests/e2e/solver_competition.rs index 4d783c7592..edc6e6e287 100644 --- a/crates/e2e/tests/e2e/solver_competition.rs +++ b/crates/e2e/tests/e2e/solver_competition.rs @@ -65,7 +65,7 @@ async fn solver_competition(web3: Web3) { .to_string(), "--price-estimation-drivers=test_quoter|http://localhost:11088/test_solver,solver2|http://localhost:11088/solver2".to_string(), ], - ); + ).await; services.start_api(vec![ "--price-estimation-drivers=test_quoter|http://localhost:11088/test_solver,solver2|http://localhost:11088/solver2".to_string(), ]).await;