From debf21d34e833083d398426def9b50d387a18211 Mon Sep 17 00:00:00 2001 From: Matthias Seitz Date: Tue, 3 Jan 2023 13:56:50 +0100 Subject: [PATCH] feat: add SyncState traits (#693) * feat: add SyncState traits * docs: clarify execution stage --- crates/interfaces/src/lib.rs | 3 ++ crates/interfaces/src/sync.rs | 77 +++++++++++++++++++++++++++++++ crates/net/network/src/network.rs | 23 ++++++++- 3 files changed, 101 insertions(+), 2 deletions(-) create mode 100644 crates/interfaces/src/sync.rs diff --git a/crates/interfaces/src/lib.rs b/crates/interfaces/src/lib.rs index 0ec6c0001f..3c42c98f1a 100644 --- a/crates/interfaces/src/lib.rs +++ b/crates/interfaces/src/lib.rs @@ -22,6 +22,9 @@ pub mod db; /// P2P traits. pub mod p2p; +/// Syncing related traits. +pub mod sync; + /// Possible errors when interacting with the chain. mod error; diff --git a/crates/interfaces/src/sync.rs b/crates/interfaces/src/sync.rs new file mode 100644 index 0000000000..642c55e96f --- /dev/null +++ b/crates/interfaces/src/sync.rs @@ -0,0 +1,77 @@ +//! Traits used when interacting with the sync status of the network. + +use reth_primitives::BlockNumber; + +/// A type that provides information about whether the node is currently syncing and the network is +/// currently serving syncing related requests. +#[auto_impl::auto_impl(&, Arc, Box)] +pub trait SyncStateProvider: Send + Sync { + /// Returns `true` if the network is undergoing sync. + fn is_syncing(&self) -> bool; +} + +/// An updater for updating the [SyncState] of the network. +/// +/// The chain sync pipeline consists of several sequential Stages, like the `HeaderStage` for +/// downloading bodies, or `ExecutionStage` for process all downloaded data. +/// +/// Some stage transitions will result in an update of the [SyncState] of the network. For example, +/// the transition from a download stage (`Headers`, `Bodies`) to a processing stage (`Sender +/// Recovery`, `Execution`) marks a transition from [`SyncState::Downloading`] to +/// [`SyncState::Executing`]. Since the execution takes some time, after the first pass the node +/// will not be synced ([`SyncState::Idle`]) yet and instead transition back to download data, but +/// now with a higher `block_target`. This cycle will continue until the node has caught up with the +/// chain and will transition to [`SyncState::Idle`] sync. +#[auto_impl::auto_impl(&, Arc, Box)] +pub trait SyncStateUpdater: SyncStateProvider { + /// Notifies about an [SyncState] update. + fn update_sync_state(&self, state: SyncState); +} + +/// The state the network is currently in when it comes to synchronization. +#[derive(Clone, Eq, PartialEq, Debug)] +pub enum SyncState { + /// Node sync is complete. + /// + /// The network just serves requests to keep up of the chain. + Idle, + /// Network is syncing and downloading up to the `target_block`. + /// + /// This represents the headers and bodies stage. + Downloading { + /// The block to which the node is downloading state. + target_block: BlockNumber, + }, + /// All headers and bodies up to the `target_block` have been downloaded and are now being + /// executed. + /// + /// This represents stages that execute/recover the downloaded data. + Executing { + /// The block to which the node executes downloaded state. + target_block: BlockNumber, + }, +} + +impl SyncState { + /// Whether the node is currently syncing. + /// + /// Note: this does not include keep-up sync when the state is idle. + pub fn is_syncing(&self) -> bool { + !matches!(self, SyncState::Idle) + } +} + +/// A [SyncStateUpdater] implementation that does nothing. +#[derive(Debug, Clone, Default)] +#[non_exhaustive] +pub struct NoopSyncStateUpdate; + +impl SyncStateProvider for NoopSyncStateUpdate { + fn is_syncing(&self) -> bool { + false + } +} + +impl SyncStateUpdater for NoopSyncStateUpdate { + fn update_sync_state(&self, _state: SyncState) {} +} diff --git a/crates/net/network/src/network.rs b/crates/net/network/src/network.rs index 4a41c56f4a..1015b12d8d 100644 --- a/crates/net/network/src/network.rs +++ b/crates/net/network/src/network.rs @@ -8,12 +8,15 @@ use crate::{ }; use parking_lot::Mutex; use reth_eth_wire::{DisconnectReason, NewBlock, NewPooledTransactionHashes, SharedTransactions}; -use reth_interfaces::p2p::headers::client::StatusUpdater; +use reth_interfaces::{ + p2p::headers::client::StatusUpdater, + sync::{SyncState, SyncStateProvider, SyncStateUpdater}, +}; use reth_primitives::{PeerId, TransactionSigned, TxHash, H256, U256}; use std::{ net::SocketAddr, sync::{ - atomic::{AtomicUsize, Ordering}, + atomic::{AtomicBool, AtomicUsize, Ordering}, Arc, }, }; @@ -48,6 +51,7 @@ impl NetworkHandle { local_peer_id, peers, network_mode, + is_syncing: Arc::new(Default::default()), }; Self { inner: Arc::new(inner) } } @@ -187,6 +191,19 @@ impl StatusUpdater for NetworkHandle { } } +impl SyncStateProvider for NetworkHandle { + fn is_syncing(&self) -> bool { + self.inner.is_syncing.load(Ordering::Relaxed) + } +} + +impl SyncStateUpdater for NetworkHandle { + fn update_sync_state(&self, state: SyncState) { + let is_syncing = state.is_syncing(); + self.inner.is_syncing.store(is_syncing, Ordering::Relaxed) + } +} + #[derive(Debug)] struct NetworkInner { /// Number of active peer sessions the node's currently handling. @@ -201,6 +218,8 @@ struct NetworkInner { peers: PeersHandle, /// The mode of the network network_mode: NetworkMode, + /// Represents if the network is currently syncing. + is_syncing: Arc, } /// Internal messages that can be passed to the [`NetworkManager`](crate::NetworkManager).