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 #[serde(default)]
268 pub safe_mode: bool,
269
270 pub node_type: NodeType,
272
273 pub listen_addresses: Vec<String>,
275
276 pub external_addresses: Vec<String>,
278
279 pub boot_nodes: Vec<RoutingNode>,
281
282 pub routing: routing::Config,
284
285 pub control_list: control_list::Config,
287
288 pub memory_limits: MemoryLimitsConfig,
290
291 #[serde(default = "default_max_app_message_bytes")]
293 pub max_app_message_bytes: usize,
294
295 #[serde(default = "default_max_pending_outbound_bytes_per_peer")]
298 pub max_pending_outbound_bytes_per_peer: usize,
299
300 #[serde(default = "default_max_pending_inbound_bytes_per_peer")]
303 pub max_pending_inbound_bytes_per_peer: usize,
304
305 #[serde(default = "default_max_pending_outbound_bytes_total")]
308 pub max_pending_outbound_bytes_total: usize,
309
310 #[serde(default = "default_max_pending_inbound_bytes_total")]
313 pub max_pending_inbound_bytes_total: usize,
314}
315
316impl Config {
317 pub fn new(
319 node_type: NodeType,
320 listen_addresses: Vec<String>,
321 external_addresses: Vec<String>,
322 boot_nodes: Vec<RoutingNode>,
323 ) -> Self {
324 Self {
325 safe_mode: false,
326 boot_nodes,
327 node_type,
328 listen_addresses,
329 external_addresses,
330 routing: routing::Config::default(),
331 control_list: control_list::Config::default(),
332 memory_limits: MemoryLimitsConfig::default(),
333 max_app_message_bytes: default_max_app_message_bytes(),
334 max_pending_outbound_bytes_per_peer:
335 default_max_pending_outbound_bytes_per_peer(),
336 max_pending_inbound_bytes_per_peer:
337 default_max_pending_inbound_bytes_per_peer(),
338 max_pending_outbound_bytes_total:
339 default_max_pending_outbound_bytes_total(),
340 max_pending_inbound_bytes_total:
341 default_max_pending_inbound_bytes_total(),
342 }
343 }
344}
345
346const fn default_max_app_message_bytes() -> usize {
347 crate::utils::MAX_APP_MESSAGE_BYTES
348}
349
350const fn default_max_pending_outbound_bytes_per_peer() -> usize {
351 crate::utils::DEFAULT_MAX_PENDING_OUTBOUND_BYTES_PER_PEER
352}
353
354const fn default_max_pending_inbound_bytes_per_peer() -> usize {
355 crate::utils::DEFAULT_MAX_PENDING_INBOUND_BYTES_PER_PEER
356}
357
358const fn default_max_pending_outbound_bytes_total() -> usize {
359 crate::utils::DEFAULT_MAX_PENDING_OUTBOUND_BYTES_TOTAL
360}
361
362const fn default_max_pending_inbound_bytes_total() -> usize {
363 crate::utils::DEFAULT_MAX_PENDING_INBOUND_BYTES_TOTAL
364}
365
366impl Default for Config {
367 fn default() -> Self {
368 Self {
369 safe_mode: false,
370 node_type: NodeType::default(),
371 listen_addresses: Vec::default(),
372 external_addresses: Vec::default(),
373 boot_nodes: Vec::default(),
374 routing: routing::Config::default(),
375 control_list: control_list::Config::default(),
376 memory_limits: MemoryLimitsConfig::default(),
377 max_app_message_bytes: default_max_app_message_bytes(),
378 max_pending_outbound_bytes_per_peer:
379 default_max_pending_outbound_bytes_per_peer(),
380 max_pending_inbound_bytes_per_peer:
381 default_max_pending_inbound_bytes_per_peer(),
382 max_pending_outbound_bytes_total:
383 default_max_pending_outbound_bytes_total(),
384 max_pending_inbound_bytes_total:
385 default_max_pending_inbound_bytes_total(),
386 }
387 }
388}
389
390#[derive(Debug, Clone, Deserialize, Default, PartialEq, Eq, Serialize)]
392pub enum NodeType {
393 #[default]
395 Bootstrap,
396 Addressable,
398 Ephemeral,
400}
401
402impl fmt::Display for NodeType {
403 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
404 match self {
405 Self::Bootstrap => write!(f, "Bootstrap"),
406 Self::Addressable => write!(f, "Addressable"),
407 Self::Ephemeral => write!(f, "Ephemeral"),
408 }
409 }
410}
411
412#[derive(Debug)]
414pub enum Command {
415 SendMessage {
417 peer: PeerId,
419 message: Bytes,
421 },
422}
423
424#[derive(Debug, Serialize, Deserialize, Clone)]
426pub enum Event {
427 StateChanged(utils::NetworkState),
429
430 Error(Error),
432}
433
434#[derive(Debug, Serialize, Deserialize)]
436pub enum CommandHelper<T>
437where
438 T: Debug + Serialize,
439{
440 SendMessage {
442 message: T,
444 },
445 ReceivedMessage {
447 sender: [u8; 32],
449 message: Bytes,
451 },
452}
453
454#[derive(
456 Debug, Serialize, Deserialize, Clone, BorshDeserialize, BorshSerialize,
457)]
458pub struct ComunicateInfo {
459 pub request_id: String,
461 pub version: u64,
463 pub receiver: PublicKey,
465 pub receiver_actor: String,
467}