Skip to content

Commit 7b200e8

Browse files
committed
Keep oracle running if Eth node is still available
1 parent 2fbe97c commit 7b200e8

File tree

1 file changed

+53
-31
lines changed
  • apps/src/lib/node/ledger/ethereum_oracle

1 file changed

+53
-31
lines changed

apps/src/lib/node/ledger/ethereum_oracle/mod.rs

Lines changed: 53 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use std::time::Duration;
99
use clarity::Address;
1010
use ethbridge_events::{event_codecs, EventKind};
1111
use eyre::eyre;
12+
use namada::core::hints;
1213
use namada::core::types::ethereum_structs;
1314
use namada::eth_bridge::oracle::config::Config;
1415
use namada::types::ethereum_events::EthereumEvent;
@@ -37,12 +38,6 @@ const DEFAULT_CEILING: Duration = std::time::Duration::from_secs(30);
3738
pub 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`.
102102
pub 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

113120
impl 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

Comments
 (0)