diff --git a/src/tasks/block/sim.rs b/src/tasks/block/sim.rs index 6868837..ce7ffb3 100644 --- a/src/tasks/block/sim.rs +++ b/src/tasks/block/sim.rs @@ -82,7 +82,6 @@ impl Simulator { block: BlockEnv, ) -> eyre::Result { let db = self.create_db().await.unwrap(); - let block_build: BlockBuild<_, NoOpInspector> = BlockBuild::new( db, constants, diff --git a/src/tasks/submit.rs b/src/tasks/submit.rs index 02efc26..cab53cb 100644 --- a/src/tasks/submit.rs +++ b/src/tasks/submit.rs @@ -7,9 +7,9 @@ use alloy::{ consensus::{SimpleCoder, constants::GWEI_TO_WEI}, eips::BlockNumberOrTag, network::{TransactionBuilder, TransactionBuilder4844}, - primitives::{FixedBytes, TxHash, U256}, + primitives::{Bytes, FixedBytes, TxHash, U256}, providers::{Provider as _, SendableTx, WalletProvider}, - rpc::types::eth::TransactionRequest, + rpc::{json_rpc::ErrorPayload, types::eth::TransactionRequest}, sol_types::{SolCall, SolError}, transports::TransportError, }; @@ -48,6 +48,133 @@ macro_rules! spawn_provider_send { }; } +/// Represents the kind of revert that can occur during simulation. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum SimRevertKind { + /// Incorrect host block error + IncorrectHostBlock, + /// Bad signature error + BadSignature, + /// One rollup block per host block error + OneRollupBlockPerHostBlock, + /// Unknown error + Unknown, +} + +impl From> for SimRevertKind { + fn from(data: Option) -> Self { + let Some(data) = data else { + return Self::Unknown; + }; + + if data.starts_with(&IncorrectHostBlock::SELECTOR) { + Self::IncorrectHostBlock + } else if data.starts_with(&Zenith::BadSignature::SELECTOR) { + Self::BadSignature + } else if data.starts_with(&Zenith::OneRollupBlockPerHostBlock::SELECTOR) { + Self::OneRollupBlockPerHostBlock + } else { + Self::Unknown + } + } +} + +#[derive(Debug, Clone)] +/// Represents an error that occurs during simulation of a transaction. +pub struct SimErrorResp { + /// The error payload containing the error code and message. + pub err: ErrorPayload, + /// The kind of revert that occurred (or unknown if not recognized). + kind: SimRevertKind, +} + +impl core::fmt::Display for SimErrorResp { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!( + f, + "SimErrorResp {{ code: {}, message: {}, kind: {:?} }}", + self.code(), + self.message(), + self.kind + ) + } +} + +impl From for SimErrorResp { + fn from(err: ErrorPayload) -> Self { + Self::new(err) + } +} + +impl SimErrorResp { + /// Creates a new `SimRevertError` with the specified kind and error + /// payload. + pub fn new(err: ErrorPayload) -> Self { + let kind = err.as_revert_data().into(); + Self { err, kind } + } + + /// True if the error is an incorrect host block. + pub fn is_incorrect_host_block(&self) -> bool { + self.as_revert_data() + .map(|b| b.starts_with(&IncorrectHostBlock::SELECTOR)) + .unwrap_or_default() + } + + /// Attempts to decode the error payload as an [`IncorrectHostBlock`]. + pub fn as_incorrect_host_block(&self) -> Option { + self.as_revert_data().and_then(|data| IncorrectHostBlock::abi_decode(&data).ok()) + } + + /// True if the error is a [`Zenith::BadSignature`]. + pub fn is_bad_signature(&self) -> bool { + self.as_revert_data() + .map(|b| b.starts_with(&Zenith::BadSignature::SELECTOR)) + .unwrap_or_default() + } + + /// Attempts to decode the error payload as a [`Zenith::BadSignature`]. + pub fn as_bad_signature(&self) -> Option { + self.as_revert_data().and_then(|data| Zenith::BadSignature::abi_decode(&data).ok()) + } + + /// True if the error is a [`Zenith::OneRollupBlockPerHostBlock`]. + pub fn is_one_rollup_block_per_host_block(&self) -> bool { + self.as_revert_data() + .map(|b| b.starts_with(&Zenith::OneRollupBlockPerHostBlock::SELECTOR)) + .unwrap_or_default() + } + + /// Attempts to decode the error payload as a + /// [`Zenith::OneRollupBlockPerHostBlock`]. + pub fn as_one_rollup_block_per_host_block(&self) -> Option { + self.as_revert_data() + .and_then(|data| Zenith::OneRollupBlockPerHostBlock::abi_decode(&data).ok()) + } + + /// True if the error is an unknown revert. + pub fn is_unknown(&self) -> bool { + !self.is_incorrect_host_block() + && !self.is_bad_signature() + && !self.is_one_rollup_block_per_host_block() + } + + /// Returns the revert data if available. + pub fn as_revert_data(&self) -> Option { + self.err.as_revert_data() + } + + /// Returns the JSON-RPC error code. + pub const fn code(&self) -> i64 { + self.err.code + } + + /// Returns the error message. + pub fn message(&self) -> &str { + &self.err.message + } +} + /// Control flow for transaction submission. #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub enum ControlFlow { @@ -145,44 +272,14 @@ impl SubmitTask { /// Simulates the transaction with a call to the host provider to check for reverts. async fn sim_with_call(&self, tx: &TransactionRequest) -> eyre::Result<()> { - if let Err(TransportError::ErrorResp(e)) = - self.provider().call(tx.clone()).block(BlockNumberOrTag::Pending.into()).await - { - // NB: These errors are all handled the same way but are logged for debugging purposes - if e.as_revert_data() - .map(|data| data.starts_with(&IncorrectHostBlock::SELECTOR)) - .unwrap_or_default() - { - debug!(%e, "incorrect host block"); - bail!(e) - } - - if e.as_revert_data() - .map(|data| data.starts_with(&Zenith::BadSignature::SELECTOR)) - .unwrap_or_default() - { - debug!(%e, "bad signature"); + match self.provider().call(tx.clone()).block(BlockNumberOrTag::Pending.into()).await { + Err(TransportError::ErrorResp(e)) => { + let e = SimErrorResp::from(e); bail!(e) } - - if e.as_revert_data() - .map(|data| data.starts_with(&Zenith::OneRollupBlockPerHostBlock::SELECTOR)) - .unwrap_or_default() - { - debug!(%e, "one rollup block per host block"); - bail!(e) - } - - error!( - code = e.code, - message = %e.message, - data = ?e.data, - "unknown error in host transaction simulation call" - ); - bail!(e) + Err(e) => bail!(e), + _ => Ok(()), } - - Ok(()) } /// Creates a transaction request for the blob with the given header and signature values.