@@ -3,39 +3,37 @@ use crate::{
3
3
signer:: LocalOrAws ,
4
4
tasks:: block:: InProgressBlock ,
5
5
} ;
6
+ use alloy:: consensus:: { constants:: GWEI_TO_WEI , SimpleCoder } ;
7
+ use alloy:: eips:: BlockNumberOrTag ;
6
8
use alloy:: network:: { TransactionBuilder , TransactionBuilder4844 } ;
7
9
use alloy:: providers:: { Provider as _, WalletProvider } ;
8
10
use alloy:: rpc:: types:: eth:: TransactionRequest ;
9
11
use alloy:: signers:: Signer ;
10
12
use alloy:: sol_types:: SolCall ;
11
13
use alloy:: transports:: TransportError ;
12
- use alloy:: { consensus:: SimpleCoder , providers:: SendableTx } ;
13
14
use alloy_primitives:: { FixedBytes , U256 } ;
14
- use eyre:: bail;
15
+ use alloy_sol_types:: SolError ;
16
+ use eyre:: eyre;
15
17
use oauth2:: {
16
18
basic:: BasicClient , basic:: BasicTokenType , reqwest:: http_client, AuthUrl , ClientId ,
17
19
ClientSecret , EmptyExtraTokenFields , StandardTokenResponse , TokenResponse , TokenUrl ,
18
20
} ;
19
21
use tokio:: { sync:: mpsc, task:: JoinHandle } ;
20
- use tracing:: { debug, error, instrument, trace, warn} ;
21
- use zenith_types:: { SignRequest , SignResponse , Zenith } ;
22
-
23
- macro_rules! spawn_provider_send {
24
- ( $provider: expr, $tx: expr) => {
25
- let p = $provider. clone( ) ;
26
- let t = $tx. clone( ) ;
27
- tokio:: spawn( async move {
28
- if let Err ( e) = p. send_tx_envelope( t) . await {
29
- warn!( %e, "error in transaction broadcast" ) ;
30
- }
31
- } ) ;
32
-
33
- } ;
34
- }
22
+ use tracing:: { debug, error, instrument, trace} ;
23
+ use zenith_types:: {
24
+ SignRequest , SignResponse ,
25
+ Zenith :: { self , IncorrectHostBlock } ,
26
+ } ;
35
27
36
28
/// OAuth Audience Claim Name, required param by IdP for client credential grant
37
29
const OAUTH_AUDIENCE_CLAIM : & str = "audience" ;
38
30
31
+ pub enum ControlFlow {
32
+ Retry ,
33
+ Skip ,
34
+ Done ,
35
+ }
36
+
39
37
/// Submits sidecars in ethereum txns to mainnet ethereum
40
38
pub struct SubmitTask {
41
39
/// Ethereum Provider
@@ -102,10 +100,10 @@ impl SubmitTask {
102
100
#[ instrument( skip_all) ]
103
101
async fn construct_sig_request ( & self , contents : & InProgressBlock ) -> eyre:: Result < SignRequest > {
104
102
let ru_chain_id = U256 :: from ( self . config . ru_chain_id ) ;
105
- let block_height = self . host_block_height ( ) . await ?;
103
+ let next_block_height = self . next_host_block_height ( ) . await ?;
106
104
107
105
Ok ( SignRequest {
108
- host_block_number : U256 :: from ( block_height ) ,
106
+ host_block_number : U256 :: from ( next_block_height ) ,
109
107
host_chain_id : U256 :: from ( self . config . host_chain_id ) ,
110
108
ru_chain_id,
111
109
gas_limit : U256 :: from ( self . config . rollup_block_gas_limit ) ,
@@ -133,19 +131,23 @@ impl SubmitTask {
133
131
let sidecar = in_progress. encode_blob :: < SimpleCoder > ( ) . build ( ) ?;
134
132
Ok ( TransactionRequest :: default ( )
135
133
. with_blob_sidecar ( sidecar)
136
- . with_input ( data) )
134
+ . with_input ( data)
135
+ . with_max_priority_fee_per_gas ( ( GWEI_TO_WEI * 16 ) as u128 ) )
137
136
}
138
137
139
- async fn host_block_height ( & self ) -> eyre:: Result < u64 > {
138
+ async fn next_host_block_height ( & self ) -> eyre:: Result < u64 > {
140
139
let result = self . provider . get_block_number ( ) . await ?;
141
- Ok ( result)
140
+ let next = result
141
+ . checked_add ( 1 )
142
+ . ok_or_else ( || eyre ! ( "next host block height overflow" ) ) ?;
143
+ Ok ( next)
142
144
}
143
145
144
146
async fn submit_transaction (
145
147
& self ,
146
148
resp : & SignResponse ,
147
149
in_progress : & InProgressBlock ,
148
- ) -> eyre:: Result < ( ) > {
150
+ ) -> eyre:: Result < ControlFlow > {
149
151
let v: u8 = resp. sig . v ( ) . y_parity_byte ( ) + 27 ;
150
152
let r: FixedBytes < 32 > = resp. sig . r ( ) . into ( ) ;
151
153
let s: FixedBytes < 32 > = resp. sig . s ( ) . into ( ) ;
@@ -161,60 +163,62 @@ impl SubmitTask {
161
163
let tx = self
162
164
. build_blob_tx ( header, v, r, s, in_progress) ?
163
165
. with_from ( self . provider . default_signer_address ( ) )
164
- . with_to ( self . config . zenith_address ) ;
165
-
166
- if let Err ( TransportError :: ErrorResp ( e) ) = self . provider . call ( & tx) . await {
166
+ . with_to ( self . config . zenith_address )
167
+ . with_gas_limit ( 1_000_000 ) ;
168
+
169
+ if let Err ( TransportError :: ErrorResp ( e) ) = self
170
+ . provider
171
+ . call ( & tx)
172
+ . block ( BlockNumberOrTag :: Pending . into ( ) )
173
+ . await
174
+ {
167
175
error ! (
168
176
code = e. code,
169
177
message = %e. message,
170
178
data = ?e. data,
171
179
"error in transaction submission"
172
180
) ;
173
181
174
- bail ! ( "bailing transaction submission" )
175
- }
176
-
177
- self . send_transaction ( resp, tx) . await ?;
182
+ if e. as_revert_data ( ) == Some ( IncorrectHostBlock :: SELECTOR . into ( ) ) {
183
+ return Ok ( ControlFlow :: Retry ) ;
184
+ }
178
185
179
- Ok ( ( ) )
180
- }
186
+ return Ok ( ControlFlow :: Skip ) ;
187
+ }
181
188
182
- async fn send_transaction (
183
- & self ,
184
- resp : & SignResponse ,
185
- tx : TransactionRequest ,
186
- ) -> Result < ( ) , eyre:: Error > {
187
189
tracing:: debug!(
188
190
host_block_number = %resp. req. host_block_number,
189
191
gas_limit = %resp. req. gas_limit,
190
192
"sending transaction to network"
191
193
) ;
192
194
193
- let SendableTx :: Envelope ( tx) = self . provider . fill ( tx) . await ? else {
194
- bail ! ( "failed to fill transaction" )
195
+ let _ = match self . provider . send_transaction ( tx) . await {
196
+ Ok ( result) => result,
197
+ Err ( e) => {
198
+ error ! ( error = %e, "error sending transaction" ) ;
199
+ return Ok ( ControlFlow :: Skip ) ;
200
+ }
195
201
} ;
196
202
197
- // Send the tx via the primary provider
198
- spawn_provider_send ! ( & self . provider, & tx) ;
199
-
200
- // Spawn send_tx futures for all additional broadcast providers
201
- for provider in self . config . connect_additional_broadcast ( ) . await ? {
202
- spawn_provider_send ! ( & provider, & tx) ;
203
- }
204
-
205
203
tracing:: info!(
206
- tx_hash = %tx. tx_hash( ) ,
207
204
ru_chain_id = %resp. req. ru_chain_id,
208
205
gas_limit = %resp. req. gas_limit,
209
206
"dispatched to network"
210
207
) ;
211
- Ok ( ( ) )
208
+
209
+ Ok ( ControlFlow :: Done )
212
210
}
213
211
214
212
#[ instrument( skip_all, err) ]
215
- async fn handle_inbound ( & self , in_progress : & InProgressBlock ) -> eyre:: Result < ( ) > {
213
+ async fn handle_inbound ( & self , in_progress : & InProgressBlock ) -> eyre:: Result < ControlFlow > {
216
214
tracing:: info!( txns = in_progress. len( ) , "handling inbound block" ) ;
217
- let sig_request = self . construct_sig_request ( in_progress) . await ?;
215
+ let sig_request = match self . construct_sig_request ( in_progress) . await {
216
+ Ok ( sig_request) => sig_request,
217
+ Err ( e) => {
218
+ tracing:: error!( error = %e, "error constructing signature request" ) ;
219
+ return Ok ( ControlFlow :: Skip ) ;
220
+ }
221
+ } ;
218
222
219
223
tracing:: debug!(
220
224
host_block_number = %sig_request. host_block_number,
@@ -235,7 +239,13 @@ impl SubmitTask {
235
239
sig,
236
240
}
237
241
} else {
238
- let resp: SignResponse = self . sup_quincey ( & sig_request) . await ?;
242
+ let resp: SignResponse = match self . sup_quincey ( & sig_request) . await {
243
+ Ok ( resp) => resp,
244
+ Err ( e) => {
245
+ tracing:: error!( error = %e, "error acquiring signature from quincey" ) ;
246
+ return Ok ( ControlFlow :: Retry ) ;
247
+ }
248
+ } ;
239
249
tracing:: debug!(
240
250
sig = hex:: encode( resp. sig. as_bytes( ) ) ,
241
251
"acquired signature from quincey"
@@ -252,8 +262,33 @@ impl SubmitTask {
252
262
let handle = tokio:: spawn ( async move {
253
263
loop {
254
264
if let Some ( in_progress) = inbound. recv ( ) . await {
255
- if let Err ( e) = self . handle_inbound ( & in_progress) . await {
256
- error ! ( %e, "error in block submission. Dropping block." ) ;
265
+ let mut retries = 0 ;
266
+ loop {
267
+ match self . handle_inbound ( & in_progress) . await {
268
+ Ok ( ControlFlow :: Retry ) => {
269
+ retries += 1 ;
270
+ if retries > 3 {
271
+ tracing:: error!(
272
+ "error handling inbound block: too many retries"
273
+ ) ;
274
+ break ;
275
+ }
276
+ tracing:: error!( "error handling inbound block: retrying" ) ;
277
+ tokio:: time:: sleep ( tokio:: time:: Duration :: from_secs ( 2 ) ) . await ;
278
+ }
279
+ Ok ( ControlFlow :: Skip ) => {
280
+ tracing:: info!( "skipping block" ) ;
281
+ break ;
282
+ }
283
+ Ok ( ControlFlow :: Done ) => {
284
+ tracing:: info!( "block landed successfully" ) ;
285
+ break ;
286
+ }
287
+ Err ( e) => {
288
+ tracing:: error!( error = %e, "error handling inbound block" ) ;
289
+ break ;
290
+ }
291
+ }
257
292
}
258
293
} else {
259
294
tracing:: debug!( "upstream task gone" ) ;
0 commit comments