@@ -9,6 +9,7 @@ use std::time::Duration;
99use clarity:: Address ;
1010use ethbridge_events:: { event_codecs, EventKind } ;
1111use eyre:: eyre;
12+ use namada:: core:: hints;
1213use namada:: core:: types:: ethereum_structs;
1314use namada:: eth_bridge:: oracle:: config:: Config ;
1415use namada:: types:: ethereum_events:: EthereumEvent ;
@@ -37,12 +38,6 @@ const DEFAULT_CEILING: Duration = std::time::Duration::from_secs(30);
3738pub enum Error {
3839 #[ error( "Ethereum node has fallen out of sync" ) ]
3940 FallenBehind ,
40- #[ error(
41- "Couldn't get the latest synced Ethereum block height from the RPC \
42- endpoint: {0}"
43- ) ]
44- #[ allow( dead_code) ]
45- FetchHeight ( String ) ,
4641 #[ error(
4742 "Couldn't check for events ({0} from {1}) with the RPC endpoint: {2}"
4843 ) ]
@@ -53,6 +48,8 @@ pub enum Error {
5348 "Need more confirmations for oracle to continue processing blocks."
5449 ) ]
5550 MoreConfirmations ,
51+ #[ error( "The Ethereum oracle timed out" ) ]
52+ Timeout ,
5653}
5754
5855/// The result of querying an Ethereum nodes syncing status.
@@ -99,15 +96,25 @@ impl Deref for Oracle {
9996}
10097
10198/// Fetch the sync status of an Ethereum node.
99+ ///
100+ /// Queries to the Ethereum node are interspersed with constant backoff
101+ /// sleeps of `backoff_duration`, before ultimately timing out at `deadline`.
102102pub async fn eth_syncing_status (
103103 client : & web30:: client:: Web3 ,
104+ backoff_duration : Duration ,
105+ deadline : Instant ,
104106) -> Result < SyncStatus , Error > {
105- match client. eth_block_number ( ) . await {
106- Ok ( height) if height == 0u64 . into ( ) => Ok ( SyncStatus :: Syncing ) ,
107- Ok ( height) => Ok ( SyncStatus :: AtHeight ( height) ) ,
108- Err ( Web3Error :: SyncingNode ( _) ) => Ok ( SyncStatus :: Syncing ) ,
109- Err ( error) => Err ( Error :: FetchHeight ( error. to_string ( ) ) ) ,
110- }
107+ TimeoutStrategy :: Constant ( backoff_duration)
108+ . timeout ( deadline, || async {
109+ ControlFlow :: Break ( match client. eth_block_number ( ) . await {
110+ Ok ( height) if height == 0u64 . into ( ) => SyncStatus :: Syncing ,
111+ Ok ( height) => SyncStatus :: AtHeight ( height) ,
112+ Err ( Web3Error :: SyncingNode ( _) ) => SyncStatus :: Syncing ,
113+ Err ( _) => return ControlFlow :: Continue ( ( ) ) ,
114+ } )
115+ } )
116+ . await
117+ . map_or_else ( |_| Err ( Error :: Timeout ) , |status| Ok ( status) )
111118}
112119
113120impl Oracle {
@@ -140,7 +147,8 @@ impl Oracle {
140147 /// number is 0 or not.
141148 #[ cfg( not( test) ) ]
142149 async fn syncing ( & self ) -> Result < SyncStatus , Error > {
143- match eth_syncing_status ( & self . client ) . await ? {
150+ let deadline = Instant :: now ( ) + self . ceiling ;
151+ match eth_syncing_status ( & self . client , self . backoff , deadline) . await ? {
144152 s @ SyncStatus :: Syncing => Ok ( s) ,
145153 SyncStatus :: AtHeight ( height) => {
146154 match & * self . last_processed_block . borrow ( ) {
@@ -275,16 +283,33 @@ async fn run_oracle_aux(mut oracle: Oracle) {
275283 "Checking Ethereum block for bridge events"
276284 ) ;
277285 let deadline = Instant :: now ( ) + oracle. ceiling ;
278- let res = TimeoutStrategy :: Constant ( oracle. backoff ) . timeout ( deadline , || async {
286+ let res = TimeoutStrategy :: Constant ( oracle. backoff ) . run ( || async {
279287 tokio:: select! {
280288 result = process( & oracle, & config, next_block_to_process. clone( ) ) => {
281289 match result {
282290 Ok ( ( ) ) => {
283291 ControlFlow :: Break ( Ok ( ( ) ) )
284292 } ,
285- Err ( error) => {
286- tracing:: warn!(
287- ?error,
293+ err @ Err (
294+ Error :: Timeout
295+ | Error :: Channel ( _, _)
296+ | Error :: CheckEvents ( _, _, _)
297+ ) => {
298+ let Err ( reason) = err else {
299+ // this is silly...
300+ hints:: cold( ) ;
301+ unreachable!( ) ;
302+ } ;
303+ tracing:: error!(
304+ reason,
305+ )
306+ ControlFlow :: Break ( Err ( ( ) ) )
307+ }
308+ Err ( reason) => {
309+ // this is a recoverable error, hence the debug log,
310+ // to avoid spamming info logs
311+ tracing:: debug!(
312+ reason,
288313 block = ?next_block_to_process,
289314 "Error while trying to process Ethereum block"
290315 ) ;
@@ -297,25 +322,22 @@ async fn run_oracle_aux(mut oracle: Oracle) {
297322 "Ethereum oracle can not send events to the ledger; the \
298323 receiver has hung up. Shutting down"
299324 ) ;
300- ControlFlow :: Break ( Err ( eyre! ( "Shutting down." ) ) )
325+ ControlFlow :: Break ( Err ( ( ) ) )
301326 }
302327 }
303- } )
304- . await
305- . expect ( "Oracle timed out while trying to communicate with the Ethereum fullnode." ) ;
306-
328+ } ) ;
307329 if res. is_err ( ) {
308330 break ;
309- } else {
310- oracle
311- . last_processed_block
312- . send_replace ( Some ( next_block_to_process. clone ( ) ) ) ;
313- // check if a new config has been sent.
314- if let Some ( new_config) = oracle. update_config ( ) {
315- config = new_config;
316- }
317- next_block_to_process += 1 . into ( ) ;
318331 }
332+
333+ oracle
334+ . last_processed_block
335+ . send_replace ( Some ( next_block_to_process. clone ( ) ) ) ;
336+ // check if a new config has been sent.
337+ if let Some ( new_config) = oracle. update_config ( ) {
338+ config = new_config;
339+ }
340+ next_block_to_process += 1 . into ( ) ;
319341 }
320342}
321343
0 commit comments