iota_config/
lib.rs

1// Copyright (c) Mysten Labs, Inc.
2// Modifications Copyright (c) 2024 IOTA Stiftung
3// SPDX-License-Identifier: Apache-2.0
4
5use std::{
6    fs,
7    io::BufWriter,
8    path::{Path, PathBuf},
9};
10
11use anyhow::{Context, Result};
12use serde::{Serialize, de::DeserializeOwned};
13use tracing::trace;
14
15pub mod certificate_deny_config;
16pub mod genesis;
17pub mod local_ip_utils;
18pub mod migration_tx_data;
19pub mod node;
20pub mod node_config_metrics;
21pub mod object_storage_config;
22pub mod p2p;
23pub mod transaction_deny_config;
24pub mod verifier_signing_config;
25
26use iota_types::multiaddr::Multiaddr;
27pub use node::{ConsensusConfig, ExecutionCacheConfig, NodeConfig};
28
29const IOTA_DIR: &str = ".iota";
30pub const IOTA_CONFIG_DIR: &str = "iota_config";
31pub const IOTA_NETWORK_CONFIG: &str = "network.yaml";
32pub const IOTA_FULLNODE_CONFIG: &str = "fullnode.yaml";
33pub const IOTA_CLIENT_CONFIG: &str = "client.yaml";
34pub const IOTA_KEYSTORE_FILENAME: &str = "iota.keystore";
35pub const IOTA_KEYSTORE_ALIASES_FILENAME: &str = "iota.aliases";
36pub const IOTA_BENCHMARK_GENESIS_GAS_KEYSTORE_FILENAME: &str = "benchmark.keystore";
37pub const IOTA_GENESIS_FILENAME: &str = "genesis.blob";
38pub const IOTA_GENESIS_MIGRATION_TX_DATA_FILENAME: &str = "migration.blob";
39pub const IOTA_DEV_NET_URL: &str = "https://api.devnet.iota.cafe:443";
40
41pub const AUTHORITIES_DB_NAME: &str = "authorities_db";
42pub const CONSENSUS_DB_NAME: &str = "consensus_db";
43pub const FULL_NODE_DB_PATH: &str = "full_node_db";
44
45pub fn iota_config_dir() -> Result<PathBuf, anyhow::Error> {
46    match std::env::var_os("IOTA_CONFIG_DIR") {
47        Some(config_env) => Ok(config_env.into()),
48        None => match dirs::home_dir() {
49            Some(v) => Ok(v.join(IOTA_DIR).join(IOTA_CONFIG_DIR)),
50            None => anyhow::bail!("cannot obtain home directory path"),
51        },
52    }
53    .and_then(|dir| {
54        if !dir.exists() {
55            fs::create_dir_all(dir.clone())?;
56        }
57        Ok(dir)
58    })
59}
60
61/// Check if the genesis blob exists in the given directory or the default
62/// directory.
63pub fn genesis_blob_exists(config_dir: Option<PathBuf>) -> bool {
64    if let Some(dir) = config_dir {
65        dir.join(IOTA_GENESIS_FILENAME).exists()
66    } else if let Some(config_env) = std::env::var_os("IOTA_CONFIG_DIR") {
67        Path::new(&config_env).join(IOTA_GENESIS_FILENAME).exists()
68    } else if let Some(home) = dirs::home_dir() {
69        let mut config = PathBuf::new();
70        config.push(&home);
71        config.extend([IOTA_DIR, IOTA_CONFIG_DIR, IOTA_GENESIS_FILENAME]);
72        config.exists()
73    } else {
74        false
75    }
76}
77
78pub fn validator_config_file(address: Multiaddr, i: usize) -> String {
79    multiaddr_to_filename(address).unwrap_or(format!("validator-config-{}.yaml", i))
80}
81
82pub fn ssfn_config_file(address: Multiaddr, i: usize) -> String {
83    multiaddr_to_filename(address).unwrap_or(format!("ssfn-config-{}.yaml", i))
84}
85
86fn multiaddr_to_filename(address: Multiaddr) -> Option<String> {
87    if let Some(hostname) = address.hostname() {
88        if let Some(port) = address.port() {
89            return Some(format!("{}-{}.yaml", hostname, port));
90        }
91    }
92    None
93}
94
95pub trait Config
96where
97    Self: DeserializeOwned + Serialize,
98{
99    fn persisted(self, path: &Path) -> PersistedConfig<Self> {
100        PersistedConfig {
101            inner: self,
102            path: path.to_path_buf(),
103        }
104    }
105
106    fn load<P: AsRef<Path>>(path: P) -> Result<Self, anyhow::Error> {
107        let path = path.as_ref();
108        trace!("Reading config from {}", path.display());
109        let reader = fs::File::open(path)
110            .with_context(|| format!("unable to load config from {}", path.display()))?;
111        Ok(serde_yaml::from_reader(reader)?)
112    }
113
114    fn save<P: AsRef<Path>>(&self, path: P) -> Result<(), anyhow::Error> {
115        let path = path.as_ref();
116        trace!("Writing config to {}", path.display());
117        let mut write = BufWriter::new(fs::File::create(path)?);
118        serde_yaml::to_writer(&mut write, &self)
119            .with_context(|| format!("unable to save config to {}", path.display()))?;
120        Ok(())
121    }
122}
123
124pub struct PersistedConfig<C> {
125    inner: C,
126    path: PathBuf,
127}
128
129impl<C> PersistedConfig<C>
130where
131    C: Config,
132{
133    pub fn read(path: &Path) -> Result<C, anyhow::Error> {
134        Config::load(path)
135    }
136
137    pub fn save(&self) -> Result<(), anyhow::Error> {
138        self.inner.save(&self.path)
139    }
140
141    pub fn into_inner(self) -> C {
142        self.inner
143    }
144
145    pub fn path(&self) -> &Path {
146        &self.path
147    }
148}
149
150impl<C> std::ops::Deref for PersistedConfig<C> {
151    type Target = C;
152
153    fn deref(&self) -> &Self::Target {
154        &self.inner
155    }
156}
157
158impl<C> std::ops::DerefMut for PersistedConfig<C> {
159    fn deref_mut(&mut self) -> &mut Self::Target {
160        &mut self.inner
161    }
162}