diff --git a/crates/net/network/src/manager.rs b/crates/net/network/src/manager.rs index 9905f395aa..8a7e1c8b5a 100644 --- a/crates/net/network/src/manager.rs +++ b/crates/net/network/src/manager.rs @@ -470,7 +470,11 @@ where let _ = tx.send(self.fetch_client()); } NetworkHandleMessage::StatusUpdate { height, hash, total_difficulty } => { - self.swarm.sessions_mut().on_status_update(height, hash, total_difficulty); + if let Some(transition) = + self.swarm.sessions_mut().on_status_update(height, hash, total_difficulty) + { + self.swarm.state_mut().update_fork_id(transition.current); + } } } } diff --git a/crates/net/network/src/session/mod.rs b/crates/net/network/src/session/mod.rs index 94192c84a2..1e24c3c938 100644 --- a/crates/net/network/src/session/mod.rs +++ b/crates/net/network/src/session/mod.rs @@ -19,7 +19,7 @@ use reth_eth_wire::{ error::EthStreamError, DisconnectReason, HelloMessage, Status, UnauthedEthStream, UnauthedP2PStream, }; -use reth_primitives::{ForkFilter, PeerId, H256, U256}; +use reth_primitives::{ForkFilter, ForkTransition, PeerId, H256, U256}; use secp256k1::SecretKey; use std::{ collections::HashMap, @@ -146,11 +146,19 @@ impl SessionManager { } } - /// Invoked on a received status update - pub(crate) fn on_status_update(&mut self, height: u64, hash: H256, total_difficulty: U256) { + /// Invoked on a received status update. + /// + /// If the updated activated another fork, this will return a [`ForkTransition`] and updates the + /// active [`ForkId`](reth_primitives::ForkId). See also [`ForkFilter::set_head`]. + pub(crate) fn on_status_update( + &mut self, + height: u64, + hash: H256, + total_difficulty: U256, + ) -> Option { self.status.blockhash = hash; self.status.total_difficulty = total_difficulty; - self.fork_filter.set_head(height); + self.fork_filter.set_head(height) } /// An incoming TCP connection was received. This starts the authentication process to turn this diff --git a/crates/net/network/src/state.rs b/crates/net/network/src/state.rs index 94f07d69c0..ed8eaec7f1 100644 --- a/crates/net/network/src/state.rs +++ b/crates/net/network/src/state.rs @@ -216,10 +216,9 @@ where self.state_fetcher.update_peer_block(peer_id, hash, number); } - /// Invoked on a [`ForkId`] update - #[allow(unused)] - pub(crate) fn update_fork_id(&mut self, _fork_id: ForkId) { - todo!() + /// Invoked when a new [`ForkId`] is activated. + pub(crate) fn update_fork_id(&mut self, fork_id: ForkId) { + self.discovery.update_fork_id(fork_id) } /// Invoked after a `NewBlock` message was received by the peer. diff --git a/crates/primitives/src/forkid.rs b/crates/primitives/src/forkid.rs index 3070a66b0e..64e6a4bcbc 100644 --- a/crates/primitives/src/forkid.rs +++ b/crates/primitives/src/forkid.rs @@ -141,7 +141,7 @@ impl ForkFilter { Self { forks, head, cache } } - fn set_head_priv(&mut self, head: BlockNumber) -> bool { + fn set_head_priv(&mut self, head: BlockNumber) -> Option { let recompute_cache = { if head < self.cache.epoch_start { true @@ -152,17 +152,27 @@ impl ForkFilter { } }; + let mut transition = None; + + // recompute the cache if recompute_cache { + let past = self.current(); + self.cache = Cache::compute_cache(&self.forks, head); + + transition = Some(ForkTransition { current: self.current(), past }) } + self.head = head; - recompute_cache + transition } - /// Set the current head - pub fn set_head(&mut self, head: BlockNumber) { - self.set_head_priv(head); + /// Set the current head. + /// + /// If the update updates the current [`ForkId`] it returns a [`ForkTransition`] + pub fn set_head(&mut self, head: BlockNumber) -> Option { + self.set_head_priv(head) } /// Return current fork id @@ -232,6 +242,17 @@ impl ForkFilter { } } +/// Represents a transition from one fork to another +/// +/// See also [`ForkFilter::set_head`] +#[derive(Debug, Clone, Eq, PartialEq)] +pub struct ForkTransition { + /// The new, active ForkId + pub current: ForkId, + /// The previously active ForkId before the transition + pub past: ForkId, +} + #[derive(Clone, Debug, PartialEq, Eq)] struct Cache { // An epoch is a period between forks. @@ -463,28 +484,34 @@ mod tests { let mut fork_filter = ForkFilter::new(0, GENESIS_HASH, vec![b1, b2]); - assert!(!fork_filter.set_head_priv(0)); + assert!(fork_filter.set_head_priv(0).is_none()); assert_eq!(fork_filter.current(), h0); - assert!(!fork_filter.set_head_priv(1)); + assert!(fork_filter.set_head_priv(1).is_none()); assert_eq!(fork_filter.current(), h0); - assert!(fork_filter.set_head_priv(b1 + 1)); + assert_eq!( + fork_filter.set_head_priv(b1 + 1).unwrap(), + ForkTransition { current: h1, past: h0 } + ); assert_eq!(fork_filter.current(), h1); - assert!(!fork_filter.set_head_priv(b1)); + assert!(fork_filter.set_head_priv(b1).is_none()); assert_eq!(fork_filter.current(), h1); - assert!(fork_filter.set_head_priv(b1 - 1)); + assert_eq!( + fork_filter.set_head_priv(b1 - 1).unwrap(), + ForkTransition { current: h0, past: h1 } + ); assert_eq!(fork_filter.current(), h0); - assert!(fork_filter.set_head_priv(b1)); + assert!(fork_filter.set_head_priv(b1).is_some()); assert_eq!(fork_filter.current(), h1); - assert!(!fork_filter.set_head_priv(b2 - 1)); + assert!(fork_filter.set_head_priv(b2 - 1).is_none()); assert_eq!(fork_filter.current(), h1); - assert!(fork_filter.set_head_priv(b2)); + assert!(fork_filter.set_head_priv(b2).is_some()); assert_eq!(fork_filter.current(), h2); } } diff --git a/crates/primitives/src/lib.rs b/crates/primitives/src/lib.rs index 0552621523..213e7b1a17 100644 --- a/crates/primitives/src/lib.rs +++ b/crates/primitives/src/lib.rs @@ -35,7 +35,7 @@ pub use block::{Block, BlockHashOrNumber, BlockLocked}; pub use chain::Chain; pub use constants::{EMPTY_OMMER_ROOT, KECCAK_EMPTY, MAINNET_GENESIS}; pub use ethbloom::Bloom; -pub use forkid::{ForkFilter, ForkHash, ForkId, ValidationError}; +pub use forkid::{ForkFilter, ForkHash, ForkId, ForkTransition, ValidationError}; pub use hardfork::Hardfork; pub use header::{Header, HeadersDirection, SealedHeader}; pub use hex_bytes::Bytes;