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
// Copyright (c) 2021-2024 Espresso Systems (espressosys.com)
// This file is part of the HotShot repository.
// You should have received a copy of the MIT License
// along with the HotShot repository. If not, see <https://mit-license.org/>.
use std::{collections::HashSet, num::NonZeroUsize, sync::Arc, time::Duration};
use async_lock::RwLock;
use hotshot_types::traits::node_implementation::NodeType;
use libp2p::{identity::Keypair, Multiaddr};
use libp2p_identity::PeerId;
use super::MAX_GOSSIP_MSG_SIZE;
/// The default Kademlia replication factor
pub const DEFAULT_REPLICATION_FACTOR: Option<NonZeroUsize> = NonZeroUsize::new(10);
/// describe the configuration of the network
#[derive(Default, derive_builder::Builder, derive_more::Debug)]
pub struct NetworkNodeConfig<T: NodeType> {
/// The keypair for the node
#[builder(setter(into, strip_option), default)]
#[debug(skip)]
pub keypair: Option<Keypair>,
/// The address to bind to
#[builder(default)]
pub bind_address: Option<Multiaddr>,
/// Replication factor for entries in the DHT
#[builder(setter(into, strip_option), default = "DEFAULT_REPLICATION_FACTOR")]
pub replication_factor: Option<NonZeroUsize>,
#[builder(default)]
/// Configuration for `GossipSub`
pub gossip_config: GossipConfig,
#[builder(default)]
/// Configuration for `RequestResponse`
pub request_response_config: RequestResponseConfig,
/// list of addresses to connect to at initialization
pub to_connect_addrs: HashSet<(PeerId, Multiaddr)>,
/// republication interval in DHT, must be much less than `ttl`
#[builder(default)]
pub republication_interval: Option<Duration>,
/// expiratiry for records in DHT
#[builder(default)]
pub ttl: Option<Duration>,
/// The stake table. Used for authenticating other nodes. If not supplied
/// we will not check other nodes against the stake table
#[builder(default)]
pub stake_table: Option<Arc<RwLock<T::Membership>>>,
/// The path to the file to save the DHT to
#[builder(default)]
pub dht_file_path: Option<String>,
/// The signed authentication message sent to the remote peer
/// If not supplied we will not send an authentication message during the handshake
#[builder(default)]
pub auth_message: Option<Vec<u8>>,
#[builder(default)]
/// The timeout for DHT lookups.
pub dht_timeout: Option<Duration>,
}
impl<T: NodeType> Clone for NetworkNodeConfig<T> {
fn clone(&self) -> Self {
Self {
keypair: self.keypair.clone(),
bind_address: self.bind_address.clone(),
replication_factor: self.replication_factor,
gossip_config: self.gossip_config.clone(),
request_response_config: self.request_response_config.clone(),
to_connect_addrs: self.to_connect_addrs.clone(),
republication_interval: self.republication_interval,
ttl: self.ttl,
stake_table: self.stake_table.as_ref().map(Arc::clone),
dht_file_path: self.dht_file_path.clone(),
auth_message: self.auth_message.clone(),
dht_timeout: self.dht_timeout,
}
}
}
/// Configuration for Libp2p's Gossipsub
#[derive(Clone, Debug)]
#[allow(missing_docs)]
pub struct GossipConfig {
/// The heartbeat interval
pub heartbeat_interval: Duration,
/// The number of past heartbeats to gossip about
pub history_gossip: usize,
/// The number of past heartbeats to remember the full messages for
pub history_length: usize,
/// The target number of peers in the mesh
pub mesh_n: usize,
/// The maximum number of peers in the mesh
pub mesh_n_high: usize,
/// The minimum number of peers in the mesh
pub mesh_n_low: usize,
/// The minimum number of mesh peers that must be outbound
pub mesh_outbound_min: usize,
/// The maximum gossip message size
pub max_transmit_size: usize,
/// The maximum number of messages in an IHAVE message
pub max_ihave_length: usize,
/// Maximum number of IHAVE messages to accept from a peer within a heartbeat
pub max_ihave_messages: usize,
/// Cache duration for published message IDs
pub published_message_ids_cache_time: Duration,
/// Time to wait for a message requested through IWANT following an IHAVE advertisement
pub iwant_followup_time: Duration,
/// The maximum number of messages we will process in a given RPC
pub max_messages_per_rpc: Option<usize>,
/// Controls how many times we will allow a peer to request the same message id through IWANT gossip before we start ignoring them.
pub gossip_retransmission: u32,
/// If enabled newly created messages will always be sent to all peers that are subscribed to the topic and have a good enough score.
pub flood_publish: bool,
/// The time period that messages are stored in the cache
pub duplicate_cache_time: Duration,
/// Time to live for fanout peers
pub fanout_ttl: Duration,
/// Initial delay in each heartbeat
pub heartbeat_initial_delay: Duration,
/// Affects how many peers we will emit gossip to at each heartbeat
pub gossip_factor: f64,
/// Minimum number of peers to emit gossip to during a heartbeat
pub gossip_lazy: usize,
}
impl Default for GossipConfig {
fn default() -> Self {
Self {
heartbeat_interval: Duration::from_secs(1), // Default of Libp2p
// The following are slightly modified defaults of Libp2p
history_gossip: 6, // The number of past heartbeats to gossip about
history_length: 8, // The number of past heartbeats to remember the full messages for
// The mesh parameters are borrowed from Ethereum:
// https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/p2p-interface.md#the-gossip-domain-gossipsub
mesh_n: 8, // The target number of peers in the mesh
mesh_n_high: 12, // The maximum number of peers in the mesh
mesh_n_low: 6, // The minimum number of peers in the mesh
mesh_outbound_min: 2, // The minimum number of mesh peers that must be outbound
max_ihave_length: 5000,
max_ihave_messages: 10,
published_message_ids_cache_time: Duration::from_secs(60 * 20), // 20 minutes
iwant_followup_time: Duration::from_secs(3),
max_messages_per_rpc: None,
gossip_retransmission: 3,
flood_publish: true,
duplicate_cache_time: Duration::from_secs(60),
fanout_ttl: Duration::from_secs(60),
heartbeat_initial_delay: Duration::from_secs(5),
gossip_factor: 0.25,
gossip_lazy: 6,
max_transmit_size: MAX_GOSSIP_MSG_SIZE, // The maximum gossip message size
}
}
}
/// Configuration for Libp2p's request-response
#[derive(Clone, Debug)]
pub struct RequestResponseConfig {
/// The maximum request size in bytes
pub request_size_maximum: u64,
/// The maximum response size in bytes
pub response_size_maximum: u64,
}
impl Default for RequestResponseConfig {
fn default() -> Self {
Self {
request_size_maximum: 20 * 1024 * 1024,
response_size_maximum: 20 * 1024 * 1024,
}
}
}