Skip to content

Commit

Permalink
Add driver submission driver to the autopilot
Browse files Browse the repository at this point in the history
  • Loading branch information
m-lord-renkse committed Oct 17, 2024
1 parent 1c8c14f commit 42bf53a
Show file tree
Hide file tree
Showing 5 changed files with 141 additions and 12 deletions.
9 changes: 8 additions & 1 deletion crates/autopilot/src/infra/solvers/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,17 @@ pub struct Driver {
// winning solution should be discarded if it contains at least one order, which
// another driver solved with surplus exceeding this driver's surplus by `threshold`
pub fairness_threshold: Option<eth::Ether>,
pub submission_address: Option<eth::Address>,
client: Client,
}

impl Driver {
pub fn new(url: Url, name: String, fairness_threshold: Option<eth::Ether>) -> Self {
pub fn new(
url: Url,
name: String,
fairness_threshold: Option<eth::Ether>,
submission_address: Option<eth::Address>,
) -> Self {
Self {
name,
url,
Expand All @@ -32,6 +38,7 @@ impl Driver {
.timeout(RESPONSE_TIME_LIMIT)
.build()
.unwrap(),
submission_address,
}
}

Expand Down
2 changes: 2 additions & 0 deletions crates/autopilot/src/run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -541,6 +541,7 @@ pub async fn run(args: Arguments) {
driver.url,
driver.name,
driver.fairness_threshold.map(Into::into),
driver.submission_address.map(Into::into),
))
})
.collect(),
Expand Down Expand Up @@ -569,6 +570,7 @@ async fn shadow_mode(args: Arguments) -> ! {
driver.url,
driver.name,
driver.fairness_threshold.map(Into::into),
driver.submission_address.map(Into::into),
))
})
.collect();
Expand Down
60 changes: 60 additions & 0 deletions crates/autopilot/src/run_loop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -720,6 +720,63 @@ impl RunLoop {
driver: &infra::Driver,
request: &solve::Request,
) -> Result<Vec<Result<competition::Solution, domain::competition::SolutionError>>, SolveError>
{
// @TODO: to be deleted once the submission address in the driver configuration
// is not optional
if let Some(submission_address) = driver.submission_address {
let authenticator = self.eth.contracts().authenticator();
let is_allowed = authenticator
.is_solver(submission_address.into())
.call()
.await;

// Do not send the request to the driver if the solver is denied
match is_allowed {
Ok(true) => {}
Ok(false) => return Err(SolveError::SolverDenyListed),
Err(err) => {
// log warning but discard solution anyway to be on the safe side
tracing::warn!(
driver = driver.name,
?driver.submission_address,
?err,
"failed to check if solver is deny listed"
);
return Err(SolveError::SolverDenyListed);
}
}

let response = tokio::time::timeout(self.config.solve_deadline, driver.solve(request))
.await
.map_err(|_| SolveError::Timeout)?
.map_err(SolveError::Failure)?;
if response.solutions.is_empty() {
return Err(SolveError::NoSolutions);
}
// Filter the responses
Ok(response
.into_domain()
.into_iter()
.filter(|solution| {
solution
.as_ref()
.ok()
.map(|solution| solution.solver() == submission_address)
.unwrap_or_default()
})
.collect())
} else {
self.try_solve_legacy(driver, request).await
}
}

