sui_config/
lib.rs

1// Copyright (c) Mysten Labs, Inc.
2// SPDX-License-Identifier: Apache-2.0
3
4use anyhow::Context;
5use anyhow::Result;
6use serde::Serialize;
7use serde::de::DeserializeOwned;
8use std::fs;
9use std::path::{Path, PathBuf};
10use tracing::trace;
11
12pub mod certificate_deny_config;
13pub mod dynamic_transaction_signing_checks;
14pub mod genesis;
15pub mod local_ip_utils;
16pub mod node;
17pub mod node_config_metrics;
18pub mod object_storage_config;
19pub mod p2p;
20pub mod rpc_config;
21pub mod transaction_deny_config;
22pub mod validator_client_monitor_config;
23pub mod verifier_signing_config;
24
25pub use node::{ConsensusConfig, ExecutionCacheConfig, NodeConfig};
26pub use rpc_config::{RpcConfig, RpcIndexInitConfig, RpcTlsConfig};
27use sui_types::multiaddr::Multiaddr;
28use tracing::debug;
29
30const SUI_DIR: &str = ".sui";
31pub const SUI_CONFIG_DIR: &str = "sui_config";
32pub const SUI_NETWORK_CONFIG: &str = "network.yaml";
33pub const SUI_FULLNODE_CONFIG: &str = "fullnode.yaml";
34pub const SUI_CLIENT_CONFIG: &str = "client.yaml";
35pub const SUI_KEYSTORE_FILENAME: &str = "sui.keystore";
36pub const SUI_KEYSTORE_ALIASES_FILENAME: &str = "sui.aliases";
37pub const SUI_BENCHMARK_GENESIS_GAS_KEYSTORE_FILENAME: &str = "benchmark.keystore";
38pub const SUI_GENESIS_FILENAME: &str = "genesis.blob";
39pub const SUI_DEV_NET_URL: &str = "https://fullnode.devnet.sui.io: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 sui_config_dir() -> Result<PathBuf, anyhow::Error> {
46    match std::env::var_os("SUI_CONFIG_DIR") {
47        Some(config_env) => Ok(config_env.into()),
48        None => match dirs::home_dir() {
49            Some(v) => Ok(v.join(SUI_DIR).join(SUI_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 directory.
62pub fn genesis_blob_exists(config_dir: Option<PathBuf>) -> bool {
63    if let Some(dir) = config_dir {
64        dir.join(SUI_GENESIS_FILENAME).exists()
65    } else if let Some(config_env) = std::env::var_os("SUI_CONFIG_DIR") {
66        Path::new(&config_env).join(SUI_GENESIS_FILENAME).exists()
67    } else if let Some(home) = dirs::home_dir() {
68        let mut config = PathBuf::new();
69        config.push(&home);
70        config.extend([SUI_DIR, SUI_CONFIG_DIR, SUI_GENESIS_FILENAME]);
71        config.exists()
72    } else {
73        false
74    }
75}
76
77pub fn validator_config_file(address: Multiaddr, i: usize) -> String {
78    multiaddr_to_filename(address).unwrap_or(format!("validator-config-{}.yaml", i))
79}
80
81pub fn ssfn_config_file(address: Multiaddr, i: usize) -> String {
82    multiaddr_to_filename(address).unwrap_or(format!("ssfn-config-{}.yaml", i))
83}
84
85fn multiaddr_to_filename(address: Multiaddr) -> Option<String> {
86    if let Some(hostname) = address.hostname()
87        && let Some(port) = address.port()
88    {
89        return Some(format!("{}-{}.yaml", hostname, port));
90    }
91    None
92}
93
94pub trait Config
95where
96    Self: DeserializeOwned + Serialize,
97{
98    fn persisted(self, path: &Path) -> PersistedConfig<Self> {
99        PersistedConfig {
100            inner: self,
101            path: path.to_path_buf(),
102        }
103    }
104
105    fn load<P: AsRef<Path>>(path: P) -> Result<Self, anyhow::Error> {
106        let path = path.as_ref();
107        trace!("Reading config from {}", path.display());
108        let reader = fs::File::open(path)
109            .with_context(|| format!("Unable to load config from {}", path.display()))?;
110        Ok(serde_yaml::from_reader(reader)?)
111    }
112
113    fn save<P: AsRef<Path>>(&self, path: P) -> Result<(), anyhow::Error> {
114        let path = path.as_ref();
115        trace!("Writing config to {}", path.display());
116        let config = serde_yaml::to_string(&self)?;
117        fs::write(path, config)
118            .with_context(|| format!("Unable to save config to {}", path.display()))?;
119        Ok(())
120    }
121
122    /// Load the config from the given path, acquiring a shared lock on the file during the read.
123    fn load_with_lock<P: AsRef<Path>>(path: P) -> Result<Self, anyhow::Error> {
124        let path = path.as_ref();
125        debug!("Reading config with lock from {}", path.display());
126        let file = fs::File::open(path)
127            .with_context(|| format!("Unable to load config from {}", path.display()))?;
128        file.lock_shared()?;
129        let config: Self = serde_yaml::from_reader(&file)?;
130        file.unlock()?;
131        Ok(config)
132    }
133
134    /// Save the config to the given path, acquiring an exclusive lock on the file during the
135    /// write.
136    fn save_with_lock<P: AsRef<Path>>(&self, path: P) -> Result<(), anyhow::Error> {
137        let path = path.as_ref();
138        debug!("Writing config with lock to {}", path.display());
139        let config_str = serde_yaml::to_string(&self)?;
140
141        let file = fs::OpenOptions::new()
142            .write(true)
143            .create(true)
144            .truncate(true)
145            .open(path)
146            .with_context(|| {
147                format!(
148                    "Unable to open config file for writing at {}",
149                    path.display()
150                )
151            })?;
152
153        file.lock()
154            .with_context(|| format!("Unable to acquire exclusive lock on {}", path.display()))?;
155
156        fs::write(path, config_str)
157            .with_context(|| format!("Unable to save config to {}", path.display()))?;
158
159        file.unlock()?;
160        Ok(())
161    }
162}
163
164pub struct PersistedConfig<C> {
165    inner: C,
166    path: PathBuf,
167}
168
169impl<C> PersistedConfig<C>
170where
171    C: Config,
172{
173    pub fn read(path: &Path) -> Result<C, anyhow::Error> {
174        Config::load(path)
175    }
176
177    pub fn save(&self) -> Result<(), anyhow::Error> {
178        self.inner.save(&self.path)
179    }
180
181    pub fn save_with_lock(&self) -> Result<(), anyhow::Error> {
182        self.inner.save_with_lock(&self.path)
183    }
184
185    pub fn into_inner(self) -> C {
186        self.inner
187    }
188
189    pub fn path(&self) -> &Path {
190        &self.path
191    }
192}
193
194impl<C> std::ops::Deref for PersistedConfig<C> {
195    type Target = C;
196
197    fn deref(&self) -> &Self::Target {
198        &self.inner
199    }
200}
201
202impl<C> std::ops::DerefMut for PersistedConfig<C> {
203    fn deref_mut(&mut self) -> &mut Self::Target {
204        &mut self.inner
205    }
206}