Skip to content

Commit

Permalink
Append tx to simulation error (#1981)
Browse files Browse the repository at this point in the history
# Description
Prerequisite for #1980

Appends `tx data` to `SimulatorError` so the clients know details of the
transaction that caused the simulation failure.
`tx data` is optional because we need it only for simulations that
reverted, to analyze and replay the tx manually on tenderly etc. We are
not interested in `tx data` for simulations that failed because of http
connection failure to tenderly, for example.

That `tx data` is then used to log to kibana, but will also be used to
inform solvers via `/notify` endpoint.
  • Loading branch information
sunce86 authored Oct 20, 2023
1 parent bb8b0fb commit c70090e
Show file tree
Hide file tree
Showing 2 changed files with 89 additions and 9 deletions.
14 changes: 13 additions & 1 deletion crates/driver/src/domain/eth/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -313,7 +313,7 @@ impl From<H256> for TxId {
}

/// An onchain transaction.
#[derive(Clone, Debug)]
#[derive(Clone)]
pub struct Tx {
pub from: Address,
pub to: Address,
Expand All @@ -322,6 +322,18 @@ pub struct Tx {
pub access_list: AccessList,
}

impl std::fmt::Debug for Tx {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Tx")
.field("from", &self.from)
.field("to", &self.to)
.field("value", &self.value)
.field("input", &hex::encode(&self.input.0))
.field("access_list", &self.access_list)
.finish()
}
}

impl Tx {
pub fn set_access_list(self, access_list: AccessList) -> Self {
Self {
Expand Down
84 changes: 76 additions & 8 deletions crates/driver/src/infra/simulator/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use {
domain::eth,
infra::blockchain::{self, Ethereum},
},
ethcontract::errors::ExecutionError,
observe::future::Measure,
};

Expand Down Expand Up @@ -78,11 +79,18 @@ impl Simulator {
Inner::Tenderly(tenderly) => {
tenderly
.simulate(tx.clone(), tenderly::GenerateAccessList::Yes)
.await?
.await
.map_err(with_tx(tx.clone()))?
.access_list
}
Inner::Ethereum(ethereum) => ethereum.create_access_list(tx.clone()).await?,
Inner::Enso(_, ethereum) => ethereum.create_access_list(tx.clone()).await?,
Inner::Ethereum(ethereum) => ethereum
.create_access_list(tx.clone())
.await
.map_err(with_tx(tx.clone()))?,
Inner::Enso(_, ethereum) => ethereum
.create_access_list(tx.clone())
.await
.map_err(with_tx(tx.clone()))?,
};
Ok(tx.access_list.merge(access_list))
}
Expand All @@ -95,13 +103,21 @@ impl Simulator {
Ok(match &self.inner {
Inner::Tenderly(tenderly) => {
tenderly
.simulate(tx, tenderly::GenerateAccessList::No)
.simulate(tx.clone(), tenderly::GenerateAccessList::No)
.measure("tenderly_simulate_gas")
.await?
.await
.map_err(with_tx(tx))?
.gas
}
Inner::Ethereum(ethereum) => ethereum.estimate_gas(tx).await?,
Inner::Enso(enso, _) => enso.simulate(tx).measure("enso_simulate_gas").await?,
Inner::Ethereum(ethereum) => ethereum
.estimate_gas(tx.clone())
.await
.map_err(with_tx(tx))?,
Inner::Enso(enso, _) => enso
.simulate(tx.clone())
.measure("enso_simulate_gas")
.await
.map_err(with_tx(tx))?,
})
}
}
Expand All @@ -114,11 +130,63 @@ enum Inner {
}

#[derive(Debug, thiserror::Error)]
pub enum Error {
pub enum SimulatorError {
#[error("tenderly error: {0:?}")]
Tenderly(#[from] tenderly::Error),
#[error("blockchain error: {0:?}")]
Blockchain(#[from] blockchain::Error),
#[error("enso error: {0:?}")]
Enso(#[from] enso::Error),
}

#[derive(Debug, thiserror::Error)]
#[error("err: {err:?}, tx: {tx:?}")]
pub struct WithTxError {
err: SimulatorError,
tx: eth::Tx,
}

#[derive(Debug, thiserror::Error)]
pub enum Error {
#[error("basic: {0:?}")]
Basic(#[from] SimulatorError),
/// If a transaction reverted, forward that transaction together with the
/// error.
#[error("with tx: {0:?}")]
WithTx(#[from] WithTxError),
}

fn with_tx<E>(tx: eth::Tx) -> impl FnOnce(E) -> Error
where
E: Into<SimulatorError>,
{
move |err| {
let err: SimulatorError = err.into();
let tx = match &err {
SimulatorError::Tenderly(tenderly::Error::Http(_)) => None,
SimulatorError::Tenderly(tenderly::Error::Revert(_)) => Some(tx),
SimulatorError::Blockchain(blockchain::Error::Method(error))
if matches!(error.inner, ExecutionError::Revert(_)) =>
{
Some(tx)
}
SimulatorError::Blockchain(blockchain::Error::Method(_)) => None,
SimulatorError::Blockchain(blockchain::Error::Web3(inner)) => {
let error = ExecutionError::from(inner.clone());
if matches!(error, ExecutionError::Revert(_)) {
Some(tx)
} else {
None
}
}
SimulatorError::Blockchain(blockchain::Error::Gas(_)) => None,
SimulatorError::Blockchain(blockchain::Error::Response(_)) => None,
SimulatorError::Enso(enso::Error::Http(_)) => None,
SimulatorError::Enso(enso::Error::Revert(_)) => Some(tx),
};
match tx {
Some(tx) => Error::WithTx(WithTxError { err, tx }),
None => Error::Basic(err),
}
}
}

0 comments on commit c70090e

Please sign in to comment.