1use serde::{Deserialize, Serialize};
4use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4};
5use std::path::PathBuf;
6
7pub const NODE_IDENTITY_FILENAME: &str = "node_identity.key";
9
10pub const NODES_SUBDIR: &str = "nodes";
12
13#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)]
15#[serde(rename_all = "lowercase")]
16pub enum IpVersion {
17 Ipv4,
19 Ipv6,
21 #[default]
23 Dual,
24}
25
26#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)]
28#[serde(rename_all = "lowercase")]
29pub enum UpgradeChannel {
30 #[default]
32 Stable,
33 Beta,
35}
36
37#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)]
39#[serde(rename_all = "lowercase")]
40pub enum NetworkMode {
41 #[default]
43 Production,
44 Testnet,
47 Development,
50}
51
52#[derive(Debug, Clone, Serialize, Deserialize)]
54pub struct TestnetConfig {
55 #[serde(default = "default_testnet_max_per_asn")]
58 pub max_nodes_per_asn: usize,
59
60 #[serde(default = "default_testnet_max_per_64")]
63 pub max_nodes_per_64: usize,
64
65 #[serde(default)]
68 pub enforce_age_requirements: bool,
69
70 #[serde(default)]
73 pub enable_geo_checks: bool,
74}
75
76impl Default for TestnetConfig {
77 fn default() -> Self {
78 Self {
79 max_nodes_per_asn: default_testnet_max_per_asn(),
80 max_nodes_per_64: default_testnet_max_per_64(),
81 enforce_age_requirements: false,
82 enable_geo_checks: false,
83 }
84 }
85}
86
87const fn default_testnet_max_per_asn() -> usize {
88 5000
89}
90
91const fn default_testnet_max_per_64() -> usize {
92 100
93}
94
95#[derive(Debug, Clone, Serialize, Deserialize)]
97pub struct NodeConfig {
98 #[serde(default = "default_root_dir")]
100 pub root_dir: PathBuf,
101
102 #[serde(default)]
104 pub port: u16,
105
106 #[serde(default)]
108 pub ip_version: IpVersion,
109
110 #[serde(default)]
112 pub bootstrap: Vec<SocketAddr>,
113
114 #[serde(default)]
116 pub network_mode: NetworkMode,
117
118 #[serde(default)]
121 pub testnet: TestnetConfig,
122
123 #[serde(default)]
125 pub upgrade: UpgradeConfig,
126
127 #[serde(default)]
129 pub payment: PaymentConfig,
130
131 #[serde(default)]
133 pub bootstrap_cache: BootstrapCacheConfig,
134
135 #[serde(default)]
137 pub storage: StorageConfig,
138
139 #[serde(default = "default_max_message_size")]
146 pub max_message_size: usize,
147
148 #[serde(default = "default_log_level")]
150 pub log_level: String,
151}
152
153#[derive(Debug, Clone, Serialize, Deserialize)]
155pub struct UpgradeConfig {
156 #[serde(default)]
158 pub channel: UpgradeChannel,
159
160 #[serde(default = "default_check_interval")]
162 pub check_interval_hours: u64,
163
164 #[serde(default = "default_github_repo")]
166 pub github_repo: String,
167
168 #[serde(default = "default_staged_rollout_hours")]
176 pub staged_rollout_hours: u64,
177
178 #[serde(default)]
185 pub stop_on_upgrade: bool,
186}
187
188#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)]
190#[serde(rename_all = "kebab-case")]
191pub enum EvmNetworkConfig {
192 #[default]
194 ArbitrumOne,
195 ArbitrumSepolia,
197}
198
199#[derive(Debug, Clone, Serialize, Deserialize)]
205pub struct PaymentConfig {
206 #[serde(default = "default_cache_capacity")]
208 pub cache_capacity: usize,
209
210 #[serde(default)]
213 pub rewards_address: Option<String>,
214
215 #[serde(default)]
217 pub evm_network: EvmNetworkConfig,
218
219 #[serde(default = "default_metrics_port")]
222 pub metrics_port: u16,
223}
224
225impl Default for PaymentConfig {
226 fn default() -> Self {
227 Self {
228 cache_capacity: default_cache_capacity(),
229 rewards_address: None,
230 evm_network: EvmNetworkConfig::default(),
231 metrics_port: default_metrics_port(),
232 }
233 }
234}
235
236const fn default_metrics_port() -> u16 {
237 9100
238}
239
240const fn default_cache_capacity() -> usize {
241 100_000
242}
243
244impl Default for NodeConfig {
245 fn default() -> Self {
246 Self {
247 root_dir: default_root_dir(),
248 port: 0,
249 ip_version: IpVersion::default(),
250 bootstrap: Vec::new(),
251 network_mode: NetworkMode::default(),
252 testnet: TestnetConfig::default(),
253 upgrade: UpgradeConfig::default(),
254 payment: PaymentConfig::default(),
255 bootstrap_cache: BootstrapCacheConfig::default(),
256 storage: StorageConfig::default(),
257 max_message_size: default_max_message_size(),
258 log_level: default_log_level(),
259 }
260 }
261}
262
263impl NodeConfig {
264 #[must_use]
270 pub fn testnet() -> Self {
271 Self {
272 network_mode: NetworkMode::Testnet,
273 testnet: TestnetConfig::default(),
274 bootstrap: default_testnet_bootstrap(),
275 ..Self::default()
276 }
277 }
278
279 #[must_use]
283 pub fn development() -> Self {
284 Self {
285 network_mode: NetworkMode::Development,
286 testnet: TestnetConfig {
287 max_nodes_per_asn: usize::MAX,
288 max_nodes_per_64: usize::MAX,
289 enforce_age_requirements: false,
290 enable_geo_checks: false,
291 },
292 ..Self::default()
293 }
294 }
295
296 #[must_use]
298 pub fn is_relaxed(&self) -> bool {
299 !matches!(self.network_mode, NetworkMode::Production)
300 }
301
302 pub fn from_file(path: &std::path::Path) -> crate::Result<Self> {
308 let content = std::fs::read_to_string(path)?;
309 toml::from_str(&content).map_err(|e| crate::Error::Config(e.to_string()))
310 }
311
312 pub fn to_file(&self, path: &std::path::Path) -> crate::Result<()> {
318 let content =
319 toml::to_string_pretty(self).map_err(|e| crate::Error::Config(e.to_string()))?;
320 std::fs::write(path, content)?;
321 Ok(())
322 }
323}
324
325impl Default for UpgradeConfig {
326 fn default() -> Self {
327 Self {
328 channel: UpgradeChannel::default(),
329 check_interval_hours: default_check_interval(),
330 github_repo: default_github_repo(),
331 staged_rollout_hours: default_staged_rollout_hours(),
332 stop_on_upgrade: false,
333 }
334 }
335}
336
337fn default_github_repo() -> String {
338 "WithAutonomi/ant-node".to_string()
339}
340
341#[must_use]
343pub fn default_root_dir() -> PathBuf {
344 directories::ProjectDirs::from("", "", "ant").map_or_else(
345 || PathBuf::from(".ant"),
346 |dirs| dirs.data_dir().to_path_buf(),
347 )
348}
349
350#[must_use]
355pub fn default_nodes_dir() -> PathBuf {
356 default_root_dir().join(NODES_SUBDIR)
357}
358
359fn default_max_message_size() -> usize {
360 crate::ant_protocol::MAX_WIRE_MESSAGE_SIZE
361}
362
363fn default_log_level() -> String {
364 "info".to_string()
365}
366
367const fn default_check_interval() -> u64 {
368 1 }
370
371const fn default_staged_rollout_hours() -> u64 {
372 1 }
374
375#[derive(Debug, Clone, Serialize, Deserialize)]
386pub struct BootstrapCacheConfig {
387 #[serde(default = "default_bootstrap_cache_enabled")]
390 pub enabled: bool,
391
392 #[serde(default)]
395 pub cache_dir: Option<PathBuf>,
396
397 #[serde(default = "default_bootstrap_max_contacts")]
400 pub max_contacts: usize,
401
402 #[serde(default = "default_bootstrap_stale_days")]
406 pub stale_threshold_days: u64,
407}
408
409impl Default for BootstrapCacheConfig {
410 fn default() -> Self {
411 Self {
412 enabled: default_bootstrap_cache_enabled(),
413 cache_dir: None,
414 max_contacts: default_bootstrap_max_contacts(),
415 stale_threshold_days: default_bootstrap_stale_days(),
416 }
417 }
418}
419
420const fn default_bootstrap_cache_enabled() -> bool {
421 true
422}
423
424const fn default_bootstrap_max_contacts() -> usize {
425 10_000
426}
427
428const fn default_bootstrap_stale_days() -> u64 {
429 7
430}
431
432#[derive(Debug, Clone, Serialize, Deserialize)]
443pub struct StorageConfig {
444 #[serde(default = "default_storage_enabled")]
447 pub enabled: bool,
448
449 #[serde(default)]
452 pub max_chunks: usize,
453
454 #[serde(default = "default_storage_verify_on_read")]
457 pub verify_on_read: bool,
458
459 #[serde(default)]
463 pub db_size_gb: usize,
464}
465
466impl Default for StorageConfig {
467 fn default() -> Self {
468 Self {
469 enabled: default_storage_enabled(),
470 max_chunks: 0,
471 verify_on_read: default_storage_verify_on_read(),
472 db_size_gb: 0,
473 }
474 }
475}
476
477const fn default_storage_enabled() -> bool {
478 true
479}
480
481const fn default_storage_verify_on_read() -> bool {
482 true
483}
484
485fn default_testnet_bootstrap() -> Vec<SocketAddr> {
491 vec![
492 SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(165, 22, 4, 178), 12000)),
494 SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(164, 92, 111, 156), 12000)),
496 ]
497}
498
499#[cfg(test)]
500mod tests {
501 use super::*;
502
503 #[test]
504 fn test_default_config_has_cache_capacity() {
505 let config = PaymentConfig::default();
506 assert!(config.cache_capacity > 0, "Cache capacity must be positive");
507 }
508
509 #[test]
510 fn test_default_evm_network() {
511 use crate::payment::EvmVerifierConfig;
512 let _config = EvmVerifierConfig::default();
513 }
515}