use std::{
net::{
IpAddr,
Ipv4Addr,
},
path::PathBuf,
time::Duration,
};
use clap::Args;
use fuel_core_interfaces::common::fuel_crypto;
use fuel_p2p::{
config::{
NotInitialized,
P2PConfig,
},
gossipsub_config::default_gossipsub_builder,
Multiaddr,
};
#[derive(Debug, Clone, Args)]
pub struct P2PArgs {
#[clap(long = "keypair")]
pub keypair: Option<PathBuf>,
#[clap(long = "network", default_value = "")]
pub network: String,
#[clap(long = "address")]
pub address: Option<IpAddr>,
#[clap(long = "public_address")]
pub public_address: Option<Multiaddr>,
#[clap(long = "peering_port", default_value = "4001")]
pub peering_port: u16,
#[clap(long = "max_block_size", default_value = "100000")]
pub max_block_size: usize,
#[clap(long = "bootstrap_nodes")]
pub bootstrap_nodes: Vec<Multiaddr>,
#[clap(long = "reserved_nodes")]
pub reserved_nodes: Vec<Multiaddr>,
#[clap(long = "reserved_nodes_only_mode")]
pub reserved_nodes_only_mode: bool,
#[clap(long = "enable_mdns")]
pub enable_mdns: bool,
#[clap(long = "max_peers_connected", default_value = "50")]
pub max_peers_connected: usize,
#[clap(long = "random_walk", default_value = "0")]
pub random_walk: u64,
#[clap(long = "allow_private_addresses")]
pub allow_private_addresses: bool,
#[clap(long = "connection_idle_timeout", default_value = "120")]
pub connection_idle_timeout: u64,
#[clap(long = "info_interval", default_value = "3")]
pub info_interval: u64,
#[clap(long = "identify_interval", default_value = "5")]
pub identify_interval: u64,
#[clap(long = "topics", default_values = &["new_tx", "new_block", "consensus_vote"])]
pub topics: Vec<String>,
#[clap(long = "max_mesh_size", default_value = "12")]
pub max_mesh_size: usize,
#[clap(long = "min_mesh_size", default_value = "4")]
pub min_mesh_size: usize,
#[clap(long = "ideal_mesh_size", default_value = "6")]
pub ideal_mesh_size: usize,
#[clap(long = "history_length", default_value = "5")]
pub history_length: usize,
#[clap(long = "history_gossip", default_value = "3")]
pub history_gossip: usize,
#[clap(long = "heartbeat_interval", default_value = "1")]
pub heartbeat_interval: u64,
#[clap(long = "max_transmit_size", default_value = "2048")]
pub max_transmit_size: usize,
#[clap(long = "request_timeout", default_value = "20")]
pub request_timeout: u64,
#[clap(long = "connection_keep_alive", default_value = "20")]
pub connection_keep_alive: u64,
}
impl P2PArgs {
pub fn into_config(self, metrics: bool) -> anyhow::Result<P2PConfig<NotInitialized>> {
let local_keypair = {
match self.keypair {
Some(path) => {
let phrase = std::fs::read_to_string(path)?;
let secret_key =
fuel_crypto::SecretKey::new_from_mnemonic_phrase_with_path(
&phrase,
"m/44'/60'/0'/0/0",
)?;
fuel_p2p::config::convert_to_libp2p_keypair(&mut secret_key.to_vec())?
}
_ => {
let mut rand = fuel_crypto::rand::thread_rng();
let secret_key = fuel_crypto::SecretKey::random(&mut rand);
fuel_p2p::config::convert_to_libp2p_keypair(&mut secret_key.to_vec())?
}
}
};
let reserved_nodes_count = self.reserved_nodes.len();
let gossipsub_config = default_gossipsub_builder()
.mesh_n(self.ideal_mesh_size + reserved_nodes_count)
.mesh_n_low(self.min_mesh_size + reserved_nodes_count)
.mesh_n_high(self.max_mesh_size + reserved_nodes_count)
.history_length(self.history_length)
.history_gossip(self.history_gossip)
.heartbeat_interval(Duration::from_secs(self.heartbeat_interval))
.max_transmit_size(self.max_transmit_size)
.build()
.expect("valid gossipsub configuration");
let random_walk = if self.random_walk == 0 {
None
} else {
Some(Duration::from_secs(self.random_walk))
};
Ok(P2PConfig {
keypair: local_keypair,
network_name: self.network,
checksum: Default::default(),
address: self
.address
.unwrap_or_else(|| IpAddr::V4(Ipv4Addr::from([0, 0, 0, 0]))),
public_address: self.public_address,
tcp_port: self.peering_port,
max_block_size: self.max_block_size,
bootstrap_nodes: self.bootstrap_nodes,
reserved_nodes: self.reserved_nodes,
reserved_nodes_only_mode: self.reserved_nodes_only_mode,
enable_mdns: self.enable_mdns,
max_peers_connected: self.max_peers_connected,
allow_private_addresses: self.allow_private_addresses,
random_walk,
connection_idle_timeout: Some(Duration::from_secs(
self.connection_idle_timeout,
)),
topics: self.topics,
gossipsub_config,
set_request_timeout: Duration::from_secs(self.request_timeout),
set_connection_keep_alive: Duration::from_secs(self.connection_keep_alive),
info_interval: Some(Duration::from_secs(self.info_interval)),
identify_interval: Some(Duration::from_secs(self.identify_interval)),
metrics,
state: NotInitialized,
})
}
}