// @TODO: Legacy try_solve, to be deleted once the submission address in the
// driver configuration is not optional
async fn try_solve_legacy(
&self,
driver: &infra::Driver,
request: &solve::Request,
) -> Result<Vec<Result<competition::Solution, domain::competition::SolutionError>>, SolveError>
{
let response = tokio::time::timeout(self.config.solve_deadline, driver.solve(request))
.await
Expand Down Expand Up @@ -871,6 +928,8 @@ enum SolveError {
NoSolutions,
#[error(transparent)]
Failure(anyhow::Error),
#[error("the solver got deny listed")]
SolverDenyListed,
}

#[derive(Debug, thiserror::Error)]
Expand Down Expand Up @@ -958,6 +1017,7 @@ impl Metrics {
SolveError::Timeout => "timeout",
SolveError::NoSolutions => "no_solutions",
SolveError::Failure(_) => "error",
SolveError::SolverDenyListed => "deny_listed",
};
Self::get()
.solve
Expand Down
11 changes: 7 additions & 4 deletions crates/e2e/src/setup/services.rs
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ impl<'a> Services<'a> {
vec![
colocation::start_baseline_solver(
"test_solver".into(),
solver,
solver.clone(),
self.contracts.weth.address(),
vec![],
)
Expand All @@ -213,7 +213,10 @@ impl<'a> Services<'a> {
None,
[
vec![
"--drivers=test_solver|http://localhost:11088/test_solver".to_string(),
format!(
"--drivers=test_solver|http://localhost:11088/test_solver|{}",
hex::encode(solver.address())
),
"--price-estimation-drivers=test_quoter|http://localhost:11088/test_solver"
.to_string(),
],
Expand Down Expand Up @@ -257,7 +260,7 @@ impl<'a> Services<'a> {
solvers.push(
colocation::start_baseline_solver(
"baseline_solver".into(),
solver,
solver.clone(),
self.contracts.weth.address(),
vec![],
)
Expand All @@ -267,7 +270,7 @@ impl<'a> Services<'a> {
// Here we call the baseline_solver "test_quoter" to make the native price
// estimation use the baseline_solver instead of the test_quoter
let autopilot_args = vec![
"--drivers=test_solver|http://localhost:11088/test_solver".to_string(),
format!("--drivers=test_solver|http://localhost:11088/test_solver|{}", hex::encode(solver.address())),
"--price-estimation-drivers=test_quoter|http://localhost:11088/baseline_solver,test_solver|http://localhost:11088/test_solver".to_string(),
"--native-price-estimators=test_quoter|http://localhost:11088/baseline_solver,test_solver|http://localhost:11088/test_solver".to_string(),
];
Expand Down
71 changes: 64 additions & 7 deletions crates/shared/src/arguments.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ macro_rules! logging_args_with_default_filter {
pub struct ExternalSolver {
pub name: String,
pub url: Url,
pub submission_address: Option<H160>,
pub fairness_threshold: Option<U256>,
}

Expand All @@ -64,7 +65,8 @@ pub struct ExternalSolver {
#[derive(clap::Parser)]
pub struct OrderQuotingArguments {
/// A list of external drivers used for price estimation in the following
/// format: `<NAME>|<URL>,<NAME>|<URL>`
/// format: `<NAME>|<URL>|<SUBMISSION_ADDRESS>|<FAIRNESS_THRESHOLD>,
/// <NAME>|<URL>|<SUBMISSION_ADDRESS>|<FAIRNESS_THRESHOLD>`
#[clap(long, env, use_value_delimiter = true)]
pub price_estimation_drivers: Vec<ExternalSolver>,

Expand Down Expand Up @@ -481,23 +483,46 @@ impl FromStr for ExternalSolver {
ensure!(parts.len() >= 2, "not enough arguments for external solver");
let (name, url) = (parts[0], parts[1]);
let url: Url = url.parse()?;
let fairness_threshold = match parts.get(2) {
Some(value) => {
Some(U256::from_dec_str(value).context("failed to parse fairness threshold")?)
let mut submission_address = None;
let mut fairness_threshold = None;

// @TODO: To remove the complex logic one submission address is not optional
if parts.len() == 4 {
submission_address = Some(
H160::from_str(parts.get(2).unwrap())
.context("failed to parse submission address")?,
);
fairness_threshold = Some(
U256::from_dec_str(parts.get(3).unwrap())
.context("failed to parse fairness threshold")?,
);
}
if parts.len() == 3 {
let part = parts.get(2).unwrap();
if let Ok(value) = H160::from_str(part) {
submission_address = Some(value);
}
None => None,
};
if let Ok(value) = U256::from_dec_str(part) {
fairness_threshold = Some(value);
}
ensure!(
submission_address.is_some() || fairness_threshold.is_some(),
"failed to parse external solver arguments"
);
}

Ok(Self {
name: name.to_owned(),
url,
fairness_threshold,
submission_address,
})
}
}

#[cfg(test)]
mod test {
use super::*;
use {super::*, hex_literal::hex};

#[test]
fn parse_driver() {
Expand All @@ -507,6 +532,7 @@ mod test {
name: "name1".into(),
url: Url::parse("http://localhost:8080").unwrap(),
fairness_threshold: None,
submission_address: None,
};
assert_eq!(driver, expected);
}
Expand All @@ -518,6 +544,37 @@ mod test {
let expected = ExternalSolver {
name: "name1".into(),
url: Url::parse("http://localhost:8080").unwrap(),
submission_address: None,
fairness_threshold: Some(U256::exp10(18)),
};
assert_eq!(driver, expected);
}

#[test]
fn parse_driver_with_submission_address() {
let argument = "name1|http://localhost:8080|0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2";
let driver = ExternalSolver::from_str(argument).unwrap();
let expected = ExternalSolver {
name: "name1".into(),
url: Url::parse("http://localhost:8080").unwrap(),
submission_address: Some(H160::from_slice(&hex!(
"C02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
))),
fairness_threshold: None,
};
assert_eq!(driver, expected);
}

#[test]
fn parse_driver_with_submission_address_and_threshold() {
let argument = "name1|http://localhost:8080|0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2|1000000000000000000";
let driver = ExternalSolver::from_str(argument).unwrap();
let expected = ExternalSolver {
name: "name1".into(),
url: Url::parse("http://localhost:8080").unwrap(),
submission_address: Some(H160::from_slice(&hex!(
"C02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
))),
fairness_threshold: Some(U256::exp10(18)),
};
assert_eq!(driver, expected);
Expand Down

0 comments on commit 42bf53a

Please sign in to comment.