aleo_std_storage/
lib.rs

1// Copyright (C) 2019-2021 Aleo Systems Inc.
2// This file is part of the aleo-std library.
3
4// The aleo-std library is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8
9// The aleo-std library is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU General Public License for more details.
13
14// You should have received a copy of the GNU General Public License
15// along with the aleo-std library. If not, see <https://www.gnu.org/licenses/>.
16
17use dirs::home_dir;
18use std::{path::PathBuf, sync::Arc};
19use tempfile::TempDir;
20
21/// The directory name for Aleo-related resources.
22const ALEO_DIRECTORY: &str = ".aleo";
23
24/// An enum to define the operating mode of the Aleo node.
25#[derive(Clone, Debug)]
26pub enum StorageMode {
27    /// The production mode is used for running a node on the Aleo mainnet.
28    Production,
29    /// The development mode is used for running a node on a local network.
30    Development(u16),
31    /// The custom mode is used for running a node on custom configurations.
32    Custom(PathBuf),
33    /// Test-only ephemeral storage which self-destructs afterwards.
34    Test(Option<Arc<TempDir>>),
35}
36
37impl StorageMode {
38    pub fn new_test(tempdir: Option<Arc<TempDir>>) -> Self {
39        if tempdir.is_some() {
40            Self::Test(tempdir)
41        } else {
42            Self::Test(Some(Arc::new(tempfile::TempDir::with_prefix("aleo_storage_").unwrap())))
43        }
44    }
45}
46
47impl PartialEq for StorageMode {
48    fn eq(&self, other: &Self) -> bool {
49        match (self, other) {
50            (StorageMode::Production, StorageMode::Production) => true,
51            (StorageMode::Development(id1), StorageMode::Development(id2)) => id1 == id2,
52            (StorageMode::Custom(path1), StorageMode::Custom(path2)) => path1 == path2,
53            (StorageMode::Test(Some(temp1)), StorageMode::Test(Some(temp2))) => temp1.path() == temp2.path(),
54            _ => false,
55        }
56    }
57}
58impl Eq for StorageMode {}
59
60impl From<u16> for StorageMode {
61    fn from(id: u16) -> Self {
62        StorageMode::Development(id)
63    }
64}
65
66impl From<PathBuf> for StorageMode {
67    fn from(path: PathBuf) -> Self {
68        StorageMode::Custom(path)
69    }
70}
71
72impl From<Arc<TempDir>> for StorageMode {
73    fn from(tempdir: Arc<TempDir>) -> Self {
74        StorageMode::Test(Some(tempdir))
75    }
76}
77
78impl StorageMode {
79    /// Returns the development ID if the mode is development.
80    pub const fn dev(&self) -> Option<u16> {
81        match self {
82            Self::Development(id) => Some(*id),
83            Self::Production | Self::Custom(_) | Self::Test(_) => None,
84        }
85    }
86}
87
88///
89/// Returns the directory for accessing resources from Aleo storage.
90/// The expected directory path to be returned is `~/.aleo/`.
91///
92pub fn aleo_dir() -> PathBuf {
93    // Locate the home directory as the starting point.
94    // If called on a non-standard OS, use the repository directory.
95    let mut path = match home_dir() {
96        Some(home) => home,
97        None => PathBuf::from(env!("CARGO_MANIFEST_DIR")),
98    };
99    // Append the Aleo directory to the path.
100    path.push(ALEO_DIRECTORY);
101    path
102}
103
104///
105/// Returns the directory for accessing the ledger files from Aleo storage.
106///
107/// In production mode, the expected directory path is `~/.aleo/storage/ledger-{network}`.
108/// In development mode, the expected directory path is `/path/to/repo/.ledger-{network}-{id}`.
109/// In custom mode, the expected directory path is `/path/to/custom`.
110///
111pub fn aleo_ledger_dir(network: u16, mode: &StorageMode) -> PathBuf {
112    // Construct the path to the ledger in storage.
113    match mode {
114        // In production mode, the ledger is stored in the `~/.aleo/` directory.
115        StorageMode::Production => {
116            let mut path = aleo_dir();
117            path.push("storage");
118            path.push(format!("ledger-{}", network));
119            path
120        }
121        // In development mode, the ledger files are stored in a hidden folder in the repository root directory.
122        StorageMode::Development(id) => {
123            let mut path = match std::env::current_dir() {
124                Ok(current_dir) => current_dir,
125                _ => PathBuf::from(env!("CARGO_MANIFEST_DIR")),
126            };
127            path.push(format!(".ledger-{}-{}", network, id));
128            path
129        }
130        // In custom mode, the ledger files are stored in the given directory path.
131        StorageMode::Custom(path) => path.to_owned(),
132        StorageMode::Test(tempdir) => {
133            if let Some(tempdir) = tempdir {
134                tempdir.path().to_owned()
135            } else {
136                // aleo_ledger_dir is only ever called with persistent storage, where TempDir must be present.
137                panic!("StorageMode::Test was created in a persistent storage context without a TempDir");
138            }
139        }
140    }
141}
142
143#[cfg(test)]
144mod tests {
145    use super::*;
146
147    #[test]
148    fn test_aleo_dir() {
149        println!("{:?} exists: {:?}", aleo_dir(), aleo_dir().exists());
150    }
151
152    #[test]
153    fn test_aleo_ledger_dir() {
154        println!(
155            "{:?} exists: {:?}",
156            aleo_ledger_dir(2, &StorageMode::Production),
157            aleo_ledger_dir(2, &StorageMode::Production).exists()
158        );
159    }
160}