@@ -7,9 +7,9 @@ use alloy::{
77 consensus:: { SimpleCoder , constants:: GWEI_TO_WEI } ,
88 eips:: BlockNumberOrTag ,
99 network:: { TransactionBuilder , TransactionBuilder4844 } ,
10- primitives:: { FixedBytes , TxHash , U256 } ,
10+ primitives:: { Bytes , FixedBytes , TxHash , U256 } ,
1111 providers:: { Provider as _, SendableTx , WalletProvider } ,
12- rpc:: types:: eth:: TransactionRequest ,
12+ rpc:: { json_rpc :: ErrorPayload , types:: eth:: TransactionRequest } ,
1313 sol_types:: { SolCall , SolError } ,
1414 transports:: TransportError ,
1515} ;
@@ -48,6 +48,133 @@ macro_rules! spawn_provider_send {
4848 } ;
4949}
5050
51+ /// Represents the kind of revert that can occur during simulation.
52+ #[ derive( Debug , Clone , Copy , PartialEq , Eq ) ]
53+ pub enum SimRevertKind {
54+ /// Incorrect host block error
55+ IncorrectHostBlock ,
56+ /// Bad signature error
57+ BadSignature ,
58+ /// One rollup block per host block error
59+ OneRollupBlockPerHostBlock ,
60+ /// Unknown error
61+ Unknown ,
62+ }
63+
64+ impl From < Option < Bytes > > for SimRevertKind {
65+ fn from ( data : Option < Bytes > ) -> Self {
66+ let Some ( data) = data else {
67+ return Self :: Unknown ;
68+ } ;
69+
70+ if data. starts_with ( & IncorrectHostBlock :: SELECTOR ) {
71+ Self :: IncorrectHostBlock
72+ } else if data. starts_with ( & Zenith :: BadSignature :: SELECTOR ) {
73+ Self :: BadSignature
74+ } else if data. starts_with ( & Zenith :: OneRollupBlockPerHostBlock :: SELECTOR ) {
75+ Self :: OneRollupBlockPerHostBlock
76+ } else {
77+ Self :: Unknown
78+ }
79+ }
80+ }
81+
82+ #[ derive( Debug , Clone ) ]
83+ /// Represents an error that occurs during simulation of a transaction.
84+ pub struct SimErrorResp {
85+ /// The error payload containing the error code and message.
86+ pub err : ErrorPayload ,
87+ /// The kind of revert that occurred (or unknown if not recognized).
88+ kind : SimRevertKind ,
89+ }
90+
91+ impl core:: fmt:: Display for SimErrorResp {
92+ fn fmt ( & self , f : & mut core:: fmt:: Formatter < ' _ > ) -> core:: fmt:: Result {
93+ write ! (
94+ f,
95+ "SimErrorResp {{ code: {}, message: {}, kind: {:?} }}" ,
96+ self . code( ) ,
97+ self . message( ) ,
98+ self . kind
99+ )
100+ }
101+ }
102+
103+ impl From < ErrorPayload > for SimErrorResp {
104+ fn from ( err : ErrorPayload ) -> Self {
105+ Self :: new ( err)
106+ }
107+ }
108+
109+ impl SimErrorResp {
110+ /// Creates a new `SimRevertError` with the specified kind and error
111+ /// payload.
112+ pub fn new ( err : ErrorPayload ) -> Self {
113+ let kind = err. as_revert_data ( ) . into ( ) ;
114+ Self { err, kind }
115+ }
116+
117+ /// True if the error is an incorrect host block.
118+ pub fn is_incorrect_host_block ( & self ) -> bool {
119+ self . as_revert_data ( )
120+ . map ( |b| b. starts_with ( & IncorrectHostBlock :: SELECTOR ) )
121+ . unwrap_or_default ( )
122+ }
123+
124+ /// Attempts to decode the error payload as an [`IncorrectHostBlock`].
125+ pub fn as_incorrect_host_block ( & self ) -> Option < IncorrectHostBlock > {
126+ self . as_revert_data ( ) . and_then ( |data| IncorrectHostBlock :: abi_decode ( & data, true ) . ok ( ) )
127+ }
128+
129+ /// True if the error is a [`Zenith::BadSignature`].
130+ pub fn is_bad_signature ( & self ) -> bool {
131+ self . as_revert_data ( )
132+ . map ( |b| b. starts_with ( & Zenith :: BadSignature :: SELECTOR ) )
133+ . unwrap_or_default ( )
134+ }
135+
136+ /// Attempts to decode the error payload as a [`Zenith::BadSignature`].
137+ pub fn as_bad_signature ( & self ) -> Option < Zenith :: BadSignature > {
138+ self . as_revert_data ( ) . and_then ( |data| Zenith :: BadSignature :: abi_decode ( & data, true ) . ok ( ) )
139+ }
140+
141+ /// True if the error is a [`Zenith::OneRollupBlockPerHostBlock`].
142+ pub fn is_one_rollup_block_per_host_block ( & self ) -> bool {
143+ self . as_revert_data ( )
144+ . map ( |b| b. starts_with ( & Zenith :: OneRollupBlockPerHostBlock :: SELECTOR ) )
145+ . unwrap_or_default ( )
146+ }
147+
148+ /// Attempts to decode the error payload as a
149+ /// [`Zenith::OneRollupBlockPerHostBlock`].
150+ pub fn as_one_rollup_block_per_host_block ( & self ) -> Option < Zenith :: OneRollupBlockPerHostBlock > {
151+ self . as_revert_data ( )
152+ . and_then ( |data| Zenith :: OneRollupBlockPerHostBlock :: abi_decode ( & data, true ) . ok ( ) )
153+ }
154+
155+ /// True if the error is an unknown revert.
156+ pub fn is_unknown ( & self ) -> bool {
157+ !self . is_incorrect_host_block ( )
158+ && !self . is_bad_signature ( )
159+ && !self . is_one_rollup_block_per_host_block ( )
160+ }
161+
162+ /// Returns the revert data if available.
163+ pub fn as_revert_data ( & self ) -> Option < Bytes > {
164+ self . err . as_revert_data ( )
165+ }
166+
167+ /// Returns the JSON-RPC error code.
168+ pub const fn code ( & self ) -> i64 {
169+ self . err . code
170+ }
171+
172+ /// Returns the error message.
173+ pub fn message ( & self ) -> & str {
174+ & self . err . message
175+ }
176+ }
177+
51178/// Control flow for transaction submission.
52179#[ derive( Debug , Copy , Clone , PartialEq , Eq ) ]
53180pub enum ControlFlow {
@@ -145,44 +272,14 @@ impl SubmitTask {
145272
146273 /// Simulates the transaction with a call to the host provider to check for reverts.
147274 async fn sim_with_call ( & self , tx : & TransactionRequest ) -> eyre:: Result < ( ) > {
148- if let Err ( TransportError :: ErrorResp ( e) ) =
149- self . provider ( ) . call ( tx. clone ( ) ) . block ( BlockNumberOrTag :: Pending . into ( ) ) . await
150- {
151- // NB: These errors are all handled the same way but are logged for debugging purposes
152- if e. as_revert_data ( )
153- . map ( |data| data. starts_with ( & IncorrectHostBlock :: SELECTOR ) )
154- . unwrap_or_default ( )
155- {
156- debug ! ( %e, "incorrect host block" ) ;
157- bail ! ( e)
158- }
159-
160- if e. as_revert_data ( )
161- . map ( |data| data. starts_with ( & Zenith :: BadSignature :: SELECTOR ) )
162- . unwrap_or_default ( )
163- {
164- debug ! ( %e, "bad signature" ) ;
275+ match self . provider ( ) . call ( tx. clone ( ) ) . block ( BlockNumberOrTag :: Pending . into ( ) ) . await {
276+ Err ( TransportError :: ErrorResp ( e) ) => {
277+ let e = SimErrorResp :: from ( e) ;
165278 bail ! ( e)
166279 }
167-
168- if e. as_revert_data ( )
169- . map ( |data| data. starts_with ( & Zenith :: OneRollupBlockPerHostBlock :: SELECTOR ) )
170- . unwrap_or_default ( )
171- {
172- debug ! ( %e, "one rollup block per host block" ) ;
173- bail ! ( e)
174- }
175-
176- error ! (
177- code = e. code,
178- message = %e. message,
179- data = ?e. data,
180- "unknown error in host transaction simulation call"
181- ) ;
182- bail ! ( e)
280+ Err ( e) => bail ! ( e) ,
281+ _ => Ok ( ( ) ) ,
183282 }
184-
185- Ok ( ( ) )
186283 }
187284
188285 /// Creates a transaction request for the blob with the given header and signature values.
0 commit comments