1use std::ffi::OsString;
5
6use clap::Parser;
7use linera_base::{crypto::ValidatorPublicKey, identifiers::ChainId};
8use serde::{Deserialize, Serialize};
9
10#[cfg(with_simple_network)]
11use crate::simple;
12
13#[derive(Clone, Debug, Parser)]
14#[cfg_attr(with_testing, derive(PartialEq))]
15pub struct CrossChainConfig {
16 #[arg(long = "cross-chain-queue-size", default_value = "1000")]
18 pub(crate) queue_size: usize,
19
20 #[arg(long = "cross-chain-max-retries", default_value = "10")]
22 pub(crate) max_retries: u32,
23
24 #[arg(long = "cross-chain-retry-delay-ms", default_value = "2000")]
26 pub(crate) retry_delay_ms: u64,
27
28 #[arg(long = "cross-chain-sender-delay-ms", default_value = "0")]
30 pub(crate) sender_delay_ms: u64,
31
32 #[arg(long = "cross-chain-sender-failure-rate", default_value = "0.0")]
34 pub(crate) sender_failure_rate: f32,
35}
36
37impl Default for CrossChainConfig {
38 fn default() -> Self {
39 CrossChainConfig::parse_from::<[OsString; 1], OsString>(["".into()])
40 }
41}
42
43impl CrossChainConfig {
44 pub fn to_args(&self) -> Vec<String> {
45 vec![
46 "--cross-chain-queue-size".to_string(),
47 self.queue_size.to_string(),
48 "--cross-chain-max-retries".to_string(),
49 self.max_retries.to_string(),
50 "--cross-chain-retry-delay-ms".to_string(),
51 self.retry_delay_ms.to_string(),
52 "--cross-chain-sender-delay-ms".to_string(),
53 self.sender_delay_ms.to_string(),
54 "--cross-chain-sender-failure-rate".to_string(),
55 self.sender_failure_rate.to_string(),
56 ]
57 }
58}
59
60#[derive(Clone, Debug, Parser)]
61pub struct NotificationConfig {
62 #[arg(long = "notification-queue-size", default_value = "1000")]
64 pub(crate) notification_queue_size: usize,
65}
66
67pub type ShardId = usize;
68
69#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
71pub struct ShardConfig {
72 pub host: String,
74 pub port: u16,
76 pub metrics_port: Option<u16>,
78}
79
80impl ShardConfig {
81 pub fn address(&self) -> String {
82 format!("{}:{}", self.host, self.port)
83 }
84
85 pub fn http_address(&self) -> String {
86 format!("http://{}:{}", self.host, self.port)
87 }
88}
89
90#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
92pub struct ProxyConfig {
93 pub host: String,
95 pub public_port: u16,
97 pub private_port: u16,
99 pub metrics_port: u16,
101}
102
103impl ProxyConfig {
104 pub fn internal_address(&self, protocol: &NetworkProtocol) -> String {
105 format!(
106 "{}://{}:{}",
107 protocol.scheme(),
108 self.host,
109 self.private_port
110 )
111 }
112}
113
114#[derive(Clone, Copy, Debug, Serialize, Deserialize, PartialEq, Eq)]
116pub enum NetworkProtocol {
117 #[cfg(with_simple_network)]
118 Simple(simple::TransportProtocol),
119 Grpc(TlsConfig),
120}
121
122#[derive(Clone, Copy, Debug, Serialize, Deserialize, PartialEq, Eq)]
123pub enum TlsConfig {
124 ClearText,
125 Tls,
126}
127
128impl NetworkProtocol {
129 fn scheme(&self) -> &'static str {
130 match self {
131 #[cfg(with_simple_network)]
132 NetworkProtocol::Simple(transport) => transport.scheme(),
133 NetworkProtocol::Grpc(tls) => match tls {
134 TlsConfig::ClearText => "http",
135 TlsConfig::Tls => "https",
136 },
137 }
138 }
139}
140
141pub type ValidatorInternalNetworkConfig = ValidatorInternalNetworkPreConfig<NetworkProtocol>;
143
144pub type ValidatorPublicNetworkConfig = ValidatorPublicNetworkPreConfig<NetworkProtocol>;
146
147#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
149pub struct ValidatorInternalNetworkPreConfig<P> {
150 pub public_key: ValidatorPublicKey,
152 pub protocol: P,
154 pub shards: Vec<ShardConfig>,
157 pub block_exporters: Vec<ExporterServiceConfig>,
161 pub proxies: Vec<ProxyConfig>,
163}
164
165impl<P> ValidatorInternalNetworkPreConfig<P> {
166 pub fn clone_with_protocol<Q>(&self, protocol: Q) -> ValidatorInternalNetworkPreConfig<Q> {
167 ValidatorInternalNetworkPreConfig {
168 public_key: self.public_key,
169 protocol,
170 shards: self.shards.clone(),
171 block_exporters: self.block_exporters.clone(),
172 proxies: self.proxies.clone(),
173 }
174 }
175}
176
177impl ValidatorInternalNetworkConfig {
178 pub fn exporter_addresses(&self) -> Vec<String> {
179 self.block_exporters
180 .iter()
181 .map(|ExporterServiceConfig { host, port }| {
182 format!("{}://{}:{}", self.protocol.scheme(), host, port)
183 })
184 .collect::<Vec<_>>()
185 }
186}
187
188impl ValidatorPublicNetworkConfig {
189 pub fn http_address(&self) -> String {
190 format!("{}://{}:{}", self.protocol.scheme(), self.host, self.port)
191 }
192}
193
194#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
196pub struct ValidatorPublicNetworkPreConfig<P> {
197 pub protocol: P,
199 pub host: String,
201 pub port: u16,
203}
204
205impl<P> ValidatorPublicNetworkPreConfig<P> {
206 pub fn clone_with_protocol<Q>(&self, protocol: Q) -> ValidatorPublicNetworkPreConfig<Q> {
207 ValidatorPublicNetworkPreConfig {
208 protocol,
209 host: self.host.clone(),
210 port: self.port,
211 }
212 }
213}
214
215impl<P> std::fmt::Display for ValidatorPublicNetworkPreConfig<P>
216where
217 P: std::fmt::Display,
218{
219 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
220 write!(f, "{}:{}:{}", self.protocol, self.host, self.port)
221 }
222}
223
224impl std::fmt::Display for NetworkProtocol {
225 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
226 match self {
227 #[cfg(with_simple_network)]
228 NetworkProtocol::Simple(protocol) => write!(f, "{:?}", protocol),
229 NetworkProtocol::Grpc(tls) => match tls {
230 TlsConfig::ClearText => write!(f, "grpc"),
231 TlsConfig::Tls => write!(f, "grpcs"),
232 },
233 }
234 }
235}
236
237impl<P> std::str::FromStr for ValidatorPublicNetworkPreConfig<P>
238where
239 P: std::str::FromStr,
240 P::Err: std::fmt::Display,
241{
242 type Err = anyhow::Error;
243
244 fn from_str(s: &str) -> Result<Self, Self::Err> {
245 let parts = s.split(':').collect::<Vec<_>>();
246 anyhow::ensure!(
247 parts.len() == 3,
248 "Expecting format `(tcp|udp|grpc|grpcs):host:port`"
249 );
250 let protocol = parts[0].parse().map_err(|s| anyhow::anyhow!("{}", s))?;
251 let host = parts[1].to_owned();
252 let port = parts[2].parse()?;
253 Ok(ValidatorPublicNetworkPreConfig {
254 protocol,
255 host,
256 port,
257 })
258 }
259}
260
261impl std::str::FromStr for NetworkProtocol {
262 type Err = String;
263
264 fn from_str(s: &str) -> Result<Self, Self::Err> {
265 let protocol = match s {
266 "grpc" => Self::Grpc(TlsConfig::ClearText),
267 "grpcs" => Self::Grpc(TlsConfig::Tls),
268 #[cfg(with_simple_network)]
269 s => Self::Simple(simple::TransportProtocol::from_str(s)?),
270 #[cfg(not(with_simple_network))]
271 s => return Err(format!("unsupported protocol: {s:?}")),
272 };
273 Ok(protocol)
274 }
275}
276
277impl<P> ValidatorInternalNetworkPreConfig<P> {
278 pub fn get_shard_id(&self, chain_id: ChainId) -> ShardId {
280 use std::hash::{Hash, Hasher};
281 let mut s = std::collections::hash_map::DefaultHasher::new();
282 self.public_key.hash(&mut s);
284 chain_id.hash(&mut s);
285 (s.finish() as ShardId) % self.shards.len()
286 }
287
288 pub fn shard(&self, shard_id: ShardId) -> &ShardConfig {
289 &self.shards[shard_id]
290 }
291
292 pub fn get_shard_for(&self, chain_id: ChainId) -> &ShardConfig {
294 self.shard(self.get_shard_id(chain_id))
295 }
296}
297
298#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
299pub struct ExporterServiceConfig {
301 pub host: String,
303 pub port: u16,
305}
306
307#[test]
308fn cross_chain_config_to_args() {
309 let config = CrossChainConfig::default();
310 let args = config.to_args();
311 let mut cmd = vec![String::new()];
312 cmd.extend(args.clone());
313 let config2 = CrossChainConfig::parse_from(cmd);
314 let args2 = config2.to_args();
315 assert_eq!(config, config2);
316 assert_eq!(args, args2);
317}