diff --git a/CHANGELOG.md b/CHANGELOG.md index a251d4cb..c2b6255e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ ### Unreleased +- Add `eth_syncing` [848](https://github.com/gakonst/ethers-rs/pull/848) - Fix overflow and possible divide-by-zero in `estimate_priority_fee` - Add BSC mainnet and testnet to the list of known chains [831](https://github.com/gakonst/ethers-rs/pull/831) diff --git a/ethers-providers/src/lib.rs b/ethers-providers/src/lib.rs index 8d932317..632d1a43 100644 --- a/ethers-providers/src/lib.rs +++ b/ethers-providers/src/lib.rs @@ -79,6 +79,15 @@ where } } +/// Structure used in eth_syncing RPC +#[derive(Clone, Debug)] +pub enum SyncingStatus { + /// When client is synced to highest block, eth_syncing with return string "false" + IsFalse, + /// When client is still syncing past blocks we get IsSyncing information. + IsSyncing { starting_block: U256, current_block: U256, highest_block: U256 }, +} + /// A middleware allows customizing requests send and received from an ethereum node. /// /// Writing a middleware is as simple as: @@ -303,6 +312,10 @@ pub trait Middleware: Sync + Send + Debug { self.inner().call(tx, block).await.map_err(FromErr::from) } + async fn syncing(&self) -> Result { + self.inner().syncing().await.map_err(FromErr::from) + } + async fn get_chainid(&self) -> Result { self.inner().get_chainid().await.map_err(FromErr::from) } diff --git a/ethers-providers/src/provider.rs b/ethers-providers/src/provider.rs index d5a9b23c..15eae5fa 100644 --- a/ethers-providers/src/provider.rs +++ b/ethers-providers/src/provider.rs @@ -3,7 +3,7 @@ use crate::{ pubsub::{PubsubClient, SubscriptionStream}, stream::{FilterWatcher, DEFAULT_POLL_INTERVAL}, FromErr, Http as HttpProvider, JsonRpcClient, JsonRpcClientWrapper, MockProvider, - PendingTransaction, QuorumProvider, + PendingTransaction, QuorumProvider, SyncingStatus, }; #[cfg(feature = "celo")] @@ -23,7 +23,7 @@ use ethers_core::{ utils, }; use hex::FromHex; -use serde::{de::DeserializeOwned, Serialize}; +use serde::{de::DeserializeOwned, Deserialize, Serialize}; use thiserror::Error; use url::{ParseError, Url}; @@ -497,6 +497,30 @@ impl Middleware for Provider

{ self.request("eth_chainId", ()).await } + /// Return current client syncing status. If IsFalse sync is over. + async fn syncing(&self) -> Result { + #[derive(Debug, Serialize, Deserialize)] + #[serde(untagged)] + pub enum SyncingStatusIntermediate { + /// When client is synced to highest block, eth_syncing with return string "false" + IsFalse(bool), + /// When client is still syncing past blocks we get IsSyncing information. + IsSyncing { starting_block: U256, current_block: U256, highest_block: U256 }, + } + let intermediate: SyncingStatusIntermediate = self.request("eth_syncing", ()).await?; + match intermediate { + SyncingStatusIntermediate::IsFalse(false) => Ok(SyncingStatus::IsFalse), + SyncingStatusIntermediate::IsFalse(true) => Err(ProviderError::CustomError( + "eth_syncing returned `true` that is undefined value.".to_owned(), + )), + SyncingStatusIntermediate::IsSyncing { + starting_block, + current_block, + highest_block, + } => Ok(SyncingStatus::IsSyncing { starting_block, current_block, highest_block }), + } + } + /// Returns the network version. async fn get_net_version(&self) -> Result { self.request("net_version", ()).await