1#![warn(missing_docs)]
4
5mod behaviour;
6mod control_list;
7pub mod error;
8pub mod metrics;
10mod monitor;
11mod routing;
12mod service;
13mod transport;
14mod utils;
15mod worker;
16
17use std::fmt::{self, Debug, Display};
18
19use ave_common::identity::PublicKey;
20use borsh::{BorshDeserialize, BorshSerialize};
21pub use control_list::Config as ControlListConfig;
22pub use error::Error;
23pub use libp2p::{
24 PeerId,
25 identity::{
26 PublicKey as PublicKeyLibP2P, ed25519::PublicKey as PublicKeyEd25519,
27 },
28};
29pub use monitor::*;
30pub use routing::{Config as RoutingConfig, RoutingNode};
31pub use service::NetworkService;
32pub use utils::NetworkState;
33pub use worker::NetworkWorker;
34
35use bytes::Bytes;
36use serde::{Deserialize, Serialize};
37
38pub use crate::utils::ReqResConfig;
39
40#[cfg(all(feature = "test", not(test), not(debug_assertions)))]
41compile_error!(
42 "The 'test' feature should only be used during development/testing"
43);
44
45#[derive(Serialize, Deserialize, Debug, Clone)]
51#[serde(rename_all = "snake_case")]
52pub enum MachineSpec {
53 Profile(MachineProfile),
55 Custom {
57 ram_mb: u64,
59 cpu_cores: usize,
61 },
62}
63
64#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq)]
78#[serde(rename_all = "snake_case")]
79pub enum MachineProfile {
80 Nano,
82 Micro,
84 Small,
86 Medium,
88 Large,
90 XLarge,
92 #[serde(rename = "2xlarge")]
94 XXLarge,
95}
96
97impl MachineProfile {
98 pub const fn ram_mb(self) -> u64 {
100 match self {
101 Self::Nano => 512,
102 Self::Micro => 1_024,
103 Self::Small => 2_048,
104 Self::Medium => 4_096,
105 Self::Large => 8_192,
106 Self::XLarge => 16_384,
107 Self::XXLarge => 32_768,
108 }
109 }
110
111 pub const fn cpu_cores(self) -> usize {
113 match self {
114 Self::Nano => 2,
115 Self::Micro => 2,
116 Self::Small => 2,
117 Self::Medium => 2,
118 Self::Large => 2,
119 Self::XLarge => 4,
120 Self::XXLarge => 8,
121 }
122 }
123}
124
125impl Display for MachineProfile {
126 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
127 match self {
128 Self::Nano => write!(f, "nano"),
129 Self::Micro => write!(f, "micro"),
130 Self::Small => write!(f, "small"),
131 Self::Medium => write!(f, "medium"),
132 Self::Large => write!(f, "large"),
133 Self::XLarge => write!(f, "xlarge"),
134 Self::XXLarge => write!(f, "2xlarge"),
135 }
136 }
137}
138
139pub struct ResolvedSpec {
142 pub ram_mb: u64,
144 pub cpu_cores: usize,
146}
147
148pub fn resolve_spec(spec: Option<MachineSpec>) -> ResolvedSpec {
154 match spec {
155 Some(MachineSpec::Profile(p)) => ResolvedSpec {
156 ram_mb: p.ram_mb(),
157 cpu_cores: p.cpu_cores(),
158 },
159 Some(MachineSpec::Custom { ram_mb, cpu_cores }) => {
160 ResolvedSpec { ram_mb, cpu_cores }
161 }
162 None => ResolvedSpec {
163 ram_mb: detect_ram_mb(),
164 cpu_cores: detect_cpu_cores(),
165 },
166 }
167}
168
169pub(crate) fn detect_ram_mb() -> u64 {
171 #[cfg(target_os = "linux")]
172 {
173 if let Ok(meminfo) = std::fs::read_to_string("/proc/meminfo") {
174 for line in meminfo.lines() {
175 if let Some(rest) = line.strip_prefix("MemTotal:")
176 && let Some(kb_str) = rest.split_whitespace().next()
177 && let Ok(kb) = kb_str.parse::<u64>()
178 {
179 return kb / 1024;
180 }
181 }
182 }
183 }
184 4_096
185}
186
187pub(crate) fn detect_cpu_cores() -> usize {
189 std::thread::available_parallelism()
190 .map(|n| n.get())
191 .unwrap_or(2)
192}
193
194#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Default)]
215#[serde(tag = "type", rename_all = "snake_case")]
216pub enum MemoryLimitsConfig {
217 #[default]
219 Disabled,
220 Percentage {
223 value: f64,
225 },
226 Mb {
228 value: usize,
230 },
231}
232
233impl MemoryLimitsConfig {
234 pub fn validate(&self) -> Result<(), String> {
236 if let Self::Percentage { value } = self
237 && (*value <= 0.0 || *value > 1.0)
238 {
239 return Err(format!(
240 "network.memory_limits percentage must be in range (0.0, 1.0], got {}",
241 value
242 ));
243 }
244
245 Ok(())
246 }
247}
248
249impl Display for MemoryLimitsConfig {
250 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
251 match self {
252 Self::Disabled => write!(f, "disabled"),
253 Self::Percentage { value } => {
254 write!(f, "{:.0}% of system RAM", value * 100.0)
255 }
256 Self::Mb { value } => write!(f, "{} MB", value),
257 }
258 }
259}
260
261#[derive(Debug, Clone, Deserialize, Serialize)]
262#[serde(default)]
263#[serde(rename_all = "snake_case")]
264pub struct Config {
266 pub node_type: NodeType,
268
269 pub listen_addresses: Vec<String>,
271
272 pub external_addresses: Vec<String>,
274
275 pub boot_nodes: Vec<RoutingNode>,
277
278 pub routing: routing::Config,
280
281 pub control_list: control_list::Config,
283
284 pub memory_limits: MemoryLimitsConfig,
286
287 #[serde(default = "default_max_app_message_bytes")]
289 pub max_app_message_bytes: usize,
290
291 #[serde(default = "default_max_pending_outbound_bytes_per_peer")]
294 pub max_pending_outbound_bytes_per_peer: usize,
295
296 #[serde(default = "default_max_pending_inbound_bytes_per_peer")]
299 pub max_pending_inbound_bytes_per_peer: usize,
300
301 #[serde(default = "default_max_pending_outbound_bytes_total")]
304 pub max_pending_outbound_bytes_total: usize,
305
306 #[serde(default = "default_max_pending_inbound_bytes_total")]
309 pub max_pending_inbound_bytes_total: usize,
310}
311
312impl Config {
313 pub fn new(
315 node_type: NodeType,
316 listen_addresses: Vec<String>,
317 external_addresses: Vec<String>,
318 boot_nodes: Vec<RoutingNode>,
319 ) -> Self {
320 Self {
321 boot_nodes,
322 node_type,
323 listen_addresses,
324 external_addresses,
325 routing: routing::Config::default(),
326 control_list: control_list::Config::default(),
327 memory_limits: MemoryLimitsConfig::default(),
328 max_app_message_bytes: default_max_app_message_bytes(),
329 max_pending_outbound_bytes_per_peer:
330 default_max_pending_outbound_bytes_per_peer(),
331 max_pending_inbound_bytes_per_peer:
332 default_max_pending_inbound_bytes_per_peer(),
333 max_pending_outbound_bytes_total:
334 default_max_pending_outbound_bytes_total(),
335 max_pending_inbound_bytes_total:
336 default_max_pending_inbound_bytes_total(),
337 }
338 }
339}
340
341const fn default_max_app_message_bytes() -> usize {
342 crate::utils::MAX_APP_MESSAGE_BYTES
343}
344
345const fn default_max_pending_outbound_bytes_per_peer() -> usize {
346 crate::utils::DEFAULT_MAX_PENDING_OUTBOUND_BYTES_PER_PEER
347}
348
349const fn default_max_pending_inbound_bytes_per_peer() -> usize {
350 crate::utils::DEFAULT_MAX_PENDING_INBOUND_BYTES_PER_PEER
351}
352
353const fn default_max_pending_outbound_bytes_total() -> usize {
354 crate::utils::DEFAULT_MAX_PENDING_OUTBOUND_BYTES_TOTAL
355}
356
357const fn default_max_pending_inbound_bytes_total() -> usize {
358 crate::utils::DEFAULT_MAX_PENDING_INBOUND_BYTES_TOTAL
359}
360
361impl Default for Config {
362 fn default() -> Self {
363 Self {
364 node_type: NodeType::default(),
365 listen_addresses: Vec::default(),
366 external_addresses: Vec::default(),
367 boot_nodes: Vec::default(),
368 routing: routing::Config::default(),
369 control_list: control_list::Config::default(),
370 memory_limits: MemoryLimitsConfig::default(),
371 max_app_message_bytes: default_max_app_message_bytes(),
372 max_pending_outbound_bytes_per_peer:
373 default_max_pending_outbound_bytes_per_peer(),
374 max_pending_inbound_bytes_per_peer:
375 default_max_pending_inbound_bytes_per_peer(),
376 max_pending_outbound_bytes_total:
377 default_max_pending_outbound_bytes_total(),
378 max_pending_inbound_bytes_total:
379 default_max_pending_inbound_bytes_total(),
380 }
381 }
382}
383
384#[derive(Debug, Clone, Deserialize, Default, PartialEq, Eq, Serialize)]
386pub enum NodeType {
387 #[default]
389 Bootstrap,
390 Addressable,
392 Ephemeral,
394}
395
396impl fmt::Display for NodeType {
397 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
398 match self {
399 Self::Bootstrap => write!(f, "Bootstrap"),
400 Self::Addressable => write!(f, "Addressable"),
401 Self::Ephemeral => write!(f, "Ephemeral"),
402 }
403 }
404}
405
406#[derive(Debug)]
408pub enum Command {
409 SendMessage {
411 peer: PeerId,
413 message: Bytes,
415 },
416}
417
418#[derive(Debug, Serialize, Deserialize, Clone)]
420pub enum Event {
421 StateChanged(utils::NetworkState),
423
424 Error(Error),
426}
427
428#[derive(Debug, Serialize, Deserialize)]
430pub enum CommandHelper<T>
431where
432 T: Debug + Serialize,
433{
434 SendMessage {
436 message: T,
438 },
439 ReceivedMessage {
441 sender: [u8; 32],
443 message: Bytes,
445 },
446}
447
448#[derive(
450 Debug, Serialize, Deserialize, Clone, BorshDeserialize, BorshSerialize,
451)]
452pub struct ComunicateInfo {
453 pub request_id: String,
455 pub version: u64,
457 pub receiver: PublicKey,
459 pub receiver_actor: String,
461}