#![warn(missing_docs)]
mod behaviour;
mod control_list;
pub mod error;
pub mod metrics;
mod monitor;
mod routing;
mod service;
mod transport;
mod utils;
mod worker;
use std::fmt::{self, Debug, Display};
use ave_common::identity::PublicKey;
use borsh::{BorshDeserialize, BorshSerialize};
pub use control_list::Config as ControlListConfig;
pub use error::Error;
pub use libp2p::{
PeerId,
identity::{
PublicKey as PublicKeyLibP2P, ed25519::PublicKey as PublicKeyEd25519,
},
};
pub use monitor::*;
pub use routing::{Config as RoutingConfig, RoutingNode};
pub use service::NetworkService;
pub use utils::NetworkState;
pub use worker::{NetworkWorker, NetworkWorkerRuntime};
use bytes::Bytes;
use serde::{Deserialize, Serialize};
pub use crate::utils::ReqResConfig;
#[cfg(all(feature = "test", not(test), not(debug_assertions)))]
compile_error!(
"The 'test' feature should only be used during development/testing"
);
#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(rename_all = "snake_case")]
pub enum MachineSpec {
Profile(MachineProfile),
Custom {
ram_mb: u64,
cpu_cores: usize,
},
}
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub enum MachineProfile {
Nano,
Micro,
Small,
Medium,
Large,
XLarge,
#[serde(rename = "2xlarge")]
XXLarge,
}
impl MachineProfile {
pub const fn ram_mb(self) -> u64 {
match self {
Self::Nano => 512,
Self::Micro => 1_024,
Self::Small => 2_048,
Self::Medium => 4_096,
Self::Large => 8_192,
Self::XLarge => 16_384,
Self::XXLarge => 32_768,
}
}
pub const fn cpu_cores(self) -> usize {
match self {
Self::Nano => 2,
Self::Micro => 2,
Self::Small => 2,
Self::Medium => 2,
Self::Large => 2,
Self::XLarge => 4,
Self::XXLarge => 8,
}
}
}
impl Display for MachineProfile {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Nano => write!(f, "nano"),
Self::Micro => write!(f, "micro"),
Self::Small => write!(f, "small"),
Self::Medium => write!(f, "medium"),
Self::Large => write!(f, "large"),
Self::XLarge => write!(f, "xlarge"),
Self::XXLarge => write!(f, "2xlarge"),
}
}
}
pub struct ResolvedSpec {
pub ram_mb: u64,
pub cpu_cores: usize,
}
pub fn resolve_spec(spec: Option<MachineSpec>) -> ResolvedSpec {
match spec {
Some(MachineSpec::Profile(p)) => ResolvedSpec {
ram_mb: p.ram_mb(),
cpu_cores: p.cpu_cores(),
},
Some(MachineSpec::Custom { ram_mb, cpu_cores }) => {
ResolvedSpec { ram_mb, cpu_cores }
}
None => ResolvedSpec {
ram_mb: detect_ram_mb(),
cpu_cores: detect_cpu_cores(),
},
}
}
pub(crate) fn detect_ram_mb() -> u64 {
#[cfg(target_os = "linux")]
{
if let Ok(meminfo) = std::fs::read_to_string("/proc/meminfo") {
for line in meminfo.lines() {
if let Some(rest) = line.strip_prefix("MemTotal:")
&& let Some(kb_str) = rest.split_whitespace().next()
&& let Ok(kb) = kb_str.parse::<u64>()
{
return kb / 1024;
}
}
}
}
4_096
}
pub(crate) fn detect_cpu_cores() -> usize {
std::thread::available_parallelism()
.map(|n| n.get())
.unwrap_or(2)
}
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Default)]
#[serde(tag = "type", rename_all = "snake_case")]
pub enum MemoryLimitsConfig {
#[default]
Disabled,
Percentage {
value: f64,
},
Mb {
value: usize,
},
}
impl MemoryLimitsConfig {
pub fn validate(&self) -> Result<(), String> {
if let Self::Percentage { value } = self
&& (*value <= 0.0 || *value > 1.0)
{
return Err(format!(
"network.memory_limits percentage must be in range (0.0, 1.0], got {}",
value
));
}
Ok(())
}
}
impl Display for MemoryLimitsConfig {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Disabled => write!(f, "disabled"),
Self::Percentage { value } => {
write!(f, "{:.0}% of system RAM", value * 100.0)
}
Self::Mb { value } => write!(f, "{} MB", value),
}
}
}
#[derive(Debug, Clone, Deserialize, Serialize)]
#[serde(default)]
#[serde(rename_all = "snake_case")]
pub struct Config {
pub node_type: NodeType,
pub listen_addresses: Vec<String>,
pub external_addresses: Vec<String>,
pub boot_nodes: Vec<RoutingNode>,
pub routing: routing::Config,
pub control_list: control_list::Config,
pub memory_limits: MemoryLimitsConfig,
#[serde(default = "default_max_app_message_bytes")]
pub max_app_message_bytes: usize,
#[serde(default = "default_max_pending_outbound_bytes_per_peer")]
pub max_pending_outbound_bytes_per_peer: usize,
#[serde(default = "default_max_pending_inbound_bytes_per_peer")]
pub max_pending_inbound_bytes_per_peer: usize,
#[serde(default = "default_max_pending_outbound_bytes_total")]
pub max_pending_outbound_bytes_total: usize,
#[serde(default = "default_max_pending_inbound_bytes_total")]
pub max_pending_inbound_bytes_total: usize,
}
impl Config {
pub fn new(
node_type: NodeType,
listen_addresses: Vec<String>,
external_addresses: Vec<String>,
boot_nodes: Vec<RoutingNode>,
) -> Self {
Self {
boot_nodes,
node_type,
listen_addresses,
external_addresses,
routing: routing::Config::default(),
control_list: control_list::Config::default(),
memory_limits: MemoryLimitsConfig::default(),
max_app_message_bytes: default_max_app_message_bytes(),
max_pending_outbound_bytes_per_peer:
default_max_pending_outbound_bytes_per_peer(),
max_pending_inbound_bytes_per_peer:
default_max_pending_inbound_bytes_per_peer(),
max_pending_outbound_bytes_total:
default_max_pending_outbound_bytes_total(),
max_pending_inbound_bytes_total:
default_max_pending_inbound_bytes_total(),
}
}
}
const fn default_max_app_message_bytes() -> usize {
crate::utils::MAX_APP_MESSAGE_BYTES
}
const fn default_max_pending_outbound_bytes_per_peer() -> usize {
crate::utils::DEFAULT_MAX_PENDING_OUTBOUND_BYTES_PER_PEER
}
const fn default_max_pending_inbound_bytes_per_peer() -> usize {
crate::utils::DEFAULT_MAX_PENDING_INBOUND_BYTES_PER_PEER
}
const fn default_max_pending_outbound_bytes_total() -> usize {
crate::utils::DEFAULT_MAX_PENDING_OUTBOUND_BYTES_TOTAL
}
const fn default_max_pending_inbound_bytes_total() -> usize {
crate::utils::DEFAULT_MAX_PENDING_INBOUND_BYTES_TOTAL
}
impl Default for Config {
fn default() -> Self {
Self {
node_type: NodeType::default(),
listen_addresses: Vec::default(),
external_addresses: Vec::default(),
boot_nodes: Vec::default(),
routing: routing::Config::default(),
control_list: control_list::Config::default(),
memory_limits: MemoryLimitsConfig::default(),
max_app_message_bytes: default_max_app_message_bytes(),
max_pending_outbound_bytes_per_peer:
default_max_pending_outbound_bytes_per_peer(),
max_pending_inbound_bytes_per_peer:
default_max_pending_inbound_bytes_per_peer(),
max_pending_outbound_bytes_total:
default_max_pending_outbound_bytes_total(),
max_pending_inbound_bytes_total:
default_max_pending_inbound_bytes_total(),
}
}
}
#[derive(Debug, Clone, Deserialize, Default, PartialEq, Eq, Serialize)]
pub enum NodeType {
#[default]
Bootstrap,
Addressable,
Ephemeral,
}
impl fmt::Display for NodeType {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Bootstrap => write!(f, "Bootstrap"),
Self::Addressable => write!(f, "Addressable"),
Self::Ephemeral => write!(f, "Ephemeral"),
}
}
}
#[derive(Debug)]
pub enum Command {
SendMessage {
peer: PeerId,
message: Bytes,
},
}
#[derive(Debug, Serialize, Deserialize, Clone)]
pub enum Event {
StateChanged(utils::NetworkState),
Error(Error),
}
#[derive(Debug, Serialize, Deserialize)]
pub enum CommandHelper<T>
where
T: Debug + Serialize,
{
SendMessage {
message: T,
},
ReceivedMessage {
sender: [u8; 32],
message: Bytes,
},
}
#[derive(
Debug, Serialize, Deserialize, Clone, BorshDeserialize, BorshSerialize,
)]
pub struct ComunicateInfo {
pub request_id: String,
pub version: u64,
pub receiver: PublicKey,
pub receiver_actor: String,
}