reth_network/config.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702
//! Network config support
use crate::{
error::NetworkError,
import::{BlockImport, ProofOfStakeBlockImport},
transactions::TransactionsManagerConfig,
NetworkHandle, NetworkManager,
};
use reth_chainspec::{ChainSpecProvider, EthChainSpec, Hardforks};
use reth_discv4::{Discv4Config, Discv4ConfigBuilder, NatResolver, DEFAULT_DISCOVERY_ADDRESS};
use reth_discv5::NetworkStackId;
use reth_dns_discovery::DnsDiscoveryConfig;
use reth_eth_wire::{
EthNetworkPrimitives, HelloMessage, HelloMessageWithProtocols, NetworkPrimitives, Status,
};
use reth_ethereum_forks::{ForkFilter, Head};
use reth_network_peers::{mainnet_nodes, pk2id, sepolia_nodes, PeerId, TrustedPeer};
use reth_network_types::{PeersConfig, SessionsConfig};
use reth_storage_api::{noop::NoopProvider, BlockNumReader, BlockReader, HeaderProvider};
use reth_tasks::{TaskSpawner, TokioTaskExecutor};
use secp256k1::SECP256K1;
use std::{collections::HashSet, net::SocketAddr, sync::Arc};
// re-export for convenience
use crate::protocol::{IntoRlpxSubProtocol, RlpxSubProtocols};
pub use secp256k1::SecretKey;
/// Convenience function to create a new random [`SecretKey`]
pub fn rng_secret_key() -> SecretKey {
SecretKey::new(&mut rand::thread_rng())
}
/// All network related initialization settings.
#[derive(Debug)]
pub struct NetworkConfig<C, N: NetworkPrimitives = EthNetworkPrimitives> {
/// The client type that can interact with the chain.
///
/// This type is used to fetch the block number after we established a session and received the
/// [Status] block hash.
pub client: C,
/// The node's secret key, from which the node's identity is derived.
pub secret_key: SecretKey,
/// All boot nodes to start network discovery with.
pub boot_nodes: HashSet<TrustedPeer>,
/// How to set up discovery over DNS.
pub dns_discovery_config: Option<DnsDiscoveryConfig>,
/// Address to use for discovery v4.
pub discovery_v4_addr: SocketAddr,
/// How to set up discovery.
pub discovery_v4_config: Option<Discv4Config>,
/// How to set up discovery version 5.
pub discovery_v5_config: Option<reth_discv5::Config>,
/// Address to listen for incoming connections
pub listener_addr: SocketAddr,
/// How to instantiate peer manager.
pub peers_config: PeersConfig,
/// How to configure the [`SessionManager`](crate::session::SessionManager).
pub sessions_config: SessionsConfig,
/// The chain id
pub chain_id: u64,
/// The [`ForkFilter`] to use at launch for authenticating sessions.
///
/// See also <https://github.com/ethereum/EIPs/blob/master/EIPS/eip-2124.md#stale-software-examples>
///
/// For sync from block `0`, this should be the default chain [`ForkFilter`] beginning at the
/// first hardfork, `Frontier` for mainnet.
pub fork_filter: ForkFilter,
/// The block importer type.
pub block_import: Box<dyn BlockImport<N::Block>>,
/// The default mode of the network.
pub network_mode: NetworkMode,
/// The executor to use for spawning tasks.
pub executor: Box<dyn TaskSpawner>,
/// The `Status` message to send to peers at the beginning.
pub status: Status,
/// Sets the hello message for the p2p handshake in `RLPx`
pub hello_message: HelloMessageWithProtocols,
/// Additional protocols to announce and handle in `RLPx`
pub extra_protocols: RlpxSubProtocols,
/// Whether to disable transaction gossip
pub tx_gossip_disabled: bool,
/// How to instantiate transactions manager.
pub transactions_manager_config: TransactionsManagerConfig,
/// The NAT resolver for external IP
pub nat: Option<NatResolver>,
}
// === impl NetworkConfig ===
impl<N: NetworkPrimitives> NetworkConfig<(), N> {
/// Convenience method for creating the corresponding builder type
pub fn builder(secret_key: SecretKey) -> NetworkConfigBuilder<N> {
NetworkConfigBuilder::new(secret_key)
}
/// Convenience method for creating the corresponding builder type with a random secret key.
pub fn builder_with_rng_secret_key() -> NetworkConfigBuilder<N> {
NetworkConfigBuilder::with_rng_secret_key()
}
}
impl<C, N: NetworkPrimitives> NetworkConfig<C, N> {
/// Create a new instance with all mandatory fields set, rest is field with defaults.
pub fn new(client: C, secret_key: SecretKey) -> Self
where
C: ChainSpecProvider<ChainSpec: Hardforks>,
{
NetworkConfig::builder(secret_key).build(client)
}
/// Apply a function to the config.
pub fn apply<F>(self, f: F) -> Self
where
F: FnOnce(Self) -> Self,
{
f(self)
}
/// Sets the config to use for the discovery v4 protocol.
pub fn set_discovery_v4(mut self, discovery_config: Discv4Config) -> Self {
self.discovery_v4_config = Some(discovery_config);
self
}
/// Sets the address for the incoming `RLPx` connection listener.
pub const fn set_listener_addr(mut self, listener_addr: SocketAddr) -> Self {
self.listener_addr = listener_addr;
self
}
/// Returns the address for the incoming `RLPx` connection listener.
pub const fn listener_addr(&self) -> &SocketAddr {
&self.listener_addr
}
}
impl<C, N> NetworkConfig<C, N>
where
C: BlockNumReader + 'static,
N: NetworkPrimitives,
{
/// Convenience method for calling [`NetworkManager::new`].
pub async fn manager(self) -> Result<NetworkManager<N>, NetworkError> {
NetworkManager::new(self).await
}
}
impl<C, N> NetworkConfig<C, N>
where
N: NetworkPrimitives,
C: BlockReader<Block = N::Block, Receipt = N::Receipt, Header = N::BlockHeader>
+ HeaderProvider
+ Clone
+ Unpin
+ 'static,
{
/// Starts the networking stack given a [`NetworkConfig`] and returns a handle to the network.
pub async fn start_network(self) -> Result<NetworkHandle<N>, NetworkError> {
let client = self.client.clone();
let (handle, network, _txpool, eth) = NetworkManager::builder::<C>(self)
.await?
.request_handler::<C>(client)
.split_with_handle();
tokio::task::spawn(network);
tokio::task::spawn(eth);
Ok(handle)
}
}
/// Builder for [`NetworkConfig`](struct.NetworkConfig.html).
#[derive(Debug)]
pub struct NetworkConfigBuilder<N: NetworkPrimitives = EthNetworkPrimitives> {
/// The node's secret key, from which the node's identity is derived.
secret_key: SecretKey,
/// How to configure discovery over DNS.
dns_discovery_config: Option<DnsDiscoveryConfig>,
/// How to set up discovery version 4.
discovery_v4_builder: Option<Discv4ConfigBuilder>,
/// How to set up discovery version 5.
discovery_v5_builder: Option<reth_discv5::ConfigBuilder>,
/// All boot nodes to start network discovery with.
boot_nodes: HashSet<TrustedPeer>,
/// Address to use for discovery
discovery_addr: Option<SocketAddr>,
/// Listener for incoming connections
listener_addr: Option<SocketAddr>,
/// How to instantiate peer manager.
peers_config: Option<PeersConfig>,
/// How to configure the sessions manager
sessions_config: Option<SessionsConfig>,
/// The default mode of the network.
network_mode: NetworkMode,
/// The executor to use for spawning tasks.
executor: Option<Box<dyn TaskSpawner>>,
/// Sets the hello message for the p2p handshake in `RLPx`
hello_message: Option<HelloMessageWithProtocols>,
/// The executor to use for spawning tasks.
extra_protocols: RlpxSubProtocols,
/// Head used to start set for the fork filter and status.
head: Option<Head>,
/// Whether tx gossip is disabled
tx_gossip_disabled: bool,
/// The block importer type
block_import: Option<Box<dyn BlockImport<N::Block>>>,
/// How to instantiate transactions manager.
transactions_manager_config: TransactionsManagerConfig,
/// The NAT resolver for external IP
nat: Option<NatResolver>,
}
// === impl NetworkConfigBuilder ===
#[allow(missing_docs)]
impl<N: NetworkPrimitives> NetworkConfigBuilder<N> {
/// Create a new builder instance with a random secret key.
pub fn with_rng_secret_key() -> Self {
Self::new(rng_secret_key())
}
/// Create a new builder instance with the given secret key.
pub fn new(secret_key: SecretKey) -> Self {
Self {
secret_key,
dns_discovery_config: Some(Default::default()),
discovery_v4_builder: Some(Default::default()),
discovery_v5_builder: None,
boot_nodes: Default::default(),
discovery_addr: None,
listener_addr: None,
peers_config: None,
sessions_config: None,
network_mode: Default::default(),
executor: None,
hello_message: None,
extra_protocols: Default::default(),
head: None,
tx_gossip_disabled: false,
block_import: None,
transactions_manager_config: Default::default(),
nat: None,
}
}
/// Apply a function to the builder.
pub fn apply<F>(self, f: F) -> Self
where
F: FnOnce(Self) -> Self,
{
f(self)
}
/// Returns the configured [`PeerId`]
pub fn get_peer_id(&self) -> PeerId {
pk2id(&self.secret_key.public_key(SECP256K1))
}
/// Returns the configured [`SecretKey`], from which the node's identity is derived.
pub const fn secret_key(&self) -> &SecretKey {
&self.secret_key
}
/// Sets the [`NetworkMode`].
pub const fn network_mode(mut self, network_mode: NetworkMode) -> Self {
self.network_mode = network_mode;
self
}
/// Configures the network to use proof-of-work.
///
/// This effectively allows block propagation in the `eth` sub-protocol, which has been
/// soft-deprecated with ethereum `PoS` after the merge. Even if block propagation is
/// technically allowed, according to the eth protocol, it is not expected to be used in `PoS`
/// networks and peers are supposed to terminate the connection if they receive a `NewBlock`
/// message.
pub const fn with_pow(self) -> Self {
self.network_mode(NetworkMode::Work)
}
/// Sets the highest synced block.
///
/// This is used to construct the appropriate [`ForkFilter`] and [`Status`] message.
///
/// If not set, this defaults to the genesis specified by the current chain specification.
pub const fn set_head(mut self, head: Head) -> Self {
self.head = Some(head);
self
}
/// Sets the `HelloMessage` to send when connecting to peers.
///
/// ```
/// # use reth_eth_wire::HelloMessage;
/// # use reth_network::NetworkConfigBuilder;
/// # fn builder(builder: NetworkConfigBuilder) {
/// let peer_id = builder.get_peer_id();
/// builder.hello_message(HelloMessage::builder(peer_id).build());
/// # }
/// ```
pub fn hello_message(mut self, hello_message: HelloMessageWithProtocols) -> Self {
self.hello_message = Some(hello_message);
self
}
/// Set a custom peer config for how peers are handled
pub fn peer_config(mut self, config: PeersConfig) -> Self {
self.peers_config = Some(config);
self
}
/// Sets the executor to use for spawning tasks.
///
/// If `None`, then [`tokio::spawn`] is used for spawning tasks.
pub fn with_task_executor(mut self, executor: Box<dyn TaskSpawner>) -> Self {
self.executor = Some(executor);
self
}
/// Sets a custom config for how sessions are handled.
pub const fn sessions_config(mut self, config: SessionsConfig) -> Self {
self.sessions_config = Some(config);
self
}
/// Configures the transactions manager with the given config.
pub const fn transactions_manager_config(mut self, config: TransactionsManagerConfig) -> Self {
self.transactions_manager_config = config;
self
}
/// Sets the discovery and listener address
///
/// This is a convenience function for both [`NetworkConfigBuilder::listener_addr`] and
/// [`NetworkConfigBuilder::discovery_addr`].
///
/// By default, both are on the same port:
/// [`DEFAULT_DISCOVERY_PORT`](reth_discv4::DEFAULT_DISCOVERY_PORT)
pub const fn set_addrs(self, addr: SocketAddr) -> Self {
self.listener_addr(addr).discovery_addr(addr)
}
/// Sets the socket address the network will listen on.
///
/// By default, this is [`DEFAULT_DISCOVERY_ADDRESS`]
pub const fn listener_addr(mut self, listener_addr: SocketAddr) -> Self {
self.listener_addr = Some(listener_addr);
self
}
/// Sets the port of the address the network will listen on.
///
/// By default, this is [`DEFAULT_DISCOVERY_PORT`](reth_discv4::DEFAULT_DISCOVERY_PORT)
pub fn listener_port(mut self, port: u16) -> Self {
self.listener_addr.get_or_insert(DEFAULT_DISCOVERY_ADDRESS).set_port(port);
self
}
/// Sets the socket address the discovery network will listen on
pub const fn discovery_addr(mut self, discovery_addr: SocketAddr) -> Self {
self.discovery_addr = Some(discovery_addr);
self
}
/// Sets the port of the address the discovery network will listen on.
///
/// By default, this is [`DEFAULT_DISCOVERY_PORT`](reth_discv4::DEFAULT_DISCOVERY_PORT)
pub fn discovery_port(mut self, port: u16) -> Self {
self.discovery_addr.get_or_insert(DEFAULT_DISCOVERY_ADDRESS).set_port(port);
self
}
/// Sets the discovery port to an unused port.
/// This is useful for testing.
pub fn with_unused_discovery_port(self) -> Self {
self.discovery_port(0)
}
/// Sets the listener port to an unused port.
/// This is useful for testing.
pub fn with_unused_listener_port(self) -> Self {
self.listener_port(0)
}
/// Sets the external ip resolver to use for discovery v4.
///
/// If no [`Discv4ConfigBuilder`] is set via [`Self::discovery`], this will create a new one.
///
/// This is a convenience function for setting the external ip resolver on the default
/// [`Discv4Config`] config.
pub fn external_ip_resolver(mut self, resolver: NatResolver) -> Self {
self.discovery_v4_builder
.get_or_insert_with(Discv4Config::builder)
.external_ip_resolver(Some(resolver));
self.nat = Some(resolver);
self
}
/// Sets the discv4 config to use.
pub fn discovery(mut self, builder: Discv4ConfigBuilder) -> Self {
self.discovery_v4_builder = Some(builder);
self
}
/// Sets the discv5 config to use.
pub fn discovery_v5(mut self, builder: reth_discv5::ConfigBuilder) -> Self {
self.discovery_v5_builder = Some(builder);
self
}
/// Sets the dns discovery config to use.
pub fn dns_discovery(mut self, config: DnsDiscoveryConfig) -> Self {
self.dns_discovery_config = Some(config);
self
}
/// Convenience function for setting [`Self::boot_nodes`] to the mainnet boot nodes.
pub fn mainnet_boot_nodes(self) -> Self {
self.boot_nodes(mainnet_nodes())
}
/// Convenience function for setting [`Self::boot_nodes`] to the sepolia boot nodes.
pub fn sepolia_boot_nodes(self) -> Self {
self.boot_nodes(sepolia_nodes())
}
/// Sets the boot nodes to use to bootstrap the configured discovery services (discv4 + discv5).
pub fn boot_nodes<T: Into<TrustedPeer>>(mut self, nodes: impl IntoIterator<Item = T>) -> Self {
self.boot_nodes = nodes.into_iter().map(Into::into).collect();
self
}
/// Returns an iterator over all configured boot nodes.
pub fn boot_nodes_iter(&self) -> impl Iterator<Item = &TrustedPeer> + '_ {
self.boot_nodes.iter()
}
/// Disable the DNS discovery.
pub fn disable_dns_discovery(mut self) -> Self {
self.dns_discovery_config = None;
self
}
// Disable nat
pub const fn disable_nat(mut self) -> Self {
self.nat = None;
self
}
/// Disables all discovery.
pub fn disable_discovery(self) -> Self {
self.disable_discv4_discovery().disable_dns_discovery().disable_nat()
}
/// Disables all discovery if the given condition is true.
pub fn disable_discovery_if(self, disable: bool) -> Self {
if disable {
self.disable_discovery()
} else {
self
}
}
/// Disable the Discv4 discovery.
pub fn disable_discv4_discovery(mut self) -> Self {
self.discovery_v4_builder = None;
self
}
/// Disable the DNS discovery if the given condition is true.
pub fn disable_dns_discovery_if(self, disable: bool) -> Self {
if disable {
self.disable_dns_discovery()
} else {
self
}
}
/// Disable the Discv4 discovery if the given condition is true.
pub fn disable_discv4_discovery_if(self, disable: bool) -> Self {
if disable {
self.disable_discv4_discovery()
} else {
self
}
}
/// Adds a new additional protocol to the `RLPx` sub-protocol list.
pub fn add_rlpx_sub_protocol(mut self, protocol: impl IntoRlpxSubProtocol) -> Self {
self.extra_protocols.push(protocol);
self
}
/// Sets whether tx gossip is disabled.
pub const fn disable_tx_gossip(mut self, disable_tx_gossip: bool) -> Self {
self.tx_gossip_disabled = disable_tx_gossip;
self
}
/// Sets the block import type.
pub fn block_import(mut self, block_import: Box<dyn BlockImport<N::Block>>) -> Self {
self.block_import = Some(block_import);
self
}
/// Convenience function for creating a [`NetworkConfig`] with a noop provider that does
/// nothing.
pub fn build_with_noop_provider<ChainSpec>(
self,
chain_spec: Arc<ChainSpec>,
) -> NetworkConfig<NoopProvider<ChainSpec>, N>
where
ChainSpec: EthChainSpec + Hardforks + 'static,
{
self.build(NoopProvider::eth(chain_spec))
}
/// Sets the NAT resolver for external IP.
pub const fn add_nat(mut self, nat: Option<NatResolver>) -> Self {
self.nat = nat;
self
}
/// Consumes the type and creates the actual [`NetworkConfig`]
/// for the given client type that can interact with the chain.
///
/// The given client is to be used for interacting with the chain, for example fetching the
/// corresponding block for a given block hash we receive from a peer in the status message when
/// establishing a connection.
pub fn build<C>(self, client: C) -> NetworkConfig<C, N>
where
C: ChainSpecProvider<ChainSpec: Hardforks>,
{
let peer_id = self.get_peer_id();
let chain_spec = client.chain_spec();
let Self {
secret_key,
mut dns_discovery_config,
discovery_v4_builder,
mut discovery_v5_builder,
boot_nodes,
discovery_addr,
listener_addr,
peers_config,
sessions_config,
network_mode,
executor,
hello_message,
extra_protocols,
head,
tx_gossip_disabled,
block_import,
transactions_manager_config,
nat,
} = self;
discovery_v5_builder = discovery_v5_builder.map(|mut builder| {
if let Some(network_stack_id) = NetworkStackId::id(&chain_spec) {
let fork_id = chain_spec.latest_fork_id();
builder = builder.fork(network_stack_id, fork_id)
}
builder
});
let listener_addr = listener_addr.unwrap_or(DEFAULT_DISCOVERY_ADDRESS);
let mut hello_message =
hello_message.unwrap_or_else(|| HelloMessage::builder(peer_id).build());
hello_message.port = listener_addr.port();
let head = head.unwrap_or_else(|| Head {
hash: chain_spec.genesis_hash(),
number: 0,
timestamp: chain_spec.genesis().timestamp,
difficulty: chain_spec.genesis().difficulty,
total_difficulty: chain_spec.genesis().difficulty,
});
// set the status
let status = Status::spec_builder(&chain_spec, &head).build();
// set a fork filter based on the chain spec and head
let fork_filter = chain_spec.fork_filter(head);
// get the chain id
let chain_id = chain_spec.chain().id();
// If default DNS config is used then we add the known dns network to bootstrap from
if let Some(dns_networks) =
dns_discovery_config.as_mut().and_then(|c| c.bootstrap_dns_networks.as_mut())
{
if dns_networks.is_empty() {
if let Some(link) = chain_spec.chain().public_dns_network_protocol() {
dns_networks.insert(link.parse().expect("is valid DNS link entry"));
}
}
}
NetworkConfig {
client,
secret_key,
boot_nodes,
dns_discovery_config,
discovery_v4_config: discovery_v4_builder.map(|builder| builder.build()),
discovery_v5_config: discovery_v5_builder.map(|builder| builder.build()),
discovery_v4_addr: discovery_addr.unwrap_or(DEFAULT_DISCOVERY_ADDRESS),
listener_addr,
peers_config: peers_config.unwrap_or_default(),
sessions_config: sessions_config.unwrap_or_default(),
chain_id,
block_import: block_import.unwrap_or_else(|| Box::<ProofOfStakeBlockImport>::default()),
network_mode,
executor: executor.unwrap_or_else(|| Box::<TokioTaskExecutor>::default()),
status,
hello_message,
extra_protocols,
fork_filter,
tx_gossip_disabled,
transactions_manager_config,
nat,
}
}
}
/// Describes the mode of the network wrt. POS or POW.
///
/// This affects block propagation in the `eth` sub-protocol [EIP-3675](https://eips.ethereum.org/EIPS/eip-3675#devp2p)
///
/// In POS `NewBlockHashes` and `NewBlock` messages become invalid.
#[derive(Debug, Clone, Copy, Eq, PartialEq, Default)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum NetworkMode {
/// Network is in proof-of-work mode.
Work,
/// Network is in proof-of-stake mode
#[default]
Stake,
}
// === impl NetworkMode ===
impl NetworkMode {
/// Returns true if network has entered proof-of-stake
pub const fn is_stake(&self) -> bool {
matches!(self, Self::Stake)
}
}
#[cfg(test)]
mod tests {
use super::*;
use rand::thread_rng;
use reth_chainspec::{Chain, MAINNET};
use reth_dns_discovery::tree::LinkEntry;
use reth_primitives::ForkHash;
use reth_storage_api::noop::NoopProvider;
use std::sync::Arc;
fn builder() -> NetworkConfigBuilder {
let secret_key = SecretKey::new(&mut thread_rng());
NetworkConfigBuilder::new(secret_key)
}
#[test]
fn test_network_dns_defaults() {
let config = builder().build(NoopProvider::default());
let dns = config.dns_discovery_config.unwrap();
let bootstrap_nodes = dns.bootstrap_dns_networks.unwrap();
let mainnet_dns: LinkEntry =
Chain::mainnet().public_dns_network_protocol().unwrap().parse().unwrap();
assert!(bootstrap_nodes.contains(&mainnet_dns));
assert_eq!(bootstrap_nodes.len(), 1);
}
#[test]
fn test_network_fork_filter_default() {
let mut chain_spec = Arc::clone(&MAINNET);
// remove any `next` fields we would have by removing all hardforks
Arc::make_mut(&mut chain_spec).hardforks = Default::default();
// check that the forkid is initialized with the genesis and no other forks
let genesis_fork_hash = ForkHash::from(chain_spec.genesis_hash());
// enforce that the fork_id set in the status is consistent with the generated fork filter
let config = builder().build_with_noop_provider(chain_spec);
let status = config.status;
let fork_filter = config.fork_filter;
// assert that there are no other forks
assert_eq!(status.forkid.next, 0);
// assert the same thing for the fork_filter
assert_eq!(fork_filter.current().next, 0);
// check status and fork_filter forkhash
assert_eq!(status.forkid.hash, genesis_fork_hash);
assert_eq!(fork_filter.current().hash, genesis_fork_hash);
}
}