use linera_base::identifiers::ChainId;
use serde::{Deserialize, Serialize};
#[cfg(with_simple_network)]
use crate::simple;
#[derive(Clone, Debug, clap::Parser)]
pub struct CrossChainConfig {
#[arg(long = "cross-chain-queue-size", default_value = "1000")]
pub(crate) queue_size: usize,
#[arg(long = "cross-chain-max-retries", default_value = "10")]
pub(crate) max_retries: u32,
#[arg(long = "cross-chain-retry-delay-ms", default_value = "2000")]
pub(crate) retry_delay_ms: u64,
#[arg(long = "cross-chain-sender-delay-ms", default_value = "0")]
pub(crate) sender_delay_ms: u64,
#[arg(long = "cross-chain-sender-failure-rate", default_value = "0.0")]
pub(crate) sender_failure_rate: f32,
#[arg(long = "cross-chain-max-tasks", default_value = "10")]
pub(crate) max_concurrent_tasks: usize,
}
#[derive(Clone, Debug, clap::Parser)]
pub struct NotificationConfig {
#[arg(long = "notification-queue-size", default_value = "1000")]
pub(crate) notification_queue_size: usize,
}
pub type ShardId = usize;
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct ShardConfig {
pub host: String,
pub port: u16,
pub metrics_host: String,
pub metrics_port: Option<u16>,
}
impl ShardConfig {
pub fn address(&self) -> String {
format!("{}:{}", self.host, self.port)
}
pub fn http_address(&self) -> String {
format!("http://{}:{}", self.host, self.port)
}
}
#[derive(Clone, Copy, Debug, Serialize, Deserialize, PartialEq, Eq)]
pub enum NetworkProtocol {
#[cfg(with_simple_network)]
Simple(simple::TransportProtocol),
Grpc(TlsConfig),
}
#[derive(Clone, Copy, Debug, Serialize, Deserialize, PartialEq, Eq)]
pub enum TlsConfig {
ClearText,
Tls,
}
impl NetworkProtocol {
fn scheme(&self) -> &'static str {
match self {
#[cfg(with_simple_network)]
NetworkProtocol::Simple(transport) => transport.scheme(),
NetworkProtocol::Grpc(tls) => match tls {
TlsConfig::ClearText => "http",
TlsConfig::Tls => "https",
},
}
}
}
pub type ValidatorInternalNetworkConfig = ValidatorInternalNetworkPreConfig<NetworkProtocol>;
pub type ValidatorPublicNetworkConfig = ValidatorPublicNetworkPreConfig<NetworkProtocol>;
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct ValidatorInternalNetworkPreConfig<P> {
pub protocol: P,
pub shards: Vec<ShardConfig>,
pub host: String,
pub port: u16,
pub metrics_host: String,
pub metrics_port: u16,
}
impl<P> ValidatorInternalNetworkPreConfig<P> {
pub fn clone_with_protocol<Q>(&self, protocol: Q) -> ValidatorInternalNetworkPreConfig<Q> {
ValidatorInternalNetworkPreConfig {
protocol,
shards: self.shards.clone(),
host: self.host.clone(),
port: self.port,
metrics_host: self.metrics_host.clone(),
metrics_port: self.metrics_port,
}
}
}
impl ValidatorInternalNetworkConfig {
pub fn proxy_address(&self) -> String {
format!("{}://{}:{}", self.protocol.scheme(), self.host, self.port)
}
}
impl ValidatorPublicNetworkConfig {
pub fn http_address(&self) -> String {
format!("{}://{}:{}", self.protocol.scheme(), self.host, self.port)
}
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct ValidatorPublicNetworkPreConfig<P> {
pub protocol: P,
pub host: String,
pub port: u16,
}
impl<P> ValidatorPublicNetworkPreConfig<P> {
pub fn clone_with_protocol<Q>(&self, protocol: Q) -> ValidatorPublicNetworkPreConfig<Q> {
ValidatorPublicNetworkPreConfig {
protocol,
host: self.host.clone(),
port: self.port,
}
}
}
impl<P> std::fmt::Display for ValidatorPublicNetworkPreConfig<P>
where
P: std::fmt::Display,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}:{}:{}", self.protocol, self.host, self.port)
}
}
impl std::fmt::Display for NetworkProtocol {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
#[cfg(with_simple_network)]
NetworkProtocol::Simple(protocol) => write!(f, "{:?}", protocol),
NetworkProtocol::Grpc(tls) => match tls {
TlsConfig::ClearText => write!(f, "grpc"),
TlsConfig::Tls => write!(f, "grpcs"),
},
}
}
}
impl<P> std::str::FromStr for ValidatorPublicNetworkPreConfig<P>
where
P: std::str::FromStr,
P::Err: std::fmt::Display,
{
type Err = anyhow::Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let parts = s.split(':').collect::<Vec<_>>();
anyhow::ensure!(
parts.len() == 3,
"Expecting format `(tcp|udp|grpc|grpcs):host:port`"
);
let protocol = parts[0].parse().map_err(|s| anyhow::anyhow!("{}", s))?;
let host = parts[1].to_owned();
let port = parts[2].parse()?;
Ok(ValidatorPublicNetworkPreConfig {
protocol,
host,
port,
})
}
}
impl std::str::FromStr for NetworkProtocol {
type Err = String;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let protocol = match s {
"grpc" => Self::Grpc(TlsConfig::ClearText),
"grpcs" => Self::Grpc(TlsConfig::Tls),
#[cfg(with_simple_network)]
s => Self::Simple(simple::TransportProtocol::from_str(s)?),
#[cfg(not(with_simple_network))]
s => return Err(format!("unsupported protocol: {s:?}")),
};
Ok(protocol)
}
}
impl<P> ValidatorInternalNetworkPreConfig<P> {
pub fn get_shard_id(&self, chain_id: ChainId) -> ShardId {
use std::hash::{Hash, Hasher};
let mut s = std::collections::hash_map::DefaultHasher::new();
chain_id.hash(&mut s);
(s.finish() as ShardId) % self.shards.len()
}
pub fn shard(&self, shard_id: ShardId) -> &ShardConfig {
&self.shards[shard_id]
}
pub fn get_shard_for(&self, chain_id: ChainId) -> &ShardConfig {
self.shard(self.get_shard_id(chain_id))
}
}