2020-09-09 16:42:52 -07:00
|
|
|
use serde::{Deserialize, Serialize};
|
|
|
|
use std::path::PathBuf;
|
|
|
|
use zebra_chain::parameters::Network;
|
|
|
|
|
|
|
|
/// Configuration for the state service.
|
|
|
|
#[derive(Clone, Debug, Deserialize, Serialize)]
|
|
|
|
#[serde(deny_unknown_fields, default)]
|
|
|
|
pub struct Config {
|
|
|
|
/// The root directory for storing cached data.
|
|
|
|
///
|
|
|
|
/// Cached data includes any state that can be replicated from the network
|
|
|
|
/// (e.g., the chain state, the blocks, the UTXO set, etc.). It does *not*
|
|
|
|
/// include private data that cannot be replicated from the network, such as
|
|
|
|
/// wallet data. That data is not handled by `zebra-state`.
|
|
|
|
///
|
|
|
|
/// Each network has a separate state, which is stored in "mainnet/state"
|
|
|
|
/// and "testnet/state" subdirectories.
|
|
|
|
///
|
|
|
|
/// The default directory is platform dependent, based on
|
|
|
|
/// [`dirs::cache_dir()`](https://docs.rs/dirs/3.0.1/dirs/fn.cache_dir.html):
|
|
|
|
///
|
|
|
|
/// |Platform | Value | Example |
|
|
|
|
/// | ------- | ----------------------------------------------- | ---------------------------------- |
|
|
|
|
/// | Linux | `$XDG_CACHE_HOME/zebra` or `$HOME/.cache/zebra` | /home/alice/.cache/zebra |
|
|
|
|
/// | macOS | `$HOME/Library/Caches/zebra` | /Users/Alice/Library/Caches/zebra |
|
|
|
|
/// | Windows | `{FOLDERID_LocalAppData}\zebra` | C:\Users\Alice\AppData\Local\zebra |
|
|
|
|
/// | Other | `std::env::current_dir()/cache` | |
|
|
|
|
pub cache_dir: PathBuf,
|
|
|
|
|
|
|
|
/// Whether to use an ephemeral database.
|
|
|
|
///
|
|
|
|
/// Ephemeral databases are stored in memory on Linux, and in a temporary directory on other OSes.
|
|
|
|
///
|
|
|
|
/// Set to `false` by default. If this is set to `true`, [`cache_dir`] is ignored.
|
|
|
|
///
|
|
|
|
/// [`cache_dir`]: struct.Config.html#structfield.cache_dir
|
|
|
|
pub ephemeral: bool,
|
2020-10-27 02:25:29 -07:00
|
|
|
|
|
|
|
/// Commit blocks to the finalized state up to this height, then exit Zebra.
|
|
|
|
///
|
|
|
|
/// If `None`, continue syncing indefinitely.
|
|
|
|
pub debug_stop_at_height: Option<u32>,
|
2020-09-09 16:42:52 -07:00
|
|
|
}
|
|
|
|
|
2020-11-18 18:05:06 -08:00
|
|
|
fn gen_temp_path() -> PathBuf {
|
|
|
|
use std::sync::atomic::{AtomicUsize, Ordering};
|
|
|
|
use std::time::SystemTime;
|
|
|
|
|
|
|
|
static SALT_COUNTER: AtomicUsize = AtomicUsize::new(0);
|
|
|
|
|
|
|
|
let seed = SALT_COUNTER.fetch_add(1, Ordering::SeqCst) as u128;
|
|
|
|
|
|
|
|
let now = SystemTime::now()
|
|
|
|
.duration_since(SystemTime::UNIX_EPOCH)
|
|
|
|
.unwrap()
|
|
|
|
.as_nanos()
|
|
|
|
<< 48;
|
|
|
|
|
|
|
|
#[cfg(not(miri))]
|
|
|
|
let pid = u128::from(std::process::id());
|
|
|
|
|
|
|
|
#[cfg(miri)]
|
|
|
|
let pid = 0;
|
|
|
|
|
|
|
|
let salt = (pid << 16) + now + seed;
|
|
|
|
|
|
|
|
if cfg!(target_os = "linux") {
|
|
|
|
// use shared memory for temporary linux files
|
|
|
|
format!("/dev/shm/pagecache.tmp.{}", salt).into()
|
|
|
|
} else {
|
|
|
|
std::env::temp_dir().join(format!("pagecache.tmp.{}", salt))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-09-09 16:42:52 -07:00
|
|
|
impl Config {
|
2020-11-18 18:05:06 -08:00
|
|
|
pub(crate) fn open_db(&self, network: Network) -> rocksdb::DB {
|
2020-09-09 16:42:52 -07:00
|
|
|
let net_dir = match network {
|
|
|
|
Network::Mainnet => "mainnet",
|
|
|
|
Network::Testnet => "testnet",
|
|
|
|
};
|
|
|
|
|
2020-11-18 18:05:06 -08:00
|
|
|
let mut opts = rocksdb::Options::default();
|
2020-09-09 16:42:52 -07:00
|
|
|
|
2020-11-18 18:05:06 -08:00
|
|
|
let cfs = vec![
|
|
|
|
rocksdb::ColumnFamilyDescriptor::new("hash_by_height", opts.clone()),
|
|
|
|
rocksdb::ColumnFamilyDescriptor::new("height_by_hash", opts.clone()),
|
|
|
|
rocksdb::ColumnFamilyDescriptor::new("block_by_height", opts.clone()),
|
|
|
|
rocksdb::ColumnFamilyDescriptor::new("tx_by_hash", opts.clone()),
|
|
|
|
rocksdb::ColumnFamilyDescriptor::new("utxo_by_outpoint", opts.clone()),
|
|
|
|
rocksdb::ColumnFamilyDescriptor::new("sprout_nullifiers", opts.clone()),
|
|
|
|
rocksdb::ColumnFamilyDescriptor::new("sapling_nullifiers", opts.clone()),
|
|
|
|
];
|
|
|
|
|
|
|
|
opts.create_if_missing(true);
|
|
|
|
opts.create_missing_column_families(true);
|
|
|
|
|
|
|
|
let path = if self.ephemeral {
|
|
|
|
gen_temp_path()
|
2020-09-09 16:42:52 -07:00
|
|
|
} else {
|
2020-11-18 18:05:06 -08:00
|
|
|
self.cache_dir
|
2020-10-27 14:24:00 -07:00
|
|
|
.join("state")
|
2020-11-18 18:05:06 -08:00
|
|
|
.join(format!("v{}", crate::constants::DATABASE_FORMAT_VERSION))
|
|
|
|
.join(net_dir)
|
|
|
|
};
|
2020-10-27 14:24:00 -07:00
|
|
|
|
2020-11-18 18:05:06 -08:00
|
|
|
rocksdb::DB::open_cf_descriptors(&opts, path, cfs).unwrap()
|
2020-09-09 16:42:52 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Construct a config for an ephemeral in memory database
|
|
|
|
pub fn ephemeral() -> Self {
|
|
|
|
let mut config = Self::default();
|
|
|
|
config.ephemeral = true;
|
|
|
|
config
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Default for Config {
|
|
|
|
fn default() -> Self {
|
|
|
|
let cache_dir = dirs::cache_dir()
|
|
|
|
.unwrap_or_else(|| std::env::current_dir().unwrap().join("cache"))
|
|
|
|
.join("zebra");
|
|
|
|
|
|
|
|
Self {
|
|
|
|
cache_dir,
|
|
|
|
ephemeral: false,
|
2020-10-27 02:25:29 -07:00
|
|
|
debug_stop_at_height: None,
|
2020-09-09 16:42:52 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|