From a0e3ec77746957fb5a21b894d72cc99b12520af6 Mon Sep 17 00:00:00 2001 From: Dusan Stanivukovic Date: Tue, 20 Feb 2024 16:10:52 +0100 Subject: [PATCH] Move driver models into `infra` (#2409) # Description No new functionality. Fixes https://github.com/cowprotocol/services/issues/2286 # Changes Moved driver api model into `infra` Removed quote model since not used. ## How to test Existing e2e tests --- crates/autopilot/src/boundary/mod.rs | 12 +- crates/autopilot/src/driver_model.rs | 187 ------------------ crates/autopilot/src/infra/solvers/dto/mod.rs | 6 + .../autopilot/src/infra/solvers/dto/reveal.rs | 30 +++ .../autopilot/src/infra/solvers/dto/settle.rs | 33 ++++ .../autopilot/src/infra/solvers/dto/solve.rs | 112 +++++++++++ crates/autopilot/src/infra/solvers/mod.rs | 19 +- crates/autopilot/src/lib.rs | 1 - crates/autopilot/src/run_loop.rs | 53 +---- crates/autopilot/src/shadow.rs | 11 +- 10 files changed, 206 insertions(+), 258 deletions(-) delete mode 100644 crates/autopilot/src/driver_model.rs create mode 100644 crates/autopilot/src/infra/solvers/dto/mod.rs create mode 100644 crates/autopilot/src/infra/solvers/dto/reveal.rs create mode 100644 crates/autopilot/src/infra/solvers/dto/settle.rs create mode 100644 crates/autopilot/src/infra/solvers/dto/solve.rs diff --git a/crates/autopilot/src/boundary/mod.rs b/crates/autopilot/src/boundary/mod.rs index 0938c4a8e0..742d16ff0a 100644 --- a/crates/autopilot/src/boundary/mod.rs +++ b/crates/autopilot/src/boundary/mod.rs @@ -1,15 +1,12 @@ -use {crate::domain, ethrpc::Web3, std::collections::HashMap, url::Url}; pub use { - crate::{ - database::{ - competition::Competition, - order_events::{store_order_events, OrderEventLabel}, - }, - driver_model::{reveal, settle, solve}, + crate::database::{ + competition::Competition, + order_events::{store_order_events, OrderEventLabel}, }, database, model::{ app_data::AppDataHash, + bytes_hex, interaction::InteractionData, order::{ BuyTokenDestination, @@ -26,6 +23,7 @@ pub use { }, shared::order_validation::{is_order_outside_market_price, Amounts}, }; +use {crate::domain, ethrpc::Web3, std::collections::HashMap, url::Url}; pub mod events; pub mod order; diff --git a/crates/autopilot/src/driver_model.rs b/crates/autopilot/src/driver_model.rs deleted file mode 100644 index 282dd52ff5..0000000000 --- a/crates/autopilot/src/driver_model.rs +++ /dev/null @@ -1,187 +0,0 @@ -//! Types for communicating with drivers as defined in -//! `crates/driver/openapi.yml`. - -// TODO: parse proper error type with kind and description, that driver returns. - -pub mod quote { - use { - number::serialization::HexOrDecimalU256, - primitive_types::{H160, U256}, - serde::{Deserialize, Serialize}, - serde_with::serde_as, - }; - - #[serde_as] - #[derive(Clone, Debug, Default, Serialize)] - #[serde(rename_all = "camelCase")] - pub struct Request { - pub sell_token: H160, - pub buy_token: H160, - pub kind: Kind, - #[serde_as(as = "HexOrDecimalU256")] - pub amount: U256, - } - - #[derive(Clone, Debug, Default, Serialize)] - #[serde(rename_all = "camelCase")] - pub enum Kind { - #[default] - Buy, - Sell, - } - - #[serde_as] - #[derive(Clone, Debug, Deserialize)] - #[serde(untagged, rename_all = "camelCase", deny_unknown_fields)] - pub enum Response { - Successful { - #[serde_as(as = "HexOrDecimalU256")] - sell_amount: U256, - #[serde_as(as = "HexOrDecimalU256")] - buy_amount: U256, - gas: u64, - }, - Unfillable { - unfillable_reason: String, - }, - } -} - -pub mod solve { - use { - crate::{boundary, infra::persistence::dto::order::Order}, - chrono::{DateTime, Utc}, - number::serialization::HexOrDecimalU256, - primitive_types::{H160, U256}, - serde::{Deserialize, Serialize}, - serde_with::{serde_as, DisplayFromStr}, - std::collections::HashMap, - }; - - #[serde_as] - #[derive(Clone, Debug, Default, Serialize)] - #[serde(rename_all = "camelCase")] - pub struct Request { - #[serde_as(as = "DisplayFromStr")] - pub id: i64, - pub tokens: Vec, - pub orders: Vec, - pub deadline: DateTime, - #[serde_as(as = "HexOrDecimalU256")] - pub score_cap: U256, - } - - #[serde_as] - #[derive(Clone, Debug, Serialize)] - #[serde(rename_all = "camelCase")] - pub struct Token { - pub address: H160, - #[serde_as(as = "Option")] - pub price: Option, - pub trusted: bool, - } - - #[serde_as] - #[derive(Clone, Debug, Default, Deserialize)] - #[serde(rename_all = "camelCase", deny_unknown_fields)] - pub struct TradedAmounts { - /// The effective amount that left the user's wallet including all fees. - #[serde_as(as = "HexOrDecimalU256")] - pub sell_amount: U256, - /// The effective amount the user received after all fees. - #[serde_as(as = "HexOrDecimalU256")] - pub buy_amount: U256, - } - - #[serde_as] - #[derive(Clone, Debug, Default, Deserialize)] - #[serde(rename_all = "camelCase", deny_unknown_fields)] - pub struct Solution { - /// Unique ID of the solution (per driver competition), used to identify - /// it in subsequent requests (reveal, settle). - #[serde_as(as = "serde_with::DisplayFromStr")] - pub solution_id: u64, - #[serde_as(as = "HexOrDecimalU256")] - pub score: U256, - /// Address used by the driver to submit the settlement onchain. - pub submission_address: H160, - pub orders: HashMap, - #[serde_as(as = "HashMap<_, HexOrDecimalU256>")] - pub clearing_prices: HashMap, - } - - #[derive(Clone, Debug, Default, Deserialize)] - #[serde(rename_all = "camelCase", deny_unknown_fields)] - pub struct Response { - pub solutions: Vec, - } -} - -pub mod reveal { - use { - model::bytes_hex, - serde::{Deserialize, Serialize}, - serde_with::serde_as, - }; - - #[serde_as] - #[derive(Clone, Debug, Default, Serialize)] - #[serde(rename_all = "camelCase")] - pub struct Request { - /// Unique ID of the solution (per driver competition), to reveal. - #[serde_as(as = "serde_with::DisplayFromStr")] - pub solution_id: u64, - } - - #[serde_as] - #[derive(Clone, Debug, Default, Deserialize)] - #[serde(rename_all = "camelCase", deny_unknown_fields)] - pub struct Calldata { - #[serde(with = "bytes_hex")] - pub internalized: Vec, - #[serde(with = "bytes_hex")] - pub uninternalized: Vec, - } - - #[derive(Clone, Debug, Default, Deserialize)] - #[serde(rename_all = "camelCase", deny_unknown_fields)] - pub struct Response { - pub calldata: Calldata, - } -} - -pub mod settle { - use { - model::bytes_hex, - primitive_types::H256, - serde::{Deserialize, Serialize}, - serde_with::serde_as, - }; - - #[serde_as] - #[derive(Clone, Debug, Default, Serialize)] - #[serde(rename_all = "camelCase")] - pub struct Request { - /// Unique ID of the solution (per driver competition), to settle. - #[serde_as(as = "serde_with::DisplayFromStr")] - pub solution_id: u64, - } - - #[serde_as] - #[derive(Clone, Debug, Default, Deserialize)] - #[serde(rename_all = "camelCase", deny_unknown_fields)] - pub struct Response { - pub calldata: Calldata, - pub tx_hash: H256, - } - - #[serde_as] - #[derive(Clone, Debug, Default, Deserialize)] - #[serde(rename_all = "camelCase", deny_unknown_fields)] - pub struct Calldata { - #[serde(with = "bytes_hex")] - pub internalized: Vec, - #[serde(with = "bytes_hex")] - pub uninternalized: Vec, - } -} diff --git a/crates/autopilot/src/infra/solvers/dto/mod.rs b/crates/autopilot/src/infra/solvers/dto/mod.rs new file mode 100644 index 0000000000..d3a156294c --- /dev/null +++ b/crates/autopilot/src/infra/solvers/dto/mod.rs @@ -0,0 +1,6 @@ +//! Types for communicating with drivers as defined in +//! `crates/driver/openapi.yml`. + +pub mod reveal; +pub mod settle; +pub mod solve; diff --git a/crates/autopilot/src/infra/solvers/dto/reveal.rs b/crates/autopilot/src/infra/solvers/dto/reveal.rs new file mode 100644 index 0000000000..9f2bc9abbc --- /dev/null +++ b/crates/autopilot/src/infra/solvers/dto/reveal.rs @@ -0,0 +1,30 @@ +use { + crate::boundary::bytes_hex, + serde::{Deserialize, Serialize}, + serde_with::serde_as, +}; + +#[serde_as] +#[derive(Clone, Debug, Default, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct Request { + /// Unique ID of the solution (per driver competition), to reveal. + #[serde_as(as = "serde_with::DisplayFromStr")] + pub solution_id: u64, +} + +#[serde_as] +#[derive(Clone, Debug, Default, Deserialize)] +#[serde(rename_all = "camelCase", deny_unknown_fields)] +pub struct Calldata { + #[serde(with = "bytes_hex")] + pub internalized: Vec, + #[serde(with = "bytes_hex")] + pub uninternalized: Vec, +} + +#[derive(Clone, Debug, Default, Deserialize)] +#[serde(rename_all = "camelCase", deny_unknown_fields)] +pub struct Response { + pub calldata: Calldata, +} diff --git a/crates/autopilot/src/infra/solvers/dto/settle.rs b/crates/autopilot/src/infra/solvers/dto/settle.rs new file mode 100644 index 0000000000..8542b57499 --- /dev/null +++ b/crates/autopilot/src/infra/solvers/dto/settle.rs @@ -0,0 +1,33 @@ +use { + crate::boundary::bytes_hex, + primitive_types::H256, + serde::{Deserialize, Serialize}, + serde_with::serde_as, +}; + +#[serde_as] +#[derive(Clone, Debug, Default, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct Request { + /// Unique ID of the solution (per driver competition), to settle. + #[serde_as(as = "serde_with::DisplayFromStr")] + pub solution_id: u64, +} + +#[serde_as] +#[derive(Clone, Debug, Default, Deserialize)] +#[serde(rename_all = "camelCase", deny_unknown_fields)] +pub struct Response { + pub calldata: Calldata, + pub tx_hash: H256, +} + +#[serde_as] +#[derive(Clone, Debug, Default, Deserialize)] +#[serde(rename_all = "camelCase", deny_unknown_fields)] +pub struct Calldata { + #[serde(with = "bytes_hex")] + pub internalized: Vec, + #[serde(with = "bytes_hex")] + pub uninternalized: Vec, +} diff --git a/crates/autopilot/src/infra/solvers/dto/solve.rs b/crates/autopilot/src/infra/solvers/dto/solve.rs new file mode 100644 index 0000000000..bdb194df23 --- /dev/null +++ b/crates/autopilot/src/infra/solvers/dto/solve.rs @@ -0,0 +1,112 @@ +use { + crate::{ + boundary, + domain, + infra::persistence::{dto, dto::order::Order}, + }, + chrono::{DateTime, Utc}, + itertools::Itertools, + number::serialization::HexOrDecimalU256, + primitive_types::{H160, U256}, + serde::{Deserialize, Serialize}, + serde_with::{serde_as, DisplayFromStr}, + std::{ + collections::{HashMap, HashSet}, + time::Duration, + }, +}; + +impl Request { + pub fn new( + id: domain::AuctionId, + auction: &domain::Auction, + trusted_tokens: &HashSet, + score_cap: U256, + time_limit: Duration, + ) -> Self { + Self { + id, + orders: auction + .orders + .clone() + .into_iter() + .map(dto::order::from_domain) + .collect(), + tokens: auction + .prices + .iter() + .map(|(address, price)| Token { + address: address.to_owned(), + price: Some(price.to_owned()), + trusted: trusted_tokens.contains(address), + }) + .chain(trusted_tokens.iter().map(|&address| Token { + address, + price: None, + trusted: true, + })) + .unique_by(|token| token.address) + .collect(), + deadline: Utc::now() + chrono::Duration::from_std(time_limit).unwrap(), + score_cap, + } + } +} + +#[serde_as] +#[derive(Clone, Debug, Default, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct Request { + #[serde_as(as = "DisplayFromStr")] + pub id: i64, + pub tokens: Vec, + pub orders: Vec, + pub deadline: DateTime, + #[serde_as(as = "HexOrDecimalU256")] + pub score_cap: U256, +} + +#[serde_as] +#[derive(Clone, Debug, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct Token { + pub address: H160, + #[serde_as(as = "Option")] + pub price: Option, + pub trusted: bool, +} + +#[serde_as] +#[derive(Clone, Debug, Default, Deserialize)] +#[serde(rename_all = "camelCase", deny_unknown_fields)] +pub struct TradedAmounts { + /// The effective amount that left the user's wallet including all fees. + #[serde_as(as = "HexOrDecimalU256")] + pub sell_amount: U256, + /// The effective amount the user received after all fees. + #[serde_as(as = "HexOrDecimalU256")] + pub buy_amount: U256, +} + +#[serde_as] +#[derive(Clone, Debug, Default, Deserialize)] +#[serde(rename_all = "camelCase", deny_unknown_fields)] +pub struct Solution { + /// Unique ID of the solution (per driver competition), used to identify + /// it in subsequent requests (reveal, settle). + #[serde_as(as = "serde_with::DisplayFromStr")] + pub solution_id: u64, + #[serde_as(as = "HexOrDecimalU256")] + pub score: U256, + /// Address used by the driver to submit the settlement onchain. + pub submission_address: H160, + pub orders: HashMap, + #[serde_as(as = "HashMap<_, HexOrDecimalU256>")] + pub clearing_prices: HashMap, +} + +#[derive(Clone, Debug, Default, Deserialize)] +#[serde(rename_all = "camelCase", deny_unknown_fields)] +pub struct Response { + pub solutions: Vec, +} diff --git a/crates/autopilot/src/infra/solvers/mod.rs b/crates/autopilot/src/infra/solvers/mod.rs index 0c9ce16f1b..ad597d99a0 100644 --- a/crates/autopilot/src/infra/solvers/mod.rs +++ b/crates/autopilot/src/infra/solvers/mod.rs @@ -1,11 +1,14 @@ use { - crate::{boundary, util}, + self::dto::{reveal, settle, solve}, + crate::util, anyhow::{anyhow, Context, Result}, reqwest::Client, std::time::Duration, url::Url, }; +pub mod dto; + const RESPONSE_SIZE_LIMIT: usize = 10_000_000; const RESPONSE_TIME_LIMIT: Duration = Duration::from_secs(60); @@ -27,25 +30,19 @@ impl Driver { } } - pub async fn solve( - &self, - request: &boundary::solve::Request, - ) -> Result { + pub async fn solve(&self, request: &solve::Request) -> Result { self.request_response("solve", request, None).await } - pub async fn reveal( - &self, - request: &boundary::reveal::Request, - ) -> Result { + pub async fn reveal(&self, request: &reveal::Request) -> Result { self.request_response("reveal", request, None).await } pub async fn settle( &self, - request: &boundary::settle::Request, + request: &settle::Request, timeout: std::time::Duration, - ) -> Result { + ) -> Result { self.request_response("settle", request, Some(timeout)) .await } diff --git a/crates/autopilot/src/lib.rs b/crates/autopilot/src/lib.rs index a86b130f90..02c4253f12 100644 --- a/crates/autopilot/src/lib.rs +++ b/crates/autopilot/src/lib.rs @@ -3,7 +3,6 @@ pub mod boundary; pub mod database; pub mod decoded_settlement; pub mod domain; -pub mod driver_model; pub mod event_updater; pub mod infra; pub mod on_settlement_event_updater; diff --git a/crates/autopilot/src/run_loop.rs b/crates/autopilot/src/run_loop.rs index 000a81d7c9..c55700f959 100644 --- a/crates/autopilot/src/run_loop.rs +++ b/crates/autopilot/src/run_loop.rs @@ -2,20 +2,16 @@ use { crate::{ database::competition::Competition, domain::{self, auction::order::Class, OrderUid}, - driver_model::{ - reveal::{self, Request}, - settle, - solve::{self, TradedAmounts}, + infra::{ + self, + solvers::dto::{reveal, settle, solve}, }, - infra::{self, persistence::dto}, run::Liveness, solvable_orders::SolvableOrdersCache, }, ::observe::metrics, anyhow::Result, - chrono::Utc, database::order_events::OrderEventLabel, - itertools::Itertools, model::solver_competition::{ CompetitionAuction, Order, @@ -308,7 +304,7 @@ impl RunLoop { id: domain::AuctionId, auction: &domain::Auction, ) -> Vec> { - let request = solve_request( + let request = solve::Request::new( id, auction, &self.market_makable_token_list.all(), @@ -399,7 +395,7 @@ impl RunLoop { solution_id: u64, ) -> Result { let response = driver - .reveal(&Request { solution_id }) + .reveal(&reveal::Request { solution_id }) .await .map_err(RevealError::Failure)?; if !response @@ -474,41 +470,6 @@ impl RunLoop { } } -pub fn solve_request( - id: domain::AuctionId, - auction: &domain::Auction, - trusted_tokens: &HashSet, - score_cap: U256, - time_limit: Duration, -) -> solve::Request { - solve::Request { - id, - orders: auction - .orders - .clone() - .into_iter() - .map(dto::order::from_domain) - .collect(), - tokens: auction - .prices - .iter() - .map(|(address, price)| solve::Token { - address: address.to_owned(), - price: Some(price.to_owned()), - trusted: trusted_tokens.contains(address), - }) - .chain(trusted_tokens.iter().map(|&address| solve::Token { - address, - price: None, - trusted: true, - })) - .unique_by(|token| token.address) - .collect(), - deadline: Utc::now() + chrono::Duration::from_std(time_limit).unwrap(), - score_cap, - } -} - /// Orders settled in the previous auction that might still be in-flight. #[derive(Default)] pub struct InFlightOrders { @@ -526,7 +487,7 @@ struct Solution { id: u64, account: H160, score: NonZeroU256, - orders: HashMap, + orders: HashMap, clearing_prices: HashMap, } @@ -535,7 +496,7 @@ impl Solution { self.orders.keys() } - pub fn orders(&self) -> &HashMap { + pub fn orders(&self) -> &HashMap { &self.orders } } diff --git a/crates/autopilot/src/shadow.rs b/crates/autopilot/src/shadow.rs index 0ab7a78106..fe7931b905 100644 --- a/crates/autopilot/src/shadow.rs +++ b/crates/autopilot/src/shadow.rs @@ -10,13 +10,12 @@ use { crate::{ domain::{self, auction::order::Class}, - driver_model::{ - reveal, - solve::{self}, + infra::{ + self, + solvers::dto::{reveal, solve}, }, - infra, run::Liveness, - run_loop::{self, observe}, + run_loop::observe, }, ::observe::metrics, number::nonzero::U256 as NonZeroU256, @@ -190,7 +189,7 @@ impl RunLoop { id: domain::AuctionId, auction: &domain::Auction, ) -> Vec> { - let request = run_loop::solve_request( + let request = solve::Request::new( id, auction, &self.trusted_tokens.all(),