@@ -7,9 +7,9 @@ use alloy::{
7
7
consensus:: { SimpleCoder , constants:: GWEI_TO_WEI } ,
8
8
eips:: BlockNumberOrTag ,
9
9
network:: { TransactionBuilder , TransactionBuilder4844 } ,
10
- primitives:: { FixedBytes , TxHash , U256 } ,
10
+ primitives:: { Bytes , FixedBytes , TxHash , U256 } ,
11
11
providers:: { Provider as _, SendableTx , WalletProvider } ,
12
- rpc:: types:: eth:: TransactionRequest ,
12
+ rpc:: { json_rpc :: ErrorPayload , types:: eth:: TransactionRequest } ,
13
13
sol_types:: { SolCall , SolError } ,
14
14
transports:: TransportError ,
15
15
} ;
@@ -48,6 +48,133 @@ macro_rules! spawn_provider_send {
48
48
} ;
49
49
}
50
50
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
+
51
178
/// Control flow for transaction submission.
52
179
#[ derive( Debug , Copy , Clone , PartialEq , Eq ) ]
53
180
pub enum ControlFlow {
@@ -145,44 +272,14 @@ impl SubmitTask {
145
272
146
273
/// Simulates the transaction with a call to the host provider to check for reverts.
147
274
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) ;
165
278
bail ! ( e)
166
279
}
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 ( ( ) ) ,
183
282
}
184
-
185
- Ok ( ( ) )
186
283
}
187
284
188
285
/// Creates a transaction request for the blob with the given header and signature values.
0 commit comments