mirror of
https://github.com/Cuprate/cuprate.git
synced 2024-12-22 19:49:28 +00:00
Merge branch 'cuprated-config' into init
This commit is contained in:
commit
bbf83b27a8
34 changed files with 912 additions and 162 deletions
40
Cargo.lock
generated
40
Cargo.lock
generated
|
@ -388,6 +388,7 @@ checksum = "19bc80abd44e4bed93ca373a0704ccbd1b710dc5749406201bb018272808dc54"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anstyle",
|
"anstyle",
|
||||||
"clap_lex",
|
"clap_lex",
|
||||||
|
"terminal_size",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -790,6 +791,7 @@ dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"monero-serai",
|
"monero-serai",
|
||||||
"rayon",
|
"rayon",
|
||||||
|
"serde",
|
||||||
"tokio",
|
"tokio",
|
||||||
"windows",
|
"windows",
|
||||||
]
|
]
|
||||||
|
@ -1035,7 +1037,6 @@ dependencies = [
|
||||||
"cuprate-consensus",
|
"cuprate-consensus",
|
||||||
"cuprate-consensus-context",
|
"cuprate-consensus-context",
|
||||||
"cuprate-consensus-rules",
|
"cuprate-consensus-rules",
|
||||||
"cuprate-constants",
|
|
||||||
"cuprate-cryptonight",
|
"cuprate-cryptonight",
|
||||||
"cuprate-dandelion-tower",
|
"cuprate-dandelion-tower",
|
||||||
"cuprate-database",
|
"cuprate-database",
|
||||||
|
@ -1077,6 +1078,7 @@ dependencies = [
|
||||||
"tokio",
|
"tokio",
|
||||||
"tokio-stream",
|
"tokio-stream",
|
||||||
"tokio-util",
|
"tokio-util",
|
||||||
|
"toml",
|
||||||
"tower 0.5.1 (git+https://github.com/Cuprate/tower.git?rev=6c7faf0)",
|
"tower 0.5.1 (git+https://github.com/Cuprate/tower.git?rev=6c7faf0)",
|
||||||
"tracing",
|
"tracing",
|
||||||
"tracing-subscriber",
|
"tracing-subscriber",
|
||||||
|
@ -2616,6 +2618,15 @@ dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde_spanned"
|
||||||
|
version = "0.6.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1"
|
||||||
|
dependencies = [
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_urlencoded"
|
name = "serde_urlencoded"
|
||||||
version = "0.7.1"
|
version = "0.7.1"
|
||||||
|
@ -2833,6 +2844,16 @@ dependencies = [
|
||||||
"windows-sys 0.59.0",
|
"windows-sys 0.59.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "terminal_size"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4f599bd7ca042cfdf8f4512b277c02ba102247820f9d9d4a9f521f496751a6ef"
|
||||||
|
dependencies = [
|
||||||
|
"rustix",
|
||||||
|
"windows-sys 0.59.0",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "thiserror"
|
name = "thiserror"
|
||||||
version = "1.0.66"
|
version = "1.0.66"
|
||||||
|
@ -2964,11 +2985,26 @@ dependencies = [
|
||||||
"tracing",
|
"tracing",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "toml"
|
||||||
|
version = "0.8.19"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a1ed1f98e3fdc28d6d910e6737ae6ab1a93bf1985935a1193e68f93eeb68d24e"
|
||||||
|
dependencies = [
|
||||||
|
"serde",
|
||||||
|
"serde_spanned",
|
||||||
|
"toml_datetime",
|
||||||
|
"toml_edit",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "toml_datetime"
|
name = "toml_datetime"
|
||||||
version = "0.6.8"
|
version = "0.6.8"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41"
|
checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41"
|
||||||
|
dependencies = [
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "toml_edit"
|
name = "toml_edit"
|
||||||
|
@ -2977,6 +3013,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5"
|
checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"indexmap",
|
"indexmap",
|
||||||
|
"serde",
|
||||||
|
"serde_spanned",
|
||||||
"toml_datetime",
|
"toml_datetime",
|
||||||
"winnow",
|
"winnow",
|
||||||
]
|
]
|
||||||
|
|
|
@ -33,6 +33,7 @@ members = [
|
||||||
]
|
]
|
||||||
|
|
||||||
[profile.release]
|
[profile.release]
|
||||||
|
panic = "abort"
|
||||||
lto = true # Build with LTO
|
lto = true # Build with LTO
|
||||||
strip = "none" # Keep panic stack traces
|
strip = "none" # Keep panic stack traces
|
||||||
codegen-units = 1 # Optimize for binary speed over compile times
|
codegen-units = 1 # Optimize for binary speed over compile times
|
||||||
|
@ -119,6 +120,7 @@ tokio-util = { version = "0.7", default-features = false }
|
||||||
tokio-stream = { version = "0.1", default-features = false }
|
tokio-stream = { version = "0.1", default-features = false }
|
||||||
tokio = { version = "1", default-features = false }
|
tokio = { version = "1", default-features = false }
|
||||||
tower = { git = "https://github.com/Cuprate/tower.git", rev = "6c7faf0", default-features = false } # <https://github.com/tower-rs/tower/pull/796>
|
tower = { git = "https://github.com/Cuprate/tower.git", rev = "6c7faf0", default-features = false } # <https://github.com/tower-rs/tower/pull/796>
|
||||||
|
toml = { version = "0.8", default-features = false }
|
||||||
tracing-subscriber = { version = "0.3", default-features = false }
|
tracing-subscriber = { version = "0.3", default-features = false }
|
||||||
tracing = { version = "0.1", default-features = false }
|
tracing = { version = "0.1", default-features = false }
|
||||||
|
|
||||||
|
|
67
Cuprated.toml
Normal file
67
Cuprated.toml
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
# ____ _
|
||||||
|
# / ___| _ _ __ _ __ __ _| |_ ___
|
||||||
|
# | | | | | | '_ \| '__/ _` | __/ _ \
|
||||||
|
# | |__| |_| | |_) | | | (_| | || __/
|
||||||
|
# \____\__,_| .__/|_| \__,_|\__\___|
|
||||||
|
# |_|
|
||||||
|
#
|
||||||
|
|
||||||
|
## The network to run on, valid values: "Mainnet", "Testnet", "Stagenet".
|
||||||
|
network = "Mainnet"
|
||||||
|
|
||||||
|
## Tracing config.
|
||||||
|
[tracing]
|
||||||
|
## The minimum level for log events to be displayed.
|
||||||
|
level = "info"
|
||||||
|
|
||||||
|
## Clear-net config.
|
||||||
|
[p2p.clear_net]
|
||||||
|
## The number of outbound connections we should make and maintain.
|
||||||
|
outbound_connections = 64
|
||||||
|
## The number of extra connections we should make under load from the rest of Cuprate, i.e. when syncing.
|
||||||
|
extra_outbound_connections = 8
|
||||||
|
## The maximum number of incoming we should allow.
|
||||||
|
max_inbound_connections = 128
|
||||||
|
## The percent of outbound connections that should be to nodes we have not connected to before.
|
||||||
|
gray_peers_percent = 0.7
|
||||||
|
## The port to accept connections on, if left `0` no connections will be accepted.
|
||||||
|
p2p_port = 0
|
||||||
|
## The IP address to listen to connections on.
|
||||||
|
listen_on = "0.0.0.0"
|
||||||
|
|
||||||
|
## The Clear-net addressbook config.
|
||||||
|
[p2p.clear_net.address_book_config]
|
||||||
|
## The size of the white peer list, which contains peers we have made a connection to before.
|
||||||
|
max_white_list_length = 1_000
|
||||||
|
## The size of the gray peer list, which contains peers we have not made a connection to before.
|
||||||
|
max_gray_list_length = 5_000
|
||||||
|
## The amount of time between address book saves.
|
||||||
|
peer_save_period = { secs = 90, nanos = 0 }
|
||||||
|
|
||||||
|
## The block downloader config.
|
||||||
|
[p2p.block_downloader]
|
||||||
|
## The size of the buffer of sequential blocks waiting to be verified and added to the chain (bytes).
|
||||||
|
buffer_size = 50_000_000
|
||||||
|
## The size of the queue of blocks which are waiting for a parent block to be downloaded (bytes).
|
||||||
|
in_progress_queue_size = 50_000_000
|
||||||
|
## The target size of a batch of blocks (bytes), must not exceed 100MB.
|
||||||
|
target_batch_size = 5_000_000
|
||||||
|
## The amount of time between checking the pool of connected peers for free peers to download blocks.
|
||||||
|
check_client_pool_interval = { secs = 30, nanos = 0 }
|
||||||
|
|
||||||
|
## Storage config
|
||||||
|
[storage]
|
||||||
|
## The amount of reader threads to spawn.
|
||||||
|
reader_threads = "OnePerThread"
|
||||||
|
|
||||||
|
## Txpool storage config.
|
||||||
|
[storage.txpool]
|
||||||
|
## The database sync mode for the txpool.
|
||||||
|
sync_mode = "Async"
|
||||||
|
## The maximum size of all the txs in the pool (bytes).
|
||||||
|
max_txpool_byte_size = 100_000_000
|
||||||
|
|
||||||
|
## Blockchain storage config.
|
||||||
|
[storage.blockchain]
|
||||||
|
## The database sync mode for the blockchain.
|
||||||
|
sync_mode = "Async"
|
|
@ -2,7 +2,7 @@
|
||||||
name = "cuprated"
|
name = "cuprated"
|
||||||
version = "0.0.1"
|
version = "0.0.1"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
description = "The Cuprate Monero Rust node."
|
description = "The Cuprate Rust Monero node."
|
||||||
license = "AGPL-3.0-only"
|
license = "AGPL-3.0-only"
|
||||||
authors = ["Boog900", "hinto-janai", "SyntheticBird45"]
|
authors = ["Boog900", "hinto-janai", "SyntheticBird45"]
|
||||||
repository = "https://github.com/Cuprate/cuprate/tree/main/binaries/cuprated"
|
repository = "https://github.com/Cuprate/cuprate/tree/main/binaries/cuprated"
|
||||||
|
@ -12,29 +12,29 @@ repository = "https://github.com/Cuprate/cuprate/tree/main/binaries/cuprated"
|
||||||
cuprate-consensus = { workspace = true }
|
cuprate-consensus = { workspace = true }
|
||||||
cuprate-fast-sync = { workspace = true }
|
cuprate-fast-sync = { workspace = true }
|
||||||
cuprate-consensus-context = { workspace = true }
|
cuprate-consensus-context = { workspace = true }
|
||||||
cuprate-consensus-rules = { workspace = true }
|
cuprate-consensus-rules = { workspace = true }
|
||||||
cuprate-constants = { workspace = true }
|
cuprate-cryptonight = { workspace = true }
|
||||||
cuprate-cryptonight = { workspace = true }
|
cuprate-helper = { workspace = true, features = ["serde"] }
|
||||||
cuprate-helper = { workspace = true }
|
cuprate-epee-encoding = { workspace = true }
|
||||||
cuprate-epee-encoding = { workspace = true }
|
cuprate-fixed-bytes = { workspace = true }
|
||||||
cuprate-fixed-bytes = { workspace = true }
|
cuprate-levin = { workspace = true }
|
||||||
cuprate-levin = { workspace = true }
|
cuprate-wire = { workspace = true }
|
||||||
cuprate-wire = { workspace = true }
|
cuprate-p2p = { workspace = true }
|
||||||
cuprate-p2p = { workspace = true }
|
cuprate-p2p-core = { workspace = true }
|
||||||
cuprate-p2p-core = { workspace = true }
|
cuprate-dandelion-tower = { workspace = true, features = ["txpool"] }
|
||||||
cuprate-dandelion-tower = { workspace = true, features = ["txpool"] }
|
cuprate-async-buffer = { workspace = true }
|
||||||
cuprate-async-buffer = { workspace = true }
|
cuprate-address-book = { workspace = true }
|
||||||
cuprate-address-book = { workspace = true }
|
cuprate-blockchain = { workspace = true }
|
||||||
cuprate-blockchain = { workspace = true }
|
cuprate-database-service = { workspace = true, features = ["serde"] }
|
||||||
cuprate-database-service = { workspace = true }
|
cuprate-txpool = { workspace = true }
|
||||||
cuprate-txpool = { workspace = true }
|
cuprate-database = { workspace = true, features = ["serde"] }
|
||||||
cuprate-database = { workspace = true }
|
cuprate-pruning = { workspace = true }
|
||||||
cuprate-pruning = { workspace = true }
|
cuprate-test-utils = { workspace = true }
|
||||||
cuprate-test-utils = { workspace = true }
|
cuprate-types = { workspace = true }
|
||||||
cuprate-types = { workspace = true }
|
cuprate-json-rpc = { workspace = true }
|
||||||
cuprate-json-rpc = { workspace = true }
|
cuprate-rpc-interface = { workspace = true }
|
||||||
cuprate-rpc-interface = { workspace = true }
|
cuprate-rpc-types = { workspace = true }
|
||||||
cuprate-rpc-types = { workspace = true }
|
|
||||||
|
|
||||||
# TODO: after v1.0.0, remove unneeded dependencies.
|
# TODO: after v1.0.0, remove unneeded dependencies.
|
||||||
anyhow = { workspace = true }
|
anyhow = { workspace = true }
|
||||||
|
@ -44,7 +44,7 @@ borsh = { workspace = true }
|
||||||
bytemuck = { workspace = true }
|
bytemuck = { workspace = true }
|
||||||
bytes = { workspace = true }
|
bytes = { workspace = true }
|
||||||
cfg-if = { workspace = true }
|
cfg-if = { workspace = true }
|
||||||
clap = { workspace = true, features = ["cargo"] }
|
clap = { workspace = true, features = ["cargo", "help", "wrap_help"] }
|
||||||
chrono = { workspace = true }
|
chrono = { workspace = true }
|
||||||
crypto-bigint = { workspace = true }
|
crypto-bigint = { workspace = true }
|
||||||
crossbeam = { workspace = true }
|
crossbeam = { workspace = true }
|
||||||
|
@ -71,15 +71,10 @@ thread_local = { workspace = true }
|
||||||
tokio-util = { workspace = true }
|
tokio-util = { workspace = true }
|
||||||
tokio-stream = { workspace = true }
|
tokio-stream = { workspace = true }
|
||||||
tokio = { workspace = true }
|
tokio = { workspace = true }
|
||||||
|
toml = { workspace = true, features = ["parse", "display"]}
|
||||||
tower = { workspace = true }
|
tower = { workspace = true }
|
||||||
tracing-subscriber = { workspace = true, features = ["std", "fmt", "default"] }
|
tracing-subscriber = { workspace = true, features = ["std", "fmt", "default"] }
|
||||||
tracing = { workspace = true }
|
tracing = { workspace = true, features = ["default"] }
|
||||||
|
|
||||||
[lints]
|
[lints]
|
||||||
workspace = true
|
workspace = true
|
||||||
|
|
||||||
[profile.dev]
|
|
||||||
panic = "abort"
|
|
||||||
|
|
||||||
[profile.release]
|
|
||||||
panic = "abort"
|
|
||||||
|
|
|
@ -1 +1,159 @@
|
||||||
//! cuprated config
|
//! cuprated config
|
||||||
|
use std::{
|
||||||
|
fs::{read_to_string, File},
|
||||||
|
io,
|
||||||
|
path::Path,
|
||||||
|
time::Duration,
|
||||||
|
};
|
||||||
|
|
||||||
|
use clap::Parser;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
use cuprate_consensus::ContextConfig;
|
||||||
|
use cuprate_helper::{
|
||||||
|
fs::{CUPRATE_CONFIG_DIR, DEFAULT_CONFIG_FILE_NAME},
|
||||||
|
network::Network,
|
||||||
|
};
|
||||||
|
use cuprate_p2p::block_downloader::BlockDownloaderConfig;
|
||||||
|
use cuprate_p2p_core::{ClearNet, ClearNetServerCfg};
|
||||||
|
|
||||||
|
mod args;
|
||||||
|
mod default;
|
||||||
|
mod fs;
|
||||||
|
mod p2p;
|
||||||
|
mod storage;
|
||||||
|
mod tracing_config;
|
||||||
|
|
||||||
|
use crate::config::fs::FileSystemConfig;
|
||||||
|
use p2p::P2PConfig;
|
||||||
|
use storage::StorageConfig;
|
||||||
|
use tracing_config::TracingConfig;
|
||||||
|
|
||||||
|
/// Reads the args & config file, returning a [`Config`].
|
||||||
|
pub fn read_config_and_args() -> Config {
|
||||||
|
let args = args::Args::parse();
|
||||||
|
|
||||||
|
let config: Config = if let Some(config_file) = &args.config_file {
|
||||||
|
// If a config file was set in the args try to read it and exit if we can't.
|
||||||
|
match Config::read_from_path(config_file) {
|
||||||
|
Ok(config) => config,
|
||||||
|
Err(e) => {
|
||||||
|
tracing::error!("Failed to read config from file: {e}");
|
||||||
|
std::process::exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// First attempt to read the config file from the current directory.
|
||||||
|
std::env::current_dir()
|
||||||
|
.map(|path| path.join(DEFAULT_CONFIG_FILE_NAME))
|
||||||
|
.map_err(Into::into)
|
||||||
|
.and_then(Config::read_from_path)
|
||||||
|
.inspect_err(|e| tracing::debug!("Failed to read config from current dir: {e}"))
|
||||||
|
// otherwise try the main config directory.
|
||||||
|
.or_else(|_| {
|
||||||
|
let file = CUPRATE_CONFIG_DIR.join(DEFAULT_CONFIG_FILE_NAME);
|
||||||
|
Config::read_from_path(file)
|
||||||
|
})
|
||||||
|
.inspect_err(|e| {
|
||||||
|
tracing::debug!("Failed to read config from config dir: {e}");
|
||||||
|
println!("Failed to find/read config file, using default config.");
|
||||||
|
})
|
||||||
|
.unwrap_or_default()
|
||||||
|
};
|
||||||
|
|
||||||
|
args.apply_args(config)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The config for all of Cuprate.
|
||||||
|
#[derive(Default, Deserialize, Serialize)]
|
||||||
|
#[serde(deny_unknown_fields, default)]
|
||||||
|
pub struct Config {
|
||||||
|
/// The network we should run on.
|
||||||
|
network: Network,
|
||||||
|
|
||||||
|
/// [`tracing`] config.
|
||||||
|
tracing: TracingConfig,
|
||||||
|
|
||||||
|
/// The P2P network config.
|
||||||
|
p2p: P2PConfig,
|
||||||
|
|
||||||
|
/// The storage config.
|
||||||
|
storage: StorageConfig,
|
||||||
|
|
||||||
|
fs: FileSystemConfig,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Config {
|
||||||
|
/// Attempts to read a config file in [`toml`] format from the given [`Path`].
|
||||||
|
///
|
||||||
|
/// # Errors
|
||||||
|
///
|
||||||
|
/// Will return an [`Err`] if the file cannot be read or if the file is not a valid [`toml`] config.
|
||||||
|
fn read_from_path(file: impl AsRef<Path>) -> Result<Self, anyhow::Error> {
|
||||||
|
let file_text = read_to_string(file.as_ref())?;
|
||||||
|
|
||||||
|
Ok(toml::from_str(&file_text)
|
||||||
|
.inspect(|_| println!("Using config at: {}", file.as_ref().to_string_lossy()))
|
||||||
|
.inspect_err(|e| {
|
||||||
|
println!("{e}");
|
||||||
|
println!(
|
||||||
|
"Failed to parse config file at: {}",
|
||||||
|
file.as_ref().to_string_lossy()
|
||||||
|
);
|
||||||
|
})?)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the current [`Network`] we are running on.
|
||||||
|
pub const fn network(&self) -> Network {
|
||||||
|
self.network
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The [`ClearNet`], [`cuprate_p2p::P2PConfig`].
|
||||||
|
pub fn clearnet_p2p_config(&self) -> cuprate_p2p::P2PConfig<ClearNet> {
|
||||||
|
cuprate_p2p::P2PConfig {
|
||||||
|
network: self.network,
|
||||||
|
seeds: p2p::clear_net_seed_nodes(self.network),
|
||||||
|
outbound_connections: self.p2p.clear_net.general.outbound_connections,
|
||||||
|
extra_outbound_connections: self.p2p.clear_net.general.extra_outbound_connections,
|
||||||
|
max_inbound_connections: self.p2p.clear_net.general.max_inbound_connections,
|
||||||
|
gray_peers_percent: self.p2p.clear_net.general.gray_peers_percent,
|
||||||
|
server_config: Some(ClearNetServerCfg {
|
||||||
|
ip: self.p2p.clear_net.listen_on,
|
||||||
|
}),
|
||||||
|
p2p_port: self.p2p.clear_net.general.p2p_port,
|
||||||
|
// TODO: set this if a public RPC server is set.
|
||||||
|
rpc_port: 0,
|
||||||
|
address_book_config: self
|
||||||
|
.p2p
|
||||||
|
.clear_net
|
||||||
|
.general
|
||||||
|
.address_book_config(&self.fs.cache_directory, self.network),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The [`ContextConfig`].
|
||||||
|
pub const fn context_config(&self) -> ContextConfig {
|
||||||
|
match self.network {
|
||||||
|
Network::Mainnet => ContextConfig::main_net(),
|
||||||
|
Network::Stagenet => ContextConfig::stage_net(),
|
||||||
|
Network::Testnet => ContextConfig::test_net(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The [`cuprate_blockchain`] config.
|
||||||
|
pub fn blockchain_config(&self) -> cuprate_blockchain::config::Config {
|
||||||
|
let blockchain = &self.storage.blockchain;
|
||||||
|
|
||||||
|
// We don't set reader threads as we manually make the reader threadpool.
|
||||||
|
cuprate_blockchain::config::ConfigBuilder::default()
|
||||||
|
.network(self.network)
|
||||||
|
.data_directory(self.fs.data_directory.clone())
|
||||||
|
.sync_mode(blockchain.shared.sync_mode)
|
||||||
|
.build()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The [`BlockDownloaderConfig`].
|
||||||
|
pub fn block_downloader_config(&self) -> BlockDownloaderConfig {
|
||||||
|
self.p2p.block_downloader.clone().into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
50
binaries/cuprated/src/config/args.rs
Normal file
50
binaries/cuprated/src/config/args.rs
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
use std::{io::Write, path::PathBuf};
|
||||||
|
|
||||||
|
use clap::builder::TypedValueParser;
|
||||||
|
|
||||||
|
use cuprate_helper::network::Network;
|
||||||
|
|
||||||
|
use crate::config::{default::create_default_config_file, Config};
|
||||||
|
|
||||||
|
/// Cuprate Args.
|
||||||
|
#[derive(clap::Parser, Debug)]
|
||||||
|
#[command(version, about)]
|
||||||
|
pub struct Args {
|
||||||
|
/// The network to run on.
|
||||||
|
#[arg(
|
||||||
|
long,
|
||||||
|
default_value_t = Network::Mainnet,
|
||||||
|
value_parser = clap::builder::PossibleValuesParser::new(["mainnet", "testnet", "stagenet"])
|
||||||
|
.map(|s| s.parse::<Network>().unwrap()),
|
||||||
|
)]
|
||||||
|
pub network: Network,
|
||||||
|
/// The amount of outbound clear-net connections to maintain.
|
||||||
|
#[arg(long)]
|
||||||
|
pub outbound_connections: Option<usize>,
|
||||||
|
/// The PATH of the `cuprated` config file.
|
||||||
|
#[arg(long)]
|
||||||
|
pub config_file: Option<PathBuf>,
|
||||||
|
/// Generate a config file and place it in the given PATH.
|
||||||
|
#[arg(long)]
|
||||||
|
pub generate_config: Option<PathBuf>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Args {
|
||||||
|
/// Apply the [`Args`] to the given [`Config`].
|
||||||
|
///
|
||||||
|
/// This may exit the program if a config value was set that requires an early exit.
|
||||||
|
pub fn apply_args(&self, mut config: Config) -> Config {
|
||||||
|
if let Some(config_folder) = self.generate_config.as_ref() {
|
||||||
|
// This will create the config file and exit.
|
||||||
|
create_default_config_file(config_folder)
|
||||||
|
};
|
||||||
|
|
||||||
|
config.network = self.network;
|
||||||
|
|
||||||
|
if let Some(outbound_connections) = self.outbound_connections {
|
||||||
|
config.p2p.clear_net.general.outbound_connections = outbound_connections;
|
||||||
|
}
|
||||||
|
|
||||||
|
config
|
||||||
|
}
|
||||||
|
}
|
44
binaries/cuprated/src/config/default.rs
Normal file
44
binaries/cuprated/src/config/default.rs
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
use std::{
|
||||||
|
io::Write,
|
||||||
|
path::{Path, PathBuf},
|
||||||
|
str::from_utf8,
|
||||||
|
};
|
||||||
|
|
||||||
|
use cuprate_helper::fs::{CUPRATE_CACHE_DIR, DEFAULT_CONFIG_FILE_NAME};
|
||||||
|
|
||||||
|
use crate::constants::EXAMPLE_CONFIG;
|
||||||
|
|
||||||
|
/// Creates a config file which will be named [`DEFAULT_CONFIG_FILE_NAME`] in the directory given in [`Path`].
|
||||||
|
///
|
||||||
|
/// This will always terminate the program, on success and failure.
|
||||||
|
pub fn create_default_config_file(path: &Path) -> ! {
|
||||||
|
let config_file = path.join(DEFAULT_CONFIG_FILE_NAME);
|
||||||
|
|
||||||
|
tracing::info!("Attempting to create new config file here: {config_file:?}");
|
||||||
|
|
||||||
|
let mut file = match std::fs::OpenOptions::new()
|
||||||
|
.write(true)
|
||||||
|
.create_new(true)
|
||||||
|
.open(&config_file)
|
||||||
|
{
|
||||||
|
Ok(file) => file,
|
||||||
|
Err(e) => {
|
||||||
|
tracing::error!("Failed to create config file, got error: {e}");
|
||||||
|
std::process::exit(1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let config = EXAMPLE_CONFIG;
|
||||||
|
file.write_all(config.as_bytes()).unwrap();
|
||||||
|
|
||||||
|
std::process::exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use crate::{config::Config, constants::EXAMPLE_CONFIG};
|
||||||
|
#[test]
|
||||||
|
fn generate_config_text_is_valid() {
|
||||||
|
let config: Config = toml::from_str(EXAMPLE_CONFIG).unwrap();
|
||||||
|
}
|
||||||
|
}
|
21
binaries/cuprated/src/config/fs.rs
Normal file
21
binaries/cuprated/src/config/fs.rs
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
use cuprate_helper::fs::{CUPRATE_CACHE_DIR, CUPRATE_DATA_DIR};
|
||||||
|
|
||||||
|
#[derive(Deserialize, Serialize)]
|
||||||
|
#[serde(deny_unknown_fields, default)]
|
||||||
|
pub struct FileSystemConfig {
|
||||||
|
pub data_directory: PathBuf,
|
||||||
|
pub cache_directory: PathBuf,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for FileSystemConfig {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
data_directory: CUPRATE_DATA_DIR.to_path_buf(),
|
||||||
|
cache_directory: CUPRATE_CACHE_DIR.to_path_buf(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
178
binaries/cuprated/src/config/p2p.rs
Normal file
178
binaries/cuprated/src/config/p2p.rs
Normal file
|
@ -0,0 +1,178 @@
|
||||||
|
use std::{
|
||||||
|
net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr},
|
||||||
|
path::Path,
|
||||||
|
time::Duration,
|
||||||
|
};
|
||||||
|
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
use cuprate_helper::{fs::addressbook_path, network::Network};
|
||||||
|
|
||||||
|
/// P2P config.
|
||||||
|
#[derive(Default, Deserialize, Serialize)]
|
||||||
|
#[serde(deny_unknown_fields, default)]
|
||||||
|
pub struct P2PConfig {
|
||||||
|
/// Clear-net config.
|
||||||
|
pub clear_net: ClearNetConfig,
|
||||||
|
/// Block downloader config.
|
||||||
|
pub block_downloader: BlockDownloaderConfig,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Deserialize, Serialize)]
|
||||||
|
#[serde(deny_unknown_fields, default)]
|
||||||
|
pub struct BlockDownloaderConfig {
|
||||||
|
/// The size in bytes of the buffer between the block downloader and the place which
|
||||||
|
/// is consuming the downloaded blocks.
|
||||||
|
pub buffer_size: usize,
|
||||||
|
/// The size of the in progress queue (in bytes) at which we stop requesting more blocks.
|
||||||
|
pub in_progress_queue_size: usize,
|
||||||
|
/// The [`Duration`] between checking the client pool for free peers.
|
||||||
|
pub check_client_pool_interval: Duration,
|
||||||
|
/// The target size of a single batch of blocks (in bytes).
|
||||||
|
pub target_batch_size: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<BlockDownloaderConfig> for cuprate_p2p::block_downloader::BlockDownloaderConfig {
|
||||||
|
fn from(value: BlockDownloaderConfig) -> Self {
|
||||||
|
Self {
|
||||||
|
buffer_size: value.buffer_size,
|
||||||
|
in_progress_queue_size: value.in_progress_queue_size,
|
||||||
|
check_client_pool_interval: value.check_client_pool_interval,
|
||||||
|
target_batch_size: value.target_batch_size,
|
||||||
|
initial_batch_len: 1,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for BlockDownloaderConfig {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
buffer_size: 50_000_000,
|
||||||
|
in_progress_queue_size: 50_000_000,
|
||||||
|
check_client_pool_interval: Duration::from_secs(30),
|
||||||
|
target_batch_size: 5_000_000,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The config values for P2P clear-net.
|
||||||
|
#[derive(Deserialize, Serialize)]
|
||||||
|
#[serde(deny_unknown_fields, default)]
|
||||||
|
pub struct ClearNetConfig {
|
||||||
|
/// The server config.
|
||||||
|
pub listen_on: IpAddr,
|
||||||
|
#[serde(flatten)]
|
||||||
|
pub general: SharedNetConfig,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for ClearNetConfig {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
listen_on: IpAddr::V4(Ipv4Addr::UNSPECIFIED),
|
||||||
|
general: Default::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Network config values shared between all network zones.
|
||||||
|
#[derive(Deserialize, Serialize)]
|
||||||
|
#[serde(deny_unknown_fields, default)]
|
||||||
|
pub struct SharedNetConfig {
|
||||||
|
/// The number of outbound connections to make and try keep.
|
||||||
|
pub outbound_connections: usize,
|
||||||
|
/// The amount of extra connections we can make if we are under load from the rest of Cuprate.
|
||||||
|
pub extra_outbound_connections: usize,
|
||||||
|
/// The maximum amount of inbound connections
|
||||||
|
pub max_inbound_connections: usize,
|
||||||
|
/// The percent of connections that should be to peers we haven't connected to before.
|
||||||
|
pub gray_peers_percent: f64,
|
||||||
|
/// port to use to accept p2p connections.
|
||||||
|
pub p2p_port: u16,
|
||||||
|
/// The address book config.
|
||||||
|
address_book_config: AddressBookConfig,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SharedNetConfig {
|
||||||
|
/// Returns the [`AddressBookConfig`].
|
||||||
|
pub fn address_book_config(
|
||||||
|
&self,
|
||||||
|
cache_dir: &Path,
|
||||||
|
network: Network,
|
||||||
|
) -> cuprate_address_book::AddressBookConfig {
|
||||||
|
cuprate_address_book::AddressBookConfig {
|
||||||
|
max_white_list_length: self.address_book_config.max_white_list_length,
|
||||||
|
max_gray_list_length: self.address_book_config.max_gray_list_length,
|
||||||
|
peer_store_directory: addressbook_path(cache_dir, network),
|
||||||
|
peer_save_period: self.address_book_config.peer_save_period,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for SharedNetConfig {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
outbound_connections: 64,
|
||||||
|
extra_outbound_connections: 8,
|
||||||
|
max_inbound_connections: 128,
|
||||||
|
gray_peers_percent: 0.7,
|
||||||
|
p2p_port: 0,
|
||||||
|
address_book_config: AddressBookConfig::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Serialize)]
|
||||||
|
#[serde(deny_unknown_fields, default)]
|
||||||
|
pub struct AddressBookConfig {
|
||||||
|
max_white_list_length: usize,
|
||||||
|
max_gray_list_length: usize,
|
||||||
|
peer_save_period: Duration,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for AddressBookConfig {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
max_white_list_length: 1_000,
|
||||||
|
max_gray_list_length: 5_000,
|
||||||
|
peer_save_period: Duration::from_secs(30),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Seed nodes for [`ClearNet`](cuprate_p2p_core::ClearNet).
|
||||||
|
pub fn clear_net_seed_nodes(network: Network) -> Vec<SocketAddr> {
|
||||||
|
let seeds = match network {
|
||||||
|
Network::Mainnet => [
|
||||||
|
"176.9.0.187:18080",
|
||||||
|
"88.198.163.90:18080",
|
||||||
|
"66.85.74.134:18080",
|
||||||
|
"51.79.173.165:18080",
|
||||||
|
"192.99.8.110:18080",
|
||||||
|
"37.187.74.171:18080",
|
||||||
|
"77.172.183.193:18080",
|
||||||
|
]
|
||||||
|
.as_slice(),
|
||||||
|
Network::Stagenet => [
|
||||||
|
"176.9.0.187:38080",
|
||||||
|
"51.79.173.165:38080",
|
||||||
|
"192.99.8.110:38080",
|
||||||
|
"37.187.74.171:38080",
|
||||||
|
"77.172.183.193:38080",
|
||||||
|
]
|
||||||
|
.as_slice(),
|
||||||
|
Network::Testnet => [
|
||||||
|
"176.9.0.187:28080",
|
||||||
|
"51.79.173.165:28080",
|
||||||
|
"192.99.8.110:28080",
|
||||||
|
"37.187.74.171:28080",
|
||||||
|
"77.172.183.193:28080",
|
||||||
|
]
|
||||||
|
.as_slice(),
|
||||||
|
};
|
||||||
|
|
||||||
|
seeds
|
||||||
|
.iter()
|
||||||
|
.map(|s| s.parse())
|
||||||
|
.collect::<Result<_, _>>()
|
||||||
|
.unwrap()
|
||||||
|
}
|
67
binaries/cuprated/src/config/storage.rs
Normal file
67
binaries/cuprated/src/config/storage.rs
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
use cuprate_database::config::SyncMode;
|
||||||
|
use cuprate_database_service::ReaderThreads;
|
||||||
|
use cuprate_helper::fs::CUPRATE_DATA_DIR;
|
||||||
|
|
||||||
|
/// The storage config.
|
||||||
|
#[derive(Default, Deserialize, Serialize)]
|
||||||
|
#[serde(deny_unknown_fields, default)]
|
||||||
|
pub struct StorageConfig {
|
||||||
|
/// The amount of reader threads to spawn between the tx-pool and blockchain.
|
||||||
|
pub reader_threads: ReaderThreads,
|
||||||
|
/// The tx-pool config.
|
||||||
|
pub txpool: TxpoolConfig,
|
||||||
|
/// The blockchain config.
|
||||||
|
pub blockchain: BlockchainConfig,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The blockchain config.
|
||||||
|
#[derive(Deserialize, Serialize)]
|
||||||
|
#[serde(deny_unknown_fields, default)]
|
||||||
|
pub struct BlockchainConfig {
|
||||||
|
#[serde(flatten)]
|
||||||
|
pub shared: SharedStorageConfig,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for BlockchainConfig {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
shared: SharedStorageConfig {
|
||||||
|
sync_mode: SyncMode::Async,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The tx-pool config.
|
||||||
|
#[derive(Deserialize, Serialize)]
|
||||||
|
#[serde(deny_unknown_fields, default)]
|
||||||
|
pub struct TxpoolConfig {
|
||||||
|
#[serde(flatten)]
|
||||||
|
pub shared: SharedStorageConfig,
|
||||||
|
|
||||||
|
/// The maximum size of the tx-pool.
|
||||||
|
pub max_txpool_byte_size: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for TxpoolConfig {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
shared: SharedStorageConfig {
|
||||||
|
sync_mode: SyncMode::Async,
|
||||||
|
},
|
||||||
|
max_txpool_byte_size: 100_000_000,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Config values shared between the tx-pool and blockchain.
|
||||||
|
#[derive(Default, Deserialize, Serialize)]
|
||||||
|
#[serde(deny_unknown_fields, default)]
|
||||||
|
pub struct SharedStorageConfig {
|
||||||
|
/// The [`SyncMode`] of the database.
|
||||||
|
pub sync_mode: SyncMode,
|
||||||
|
}
|
42
binaries/cuprated/src/config/tracing_config.rs
Normal file
42
binaries/cuprated/src/config/tracing_config.rs
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use tracing::level_filters::LevelFilter;
|
||||||
|
|
||||||
|
/// [`tracing`] config.
|
||||||
|
#[derive(Deserialize, Serialize)]
|
||||||
|
#[serde(deny_unknown_fields, default)]
|
||||||
|
pub struct TracingConfig {
|
||||||
|
/// The default minimum log level.
|
||||||
|
#[serde(with = "level_filter_serde")]
|
||||||
|
level: LevelFilter,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for TracingConfig {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
level: LevelFilter::INFO,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mod level_filter_serde {
|
||||||
|
use std::str::FromStr;
|
||||||
|
|
||||||
|
use serde::{Deserialize, Deserializer, Serializer};
|
||||||
|
use tracing::level_filters::LevelFilter;
|
||||||
|
|
||||||
|
#[expect(clippy::trivially_copy_pass_by_ref, reason = "serde")]
|
||||||
|
pub fn serialize<S>(level_filter: &LevelFilter, s: S) -> Result<S::Ok, S::Error>
|
||||||
|
where
|
||||||
|
S: Serializer,
|
||||||
|
{
|
||||||
|
s.serialize_str(&level_filter.to_string())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn deserialize<'de, D>(d: D) -> Result<LevelFilter, D::Error>
|
||||||
|
where
|
||||||
|
D: Deserializer<'de>,
|
||||||
|
{
|
||||||
|
let s = String::deserialize(d)?;
|
||||||
|
LevelFilter::from_str(&s).map_err(serde::de::Error::custom)
|
||||||
|
}
|
||||||
|
}
|
|
@ -18,6 +18,8 @@ pub const VERSION_BUILD: &str = if cfg!(debug_assertions) {
|
||||||
pub const PANIC_CRITICAL_SERVICE_ERROR: &str =
|
pub const PANIC_CRITICAL_SERVICE_ERROR: &str =
|
||||||
"A service critical to Cuprate's function returned an unexpected error.";
|
"A service critical to Cuprate's function returned an unexpected error.";
|
||||||
|
|
||||||
|
pub const EXAMPLE_CONFIG: &str = include_str!("../../../Cuprated.toml");
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
|
@ -29,6 +29,8 @@ fn main() {
|
||||||
// Initialize global static `LazyLock` data.
|
// Initialize global static `LazyLock` data.
|
||||||
statics::init_lazylock_statics();
|
statics::init_lazylock_statics();
|
||||||
|
|
||||||
|
let _config = config::read_config_and_args();
|
||||||
|
|
||||||
// TODO: everything else.
|
// TODO: everything else.
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,6 +35,8 @@ futures = { workspace = true, optional = true, features = ["std"] }
|
||||||
monero-serai = { workspace = true, optional = true }
|
monero-serai = { workspace = true, optional = true }
|
||||||
rayon = { workspace = true, optional = true }
|
rayon = { workspace = true, optional = true }
|
||||||
|
|
||||||
|
serde = { workspace = true, optional = true, features = ["derive"] }
|
||||||
|
|
||||||
# This is kinda a stupid work around.
|
# This is kinda a stupid work around.
|
||||||
# [thread] needs to activate one of these libs (windows|libc)
|
# [thread] needs to activate one of these libs (windows|libc)
|
||||||
# although it depends on what target we're building for.
|
# although it depends on what target we're building for.
|
||||||
|
|
|
@ -28,7 +28,12 @@
|
||||||
//! - <https://docs.rs/dirs>
|
//! - <https://docs.rs/dirs>
|
||||||
|
|
||||||
//---------------------------------------------------------------------------------------------------- Use
|
//---------------------------------------------------------------------------------------------------- Use
|
||||||
use std::{path::PathBuf, sync::LazyLock};
|
use std::{
|
||||||
|
path::{Path, PathBuf},
|
||||||
|
sync::LazyLock,
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::network::Network;
|
||||||
|
|
||||||
//---------------------------------------------------------------------------------------------------- Const
|
//---------------------------------------------------------------------------------------------------- Const
|
||||||
/// Cuprate's main directory.
|
/// Cuprate's main directory.
|
||||||
|
@ -58,6 +63,9 @@ pub const CUPRATE_DIR: &str = {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// The default name of Cuprate's config file.
|
||||||
|
pub const DEFAULT_CONFIG_FILE_NAME: &str = "Cuprated.toml";
|
||||||
|
|
||||||
//---------------------------------------------------------------------------------------------------- Directories
|
//---------------------------------------------------------------------------------------------------- Directories
|
||||||
/// Create a `LazyLock` for common PATHs used by Cuprate.
|
/// Create a `LazyLock` for common PATHs used by Cuprate.
|
||||||
///
|
///
|
||||||
|
@ -150,32 +158,61 @@ impl_path_lazylock! {
|
||||||
CUPRATE_DATA_DIR,
|
CUPRATE_DATA_DIR,
|
||||||
data_dir,
|
data_dir,
|
||||||
"",
|
"",
|
||||||
|
}
|
||||||
|
|
||||||
/// Cuprate's blockchain directory.
|
/// Joins the [`Network`] to the [`Path`].
|
||||||
///
|
///
|
||||||
/// This is the PATH used for any Cuprate blockchain files.
|
/// This will keep the path the same for [`Network::Mainnet`].
|
||||||
///
|
fn path_with_network(path: &Path, network: Network) -> PathBuf {
|
||||||
/// | OS | PATH |
|
match network {
|
||||||
/// |---------|----------------------------------------------------------------|
|
Network::Mainnet => path.to_path_buf(),
|
||||||
/// | Windows | `C:\Users\Alice\AppData\Roaming\Cuprate\blockchain\` |
|
network => path.join(network.to_string()),
|
||||||
/// | macOS | `/Users/Alice/Library/Application Support/Cuprate/blockchain/` |
|
}
|
||||||
/// | Linux | `/home/alice/.local/share/cuprate/blockchain/` |
|
}
|
||||||
CUPRATE_BLOCKCHAIN_DIR,
|
|
||||||
data_dir,
|
|
||||||
"blockchain",
|
|
||||||
|
|
||||||
/// Cuprate's transaction pool directory.
|
/// Cuprate's blockchain directory.
|
||||||
///
|
///
|
||||||
/// This is the PATH used for any Cuprate txpool files.
|
/// This is the PATH used for any Cuprate blockchain files.
|
||||||
///
|
///
|
||||||
/// | OS | PATH |
|
/// ```rust
|
||||||
/// |---------|------------------------------------------------------------|
|
/// use cuprate_helper::{network::Network, fs::{CUPRATE_DATA_DIR, blockchain_path}};
|
||||||
/// | Windows | `C:\Users\Alice\AppData\Roaming\Cuprate\txpool\` |
|
///
|
||||||
/// | macOS | `/Users/Alice/Library/Application Support/Cuprate/txpool/` |
|
/// assert_eq!(blockchain_path(&**CUPRATE_DATA_DIR, Network::Mainnet).as_path(), CUPRATE_DATA_DIR.join("blockchain"));
|
||||||
/// | Linux | `/home/alice/.local/share/cuprate/txpool/` |
|
/// assert_eq!(blockchain_path(&**CUPRATE_DATA_DIR, Network::Stagenet).as_path(), CUPRATE_DATA_DIR.join(Network::Stagenet.to_string()).join("blockchain"));
|
||||||
CUPRATE_TXPOOL_DIR,
|
/// assert_eq!(blockchain_path(&**CUPRATE_DATA_DIR, Network::Testnet).as_path(), CUPRATE_DATA_DIR.join(Network::Testnet.to_string()).join("blockchain"));
|
||||||
data_dir,
|
/// ```
|
||||||
"txpool",
|
pub fn blockchain_path(data_dir: &Path, network: Network) -> PathBuf {
|
||||||
|
path_with_network(data_dir, network).join("blockchain")
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Cuprate's txpool directory.
|
||||||
|
///
|
||||||
|
/// This is the PATH used for any Cuprate txpool files.
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// use cuprate_helper::{network::Network, fs::{CUPRATE_DATA_DIR, txpool_path}};
|
||||||
|
///
|
||||||
|
/// assert_eq!(txpool_path(&**CUPRATE_DATA_DIR, Network::Mainnet).as_path(), CUPRATE_DATA_DIR.join("txpool"));
|
||||||
|
/// assert_eq!(txpool_path(&**CUPRATE_DATA_DIR, Network::Stagenet).as_path(), CUPRATE_DATA_DIR.join(Network::Stagenet.to_string()).join("txpool"));
|
||||||
|
/// assert_eq!(txpool_path(&**CUPRATE_DATA_DIR, Network::Testnet).as_path(), CUPRATE_DATA_DIR.join(Network::Testnet.to_string()).join("txpool"));
|
||||||
|
/// ```
|
||||||
|
pub fn txpool_path(data_dir: &Path, network: Network) -> PathBuf {
|
||||||
|
path_with_network(data_dir, network).join("txpool")
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Cuprate's address-book directory.
|
||||||
|
///
|
||||||
|
/// This is the PATH used for any Cuprate address-book files.
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// use cuprate_helper::{network::Network, fs::{CUPRATE_CACHE_DIR, addressbook_path}};
|
||||||
|
///
|
||||||
|
/// assert_eq!(addressbook_path(&**CUPRATE_CACHE_DIR, Network::Mainnet).as_path(), CUPRATE_CACHE_DIR.join("addressbook"));
|
||||||
|
/// assert_eq!(addressbook_path(&**CUPRATE_CACHE_DIR, Network::Stagenet).as_path(), CUPRATE_CACHE_DIR.join(Network::Stagenet.to_string()).join("addressbook"));
|
||||||
|
/// assert_eq!(addressbook_path(&**CUPRATE_CACHE_DIR, Network::Testnet).as_path(), CUPRATE_CACHE_DIR.join(Network::Testnet.to_string()).join("addressbook"));
|
||||||
|
/// ```
|
||||||
|
pub fn addressbook_path(cache_dir: &Path, network: Network) -> PathBuf {
|
||||||
|
path_with_network(cache_dir, network).join("addressbook")
|
||||||
}
|
}
|
||||||
|
|
||||||
//---------------------------------------------------------------------------------------------------- Tests
|
//---------------------------------------------------------------------------------------------------- Tests
|
||||||
|
@ -197,29 +234,21 @@ mod test {
|
||||||
(&*CUPRATE_CACHE_DIR, ""),
|
(&*CUPRATE_CACHE_DIR, ""),
|
||||||
(&*CUPRATE_CONFIG_DIR, ""),
|
(&*CUPRATE_CONFIG_DIR, ""),
|
||||||
(&*CUPRATE_DATA_DIR, ""),
|
(&*CUPRATE_DATA_DIR, ""),
|
||||||
(&*CUPRATE_BLOCKCHAIN_DIR, ""),
|
|
||||||
(&*CUPRATE_TXPOOL_DIR, ""),
|
|
||||||
];
|
];
|
||||||
|
|
||||||
if cfg!(target_os = "windows") {
|
if cfg!(target_os = "windows") {
|
||||||
array[0].1 = r"AppData\Local\Cuprate";
|
array[0].1 = r"AppData\Local\Cuprate";
|
||||||
array[1].1 = r"AppData\Roaming\Cuprate";
|
array[1].1 = r"AppData\Roaming\Cuprate";
|
||||||
array[2].1 = r"AppData\Roaming\Cuprate";
|
array[2].1 = r"AppData\Roaming\Cuprate";
|
||||||
array[3].1 = r"AppData\Roaming\Cuprate\blockchain";
|
|
||||||
array[4].1 = r"AppData\Roaming\Cuprate\txpool";
|
|
||||||
} else if cfg!(target_os = "macos") {
|
} else if cfg!(target_os = "macos") {
|
||||||
array[0].1 = "Library/Caches/Cuprate";
|
array[0].1 = "Library/Caches/Cuprate";
|
||||||
array[1].1 = "Library/Application Support/Cuprate";
|
array[1].1 = "Library/Application Support/Cuprate";
|
||||||
array[2].1 = "Library/Application Support/Cuprate";
|
array[2].1 = "Library/Application Support/Cuprate";
|
||||||
array[3].1 = "Library/Application Support/Cuprate/blockchain";
|
|
||||||
array[4].1 = "Library/Application Support/Cuprate/txpool";
|
|
||||||
} else {
|
} else {
|
||||||
// Assumes Linux.
|
// Assumes Linux.
|
||||||
array[0].1 = ".cache/cuprate";
|
array[0].1 = ".cache/cuprate";
|
||||||
array[1].1 = ".config/cuprate";
|
array[1].1 = ".config/cuprate";
|
||||||
array[2].1 = ".local/share/cuprate";
|
array[2].1 = ".local/share/cuprate";
|
||||||
array[3].1 = ".local/share/cuprate/blockchain";
|
|
||||||
array[4].1 = ".local/share/cuprate/txpool";
|
|
||||||
};
|
};
|
||||||
|
|
||||||
for (path, expected) in array {
|
for (path, expected) in array {
|
||||||
|
|
|
@ -5,6 +5,12 @@
|
||||||
//! into it's own crate.
|
//! into it's own crate.
|
||||||
//!
|
//!
|
||||||
//! `#[no_std]` compatible.
|
//! `#[no_std]` compatible.
|
||||||
|
// TODO: move to types crate.
|
||||||
|
|
||||||
|
use core::{
|
||||||
|
fmt::{Display, Formatter},
|
||||||
|
str::FromStr,
|
||||||
|
};
|
||||||
|
|
||||||
const MAINNET_NETWORK_ID: [u8; 16] = [
|
const MAINNET_NETWORK_ID: [u8; 16] = [
|
||||||
0x12, 0x30, 0xF1, 0x71, 0x61, 0x04, 0x41, 0x61, 0x17, 0x31, 0x00, 0x82, 0x16, 0xA1, 0xA1, 0x10,
|
0x12, 0x30, 0xF1, 0x71, 0x61, 0x04, 0x41, 0x61, 0x17, 0x31, 0x00, 0x82, 0x16, 0xA1, 0xA1, 0x10,
|
||||||
|
@ -17,7 +23,8 @@ const STAGENET_NETWORK_ID: [u8; 16] = [
|
||||||
];
|
];
|
||||||
|
|
||||||
/// An enum representing every Monero network.
|
/// An enum representing every Monero network.
|
||||||
#[derive(Debug, Clone, Copy, Default)]
|
#[derive(Debug, Clone, Copy, Default, Ord, PartialOrd, Eq, PartialEq)]
|
||||||
|
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
|
||||||
pub enum Network {
|
pub enum Network {
|
||||||
/// Mainnet
|
/// Mainnet
|
||||||
#[default]
|
#[default]
|
||||||
|
@ -38,3 +45,28 @@ impl Network {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
|
pub struct ParseNetworkError;
|
||||||
|
|
||||||
|
impl FromStr for Network {
|
||||||
|
type Err = ParseNetworkError;
|
||||||
|
|
||||||
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
|
match s {
|
||||||
|
"mainnet" | "Mainnet" => Ok(Self::Mainnet),
|
||||||
|
"testnet" | "Testnet" => Ok(Self::Testnet),
|
||||||
|
"stagenet" | "Stagenet" => Ok(Self::Stagenet),
|
||||||
|
_ => Err(ParseNetworkError),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl Display for Network {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
|
||||||
|
f.write_str(match self {
|
||||||
|
Self::Mainnet => "mainnet",
|
||||||
|
Self::Testnet => "testnet",
|
||||||
|
Self::Stagenet => "stagenet",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -23,7 +23,7 @@ indexmap = { workspace = true, features = ["std"] }
|
||||||
|
|
||||||
rand = { workspace = true, features = ["std", "std_rng"] }
|
rand = { workspace = true, features = ["std", "std_rng"] }
|
||||||
|
|
||||||
borsh = { workspace = true, features = ["derive", "std"]}
|
borsh = { workspace = true, features = ["derive", "std"] }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
cuprate-test-utils = { workspace = true }
|
cuprate-test-utils = { workspace = true }
|
||||||
|
|
|
@ -15,7 +15,7 @@ fn test_cfg() -> AddressBookConfig {
|
||||||
AddressBookConfig {
|
AddressBookConfig {
|
||||||
max_white_list_length: 100,
|
max_white_list_length: 100,
|
||||||
max_gray_list_length: 500,
|
max_gray_list_length: 500,
|
||||||
peer_store_file: PathBuf::new(),
|
peer_store_directory: PathBuf::new(),
|
||||||
peer_save_period: Duration::from_secs(60),
|
peer_save_period: Duration::from_secs(60),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,8 +29,8 @@ pub struct AddressBookConfig {
|
||||||
///
|
///
|
||||||
/// Gray peers are peers we are yet to make a connection to.
|
/// Gray peers are peers we are yet to make a connection to.
|
||||||
pub max_gray_list_length: usize,
|
pub max_gray_list_length: usize,
|
||||||
/// The location to store the address book.
|
/// The location to store the peer store files.
|
||||||
pub peer_store_file: PathBuf,
|
pub peer_store_directory: PathBuf,
|
||||||
/// The amount of time between saving the address book to disk.
|
/// The amount of time between saving the address book to disk.
|
||||||
pub peer_save_period: Duration,
|
pub peer_save_period: Duration,
|
||||||
}
|
}
|
||||||
|
@ -63,11 +63,6 @@ pub enum AddressBookError {
|
||||||
pub async fn init_address_book<Z: BorshNetworkZone>(
|
pub async fn init_address_book<Z: BorshNetworkZone>(
|
||||||
cfg: AddressBookConfig,
|
cfg: AddressBookConfig,
|
||||||
) -> Result<book::AddressBook<Z>, std::io::Error> {
|
) -> Result<book::AddressBook<Z>, std::io::Error> {
|
||||||
tracing::info!(
|
|
||||||
"Loading peers from file: {} ",
|
|
||||||
cfg.peer_store_file.display()
|
|
||||||
);
|
|
||||||
|
|
||||||
let (white_list, gray_list) = match store::read_peers_from_disk::<Z>(&cfg).await {
|
let (white_list, gray_list) = match store::read_peers_from_disk::<Z>(&cfg).await {
|
||||||
Ok(res) => res,
|
Ok(res) => res,
|
||||||
Err(e) if e.kind() == ErrorKind::NotFound => (vec![], vec![]),
|
Err(e) if e.kind() == ErrorKind::NotFound => (vec![], vec![]),
|
||||||
|
|
|
@ -39,7 +39,9 @@ pub(crate) fn save_peers_to_disk<Z: BorshNetworkZone>(
|
||||||
})
|
})
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let file = cfg.peer_store_file.clone();
|
let file = cfg
|
||||||
|
.peer_store_directory
|
||||||
|
.join(format!("{}_p2p_state", Z::NAME));
|
||||||
spawn_blocking(move || fs::write(&file, &data))
|
spawn_blocking(move || fs::write(&file, &data))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -52,7 +54,12 @@ pub(crate) async fn read_peers_from_disk<Z: BorshNetworkZone>(
|
||||||
),
|
),
|
||||||
std::io::Error,
|
std::io::Error,
|
||||||
> {
|
> {
|
||||||
let file = cfg.peer_store_file.clone();
|
let file = cfg
|
||||||
|
.peer_store_directory
|
||||||
|
.join(format!("{}_p2p_state", Z::NAME));
|
||||||
|
|
||||||
|
tracing::info!("Loading peers from file: {} ", file.display());
|
||||||
|
|
||||||
let data = spawn_blocking(move || fs::read(file)).await.unwrap()?;
|
let data = spawn_blocking(move || fs::read(file)).await.unwrap()?;
|
||||||
|
|
||||||
let de_ser: DeserPeerDataV1<Z::Addr> = from_slice(&data)?;
|
let de_ser: DeserPeerDataV1<Z::Addr> = from_slice(&data)?;
|
||||||
|
|
|
@ -70,7 +70,7 @@ pub struct BlockDownloaderConfig {
|
||||||
/// The target size of a single batch of blocks (in bytes).
|
/// The target size of a single batch of blocks (in bytes).
|
||||||
pub target_batch_size: usize,
|
pub target_batch_size: usize,
|
||||||
/// The initial amount of blocks to request (in number of blocks)
|
/// The initial amount of blocks to request (in number of blocks)
|
||||||
pub initial_batch_size: usize,
|
pub initial_batch_len: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An error that occurred in the [`BlockDownloader`].
|
/// An error that occurred in the [`BlockDownloader`].
|
||||||
|
@ -243,7 +243,7 @@ where
|
||||||
Self {
|
Self {
|
||||||
client_pool,
|
client_pool,
|
||||||
our_chain_svc,
|
our_chain_svc,
|
||||||
amount_of_blocks_to_request: config.initial_batch_size,
|
amount_of_blocks_to_request: config.initial_batch_len,
|
||||||
amount_of_blocks_to_request_updated_at: 0,
|
amount_of_blocks_to_request_updated_at: 0,
|
||||||
amount_of_empty_chain_entries: 0,
|
amount_of_empty_chain_entries: 0,
|
||||||
block_download_tasks: JoinSet::new(),
|
block_download_tasks: JoinSet::new(),
|
||||||
|
|
|
@ -69,7 +69,7 @@ proptest! {
|
||||||
in_progress_queue_size: 10_000,
|
in_progress_queue_size: 10_000,
|
||||||
check_client_pool_interval: Duration::from_secs(5),
|
check_client_pool_interval: Duration::from_secs(5),
|
||||||
target_batch_size: 5_000,
|
target_batch_size: 5_000,
|
||||||
initial_batch_size: 1,
|
initial_batch_len: 1,
|
||||||
});
|
});
|
||||||
|
|
||||||
let blocks = stream.map(|blocks| blocks.blocks).concat().await;
|
let blocks = stream.map(|blocks| blocks.blocks).concat().await;
|
||||||
|
|
|
@ -15,7 +15,7 @@ default = ["heed"]
|
||||||
heed = ["cuprate-database/heed"]
|
heed = ["cuprate-database/heed"]
|
||||||
redb = ["cuprate-database/redb"]
|
redb = ["cuprate-database/redb"]
|
||||||
redb-memory = ["cuprate-database/redb-memory"]
|
redb-memory = ["cuprate-database/redb-memory"]
|
||||||
serde = ["dep:serde", "cuprate-database/serde", "cuprate-database-service/serde"]
|
serde = ["dep:serde", "cuprate-database/serde", "cuprate-database-service/serde", "cuprate-helper/serde"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
cuprate-database = { workspace = true }
|
cuprate-database = { workspace = true }
|
||||||
|
|
|
@ -76,7 +76,7 @@ use cuprate_blockchain::{
|
||||||
let tmp_dir = tempfile::tempdir()?;
|
let tmp_dir = tempfile::tempdir()?;
|
||||||
let db_dir = tmp_dir.path().to_owned();
|
let db_dir = tmp_dir.path().to_owned();
|
||||||
let config = ConfigBuilder::new()
|
let config = ConfigBuilder::new()
|
||||||
.db_directory(db_dir.into())
|
.data_directory(db_dir.into())
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
// Initialize the database environment.
|
// Initialize the database environment.
|
||||||
|
|
|
@ -25,7 +25,7 @@
|
||||||
//!
|
//!
|
||||||
//! let config = ConfigBuilder::new()
|
//! let config = ConfigBuilder::new()
|
||||||
//! // Use a custom database directory.
|
//! // Use a custom database directory.
|
||||||
//! .db_directory(db_dir.into())
|
//! .data_directory(db_dir.into())
|
||||||
//! // Use as many reader threads as possible (when using `service`).
|
//! // Use as many reader threads as possible (when using `service`).
|
||||||
//! .reader_threads(ReaderThreads::OnePerThread)
|
//! .reader_threads(ReaderThreads::OnePerThread)
|
||||||
//! // Use the fastest sync mode.
|
//! // Use the fastest sync mode.
|
||||||
|
@ -41,13 +41,16 @@
|
||||||
//! ```
|
//! ```
|
||||||
|
|
||||||
//---------------------------------------------------------------------------------------------------- Import
|
//---------------------------------------------------------------------------------------------------- Import
|
||||||
use std::{borrow::Cow, path::Path};
|
use std::{borrow::Cow, path::PathBuf};
|
||||||
|
|
||||||
#[cfg(feature = "serde")]
|
#[cfg(feature = "serde")]
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use cuprate_database::{config::SyncMode, resize::ResizeAlgorithm};
|
use cuprate_database::{config::SyncMode, resize::ResizeAlgorithm};
|
||||||
use cuprate_helper::fs::CUPRATE_BLOCKCHAIN_DIR;
|
use cuprate_helper::{
|
||||||
|
fs::{blockchain_path, CUPRATE_DATA_DIR},
|
||||||
|
network::Network,
|
||||||
|
};
|
||||||
|
|
||||||
// re-exports
|
// re-exports
|
||||||
pub use cuprate_database_service::ReaderThreads;
|
pub use cuprate_database_service::ReaderThreads;
|
||||||
|
@ -59,8 +62,9 @@ pub use cuprate_database_service::ReaderThreads;
|
||||||
#[derive(Debug, Clone, PartialEq, PartialOrd)]
|
#[derive(Debug, Clone, PartialEq, PartialOrd)]
|
||||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||||
pub struct ConfigBuilder {
|
pub struct ConfigBuilder {
|
||||||
/// [`Config::db_directory`].
|
network: Network,
|
||||||
db_directory: Option<Cow<'static, Path>>,
|
|
||||||
|
data_dir: Option<PathBuf>,
|
||||||
|
|
||||||
/// [`Config::cuprate_database_config`].
|
/// [`Config::cuprate_database_config`].
|
||||||
db_config: cuprate_database::config::ConfigBuilder,
|
db_config: cuprate_database::config::ConfigBuilder,
|
||||||
|
@ -76,10 +80,12 @@ impl ConfigBuilder {
|
||||||
/// after this function to use default values.
|
/// after this function to use default values.
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
db_directory: None,
|
network: Network::default(),
|
||||||
db_config: cuprate_database::config::ConfigBuilder::new(Cow::Borrowed(
|
data_dir: None,
|
||||||
&*CUPRATE_BLOCKCHAIN_DIR,
|
db_config: cuprate_database::config::ConfigBuilder::new(Cow::Owned(blockchain_path(
|
||||||
)),
|
&CUPRATE_DATA_DIR,
|
||||||
|
Network::Mainnet,
|
||||||
|
))),
|
||||||
reader_threads: None,
|
reader_threads: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -87,21 +93,21 @@ impl ConfigBuilder {
|
||||||
/// Build into a [`Config`].
|
/// Build into a [`Config`].
|
||||||
///
|
///
|
||||||
/// # Default values
|
/// # Default values
|
||||||
/// If [`ConfigBuilder::db_directory`] was not called,
|
/// If [`ConfigBuilder::data_directory`] was not called,
|
||||||
/// the default [`CUPRATE_BLOCKCHAIN_DIR`] will be used.
|
/// [`blockchain_path`] with [`CUPRATE_DATA_DIR`] [`Network::Mainnet`] will be used.
|
||||||
///
|
///
|
||||||
/// For all other values, [`Default::default`] is used.
|
/// For all other values, [`Default::default`] is used.
|
||||||
pub fn build(self) -> Config {
|
pub fn build(self) -> Config {
|
||||||
// INVARIANT: all PATH safety checks are done
|
// INVARIANT: all PATH safety checks are done
|
||||||
// in `helper::fs`. No need to do them here.
|
// in `helper::fs`. No need to do them here.
|
||||||
let db_directory = self
|
let data_dir = self
|
||||||
.db_directory
|
.data_dir
|
||||||
.unwrap_or_else(|| Cow::Borrowed(&*CUPRATE_BLOCKCHAIN_DIR));
|
.unwrap_or_else(|| CUPRATE_DATA_DIR.to_path_buf());
|
||||||
|
|
||||||
let reader_threads = self.reader_threads.unwrap_or_default();
|
let reader_threads = self.reader_threads.unwrap_or_default();
|
||||||
let db_config = self
|
let db_config = self
|
||||||
.db_config
|
.db_config
|
||||||
.db_directory(db_directory)
|
.db_directory(Cow::Owned(blockchain_path(&data_dir, self.network)))
|
||||||
.reader_threads(reader_threads.as_threads())
|
.reader_threads(reader_threads.as_threads())
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
|
@ -111,10 +117,17 @@ impl ConfigBuilder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set a custom database directory (and file) [`Path`].
|
/// Change the network this blockchain database is for.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn db_directory(mut self, db_directory: Cow<'static, Path>) -> Self {
|
pub const fn network(mut self, network: Network) -> Self {
|
||||||
self.db_directory = Some(db_directory);
|
self.network = network;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set a custom database directory (and file) [`PathBuf`].
|
||||||
|
#[must_use]
|
||||||
|
pub fn data_directory(mut self, db_directory: PathBuf) -> Self {
|
||||||
|
self.data_dir = Some(db_directory);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -145,9 +158,7 @@ impl ConfigBuilder {
|
||||||
/// Good default for testing, and resource-available machines.
|
/// Good default for testing, and resource-available machines.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn fast(mut self) -> Self {
|
pub fn fast(mut self) -> Self {
|
||||||
self.db_config =
|
self.db_config = self.db_config.fast();
|
||||||
cuprate_database::config::ConfigBuilder::new(Cow::Borrowed(&*CUPRATE_BLOCKCHAIN_DIR))
|
|
||||||
.fast();
|
|
||||||
|
|
||||||
self.reader_threads = Some(ReaderThreads::OnePerThread);
|
self.reader_threads = Some(ReaderThreads::OnePerThread);
|
||||||
self
|
self
|
||||||
|
@ -159,9 +170,7 @@ impl ConfigBuilder {
|
||||||
/// Good default for resource-limited machines, e.g. a cheap VPS.
|
/// Good default for resource-limited machines, e.g. a cheap VPS.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn low_power(mut self) -> Self {
|
pub fn low_power(mut self) -> Self {
|
||||||
self.db_config =
|
self.db_config = self.db_config.low_power();
|
||||||
cuprate_database::config::ConfigBuilder::new(Cow::Borrowed(&*CUPRATE_BLOCKCHAIN_DIR))
|
|
||||||
.low_power();
|
|
||||||
|
|
||||||
self.reader_threads = Some(ReaderThreads::One);
|
self.reader_threads = Some(ReaderThreads::One);
|
||||||
self
|
self
|
||||||
|
@ -170,10 +179,13 @@ impl ConfigBuilder {
|
||||||
|
|
||||||
impl Default for ConfigBuilder {
|
impl Default for ConfigBuilder {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
let db_directory = Cow::Borrowed(&**CUPRATE_BLOCKCHAIN_DIR);
|
|
||||||
Self {
|
Self {
|
||||||
db_directory: Some(db_directory.clone()),
|
network: Network::default(),
|
||||||
db_config: cuprate_database::config::ConfigBuilder::new(db_directory),
|
data_dir: Some(CUPRATE_DATA_DIR.to_path_buf()),
|
||||||
|
db_config: cuprate_database::config::ConfigBuilder::new(Cow::Owned(blockchain_path(
|
||||||
|
&CUPRATE_DATA_DIR,
|
||||||
|
Network::default(),
|
||||||
|
))),
|
||||||
reader_threads: Some(ReaderThreads::default()),
|
reader_threads: Some(ReaderThreads::default()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -201,7 +213,7 @@ impl Config {
|
||||||
/// Create a new [`Config`] with sane default settings.
|
/// Create a new [`Config`] with sane default settings.
|
||||||
///
|
///
|
||||||
/// The [`cuprate_database::config::Config::db_directory`]
|
/// The [`cuprate_database::config::Config::db_directory`]
|
||||||
/// will be set to [`CUPRATE_BLOCKCHAIN_DIR`].
|
/// will be set to [`blockchain_path`] with [`CUPRATE_DATA_DIR`] [`Network::Mainnet`].
|
||||||
///
|
///
|
||||||
/// All other values will be [`Default::default`].
|
/// All other values will be [`Default::default`].
|
||||||
///
|
///
|
||||||
|
@ -213,14 +225,14 @@ impl Config {
|
||||||
/// resize::ResizeAlgorithm,
|
/// resize::ResizeAlgorithm,
|
||||||
/// DATABASE_DATA_FILENAME,
|
/// DATABASE_DATA_FILENAME,
|
||||||
/// };
|
/// };
|
||||||
/// use cuprate_helper::fs::*;
|
/// use cuprate_helper::{fs::*, network::Network};
|
||||||
///
|
///
|
||||||
/// use cuprate_blockchain::config::*;
|
/// use cuprate_blockchain::config::*;
|
||||||
///
|
///
|
||||||
/// let config = Config::new();
|
/// let config = Config::new();
|
||||||
///
|
///
|
||||||
/// assert_eq!(config.db_config.db_directory(), &*CUPRATE_BLOCKCHAIN_DIR);
|
/// assert_eq!(config.db_config.db_directory().as_ref(), blockchain_path(&CUPRATE_DATA_DIR, Network::Mainnet).as_path());
|
||||||
/// assert!(config.db_config.db_file().starts_with(&*CUPRATE_BLOCKCHAIN_DIR));
|
/// assert!(config.db_config.db_file().starts_with(&*CUPRATE_DATA_DIR));
|
||||||
/// assert!(config.db_config.db_file().ends_with(DATABASE_DATA_FILENAME));
|
/// assert!(config.db_config.db_file().ends_with(DATABASE_DATA_FILENAME));
|
||||||
/// assert_eq!(config.db_config.sync_mode, SyncMode::default());
|
/// assert_eq!(config.db_config.sync_mode, SyncMode::default());
|
||||||
/// assert_eq!(config.db_config.resize_algorithm, ResizeAlgorithm::default());
|
/// assert_eq!(config.db_config.resize_algorithm, ResizeAlgorithm::default());
|
||||||
|
|
|
@ -71,7 +71,7 @@
|
||||||
//! let tmp_dir = tempfile::tempdir()?;
|
//! let tmp_dir = tempfile::tempdir()?;
|
||||||
//! let db_dir = tmp_dir.path().to_owned();
|
//! let db_dir = tmp_dir.path().to_owned();
|
||||||
//! let config = ConfigBuilder::new()
|
//! let config = ConfigBuilder::new()
|
||||||
//! .db_directory(db_dir.into())
|
//! .data_directory(db_dir.into())
|
||||||
//! .build();
|
//! .build();
|
||||||
//!
|
//!
|
||||||
//! // Initialize the database environment.
|
//! // Initialize the database environment.
|
||||||
|
|
|
@ -77,7 +77,7 @@
|
||||||
//! let tmp_dir = tempfile::tempdir()?;
|
//! let tmp_dir = tempfile::tempdir()?;
|
||||||
//! let db_dir = tmp_dir.path().to_owned();
|
//! let db_dir = tmp_dir.path().to_owned();
|
||||||
//! let config = ConfigBuilder::new()
|
//! let config = ConfigBuilder::new()
|
||||||
//! .db_directory(db_dir.into())
|
//! .data_directory(db_dir.into())
|
||||||
//! .build();
|
//! .build();
|
||||||
//!
|
//!
|
||||||
//! // Initialize the database thread-pool.
|
//! // Initialize the database thread-pool.
|
||||||
|
|
|
@ -7,7 +7,6 @@
|
||||||
|
|
||||||
//---------------------------------------------------------------------------------------------------- Use
|
//---------------------------------------------------------------------------------------------------- Use
|
||||||
use std::{
|
use std::{
|
||||||
borrow::Cow,
|
|
||||||
collections::{HashMap, HashSet},
|
collections::{HashMap, HashSet},
|
||||||
sync::Arc,
|
sync::Arc,
|
||||||
};
|
};
|
||||||
|
@ -46,7 +45,7 @@ fn init_service() -> (
|
||||||
) {
|
) {
|
||||||
let tempdir = tempfile::tempdir().unwrap();
|
let tempdir = tempfile::tempdir().unwrap();
|
||||||
let config = ConfigBuilder::new()
|
let config = ConfigBuilder::new()
|
||||||
.db_directory(Cow::Owned(tempdir.path().into()))
|
.data_directory(tempdir.path().into())
|
||||||
.low_power()
|
.low_power()
|
||||||
.build();
|
.build();
|
||||||
let (reader, writer, env) = init(config).unwrap();
|
let (reader, writer, env) = init(config).unwrap();
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
//! - only used internally
|
//! - only used internally
|
||||||
|
|
||||||
//---------------------------------------------------------------------------------------------------- Import
|
//---------------------------------------------------------------------------------------------------- Import
|
||||||
use std::{borrow::Cow, fmt::Debug};
|
use std::fmt::Debug;
|
||||||
|
|
||||||
use pretty_assertions::assert_eq;
|
use pretty_assertions::assert_eq;
|
||||||
|
|
||||||
|
@ -74,7 +74,7 @@ impl AssertTableLen {
|
||||||
pub(crate) fn tmp_concrete_env() -> (impl Env, tempfile::TempDir) {
|
pub(crate) fn tmp_concrete_env() -> (impl Env, tempfile::TempDir) {
|
||||||
let tempdir = tempfile::tempdir().unwrap();
|
let tempdir = tempfile::tempdir().unwrap();
|
||||||
let config = ConfigBuilder::new()
|
let config = ConfigBuilder::new()
|
||||||
.db_directory(Cow::Owned(tempdir.path().into()))
|
.data_directory(tempdir.path().into())
|
||||||
.low_power()
|
.low_power()
|
||||||
.build();
|
.build();
|
||||||
let env = crate::open(config).unwrap();
|
let env = crate::open(config).unwrap();
|
||||||
|
|
|
@ -15,7 +15,7 @@ default = ["heed"]
|
||||||
heed = ["cuprate-database/heed"]
|
heed = ["cuprate-database/heed"]
|
||||||
redb = ["cuprate-database/redb"]
|
redb = ["cuprate-database/redb"]
|
||||||
redb-memory = ["cuprate-database/redb-memory"]
|
redb-memory = ["cuprate-database/redb-memory"]
|
||||||
serde = ["dep:serde", "cuprate-database/serde", "cuprate-database-service/serde"]
|
serde = ["dep:serde", "cuprate-database/serde", "cuprate-database-service/serde", "cuprate-helper/serde"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
cuprate-database = { workspace = true, features = ["heed"] }
|
cuprate-database = { workspace = true, features = ["heed"] }
|
||||||
|
|
|
@ -78,7 +78,7 @@ use cuprate_txpool::{
|
||||||
let tmp_dir = tempfile::tempdir()?;
|
let tmp_dir = tempfile::tempdir()?;
|
||||||
let db_dir = tmp_dir.path().to_owned();
|
let db_dir = tmp_dir.path().to_owned();
|
||||||
let config = ConfigBuilder::new()
|
let config = ConfigBuilder::new()
|
||||||
.db_directory(db_dir.into())
|
.data_directory(db_dir.into())
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
// Initialize the database environment.
|
// Initialize the database environment.
|
||||||
|
|
|
@ -1,15 +1,18 @@
|
||||||
//! The transaction pool [`Config`].
|
//! The transaction pool [`Config`].
|
||||||
use std::{borrow::Cow, path::Path};
|
use std::{borrow::Cow, path::PathBuf};
|
||||||
|
|
||||||
|
#[cfg(feature = "serde")]
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use cuprate_database::{
|
use cuprate_database::{
|
||||||
config::{Config as DbConfig, SyncMode},
|
config::{Config as DbConfig, SyncMode},
|
||||||
resize::ResizeAlgorithm,
|
resize::ResizeAlgorithm,
|
||||||
};
|
};
|
||||||
use cuprate_database_service::ReaderThreads;
|
use cuprate_database_service::ReaderThreads;
|
||||||
use cuprate_helper::fs::CUPRATE_TXPOOL_DIR;
|
use cuprate_helper::{
|
||||||
|
fs::{txpool_path, CUPRATE_DATA_DIR},
|
||||||
#[cfg(feature = "serde")]
|
network::Network,
|
||||||
use serde::{Deserialize, Serialize};
|
};
|
||||||
|
|
||||||
/// The default transaction pool weight limit.
|
/// The default transaction pool weight limit.
|
||||||
const DEFAULT_TXPOOL_WEIGHT_LIMIT: usize = 600 * 1024 * 1024;
|
const DEFAULT_TXPOOL_WEIGHT_LIMIT: usize = 600 * 1024 * 1024;
|
||||||
|
@ -21,8 +24,9 @@ const DEFAULT_TXPOOL_WEIGHT_LIMIT: usize = 600 * 1024 * 1024;
|
||||||
#[derive(Debug, Clone, PartialEq, PartialOrd)]
|
#[derive(Debug, Clone, PartialEq, PartialOrd)]
|
||||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||||
pub struct ConfigBuilder {
|
pub struct ConfigBuilder {
|
||||||
/// [`Config::db_directory`].
|
network: Network,
|
||||||
db_directory: Option<Cow<'static, Path>>,
|
|
||||||
|
data_dir: Option<PathBuf>,
|
||||||
|
|
||||||
/// [`Config::cuprate_database_config`].
|
/// [`Config::cuprate_database_config`].
|
||||||
db_config: cuprate_database::config::ConfigBuilder,
|
db_config: cuprate_database::config::ConfigBuilder,
|
||||||
|
@ -41,10 +45,12 @@ impl ConfigBuilder {
|
||||||
/// after this function to use default values.
|
/// after this function to use default values.
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
db_directory: None,
|
network: Network::default(),
|
||||||
db_config: cuprate_database::config::ConfigBuilder::new(Cow::Borrowed(
|
data_dir: None,
|
||||||
&*CUPRATE_TXPOOL_DIR,
|
db_config: cuprate_database::config::ConfigBuilder::new(Cow::Owned(txpool_path(
|
||||||
)),
|
&CUPRATE_DATA_DIR,
|
||||||
|
Network::Mainnet,
|
||||||
|
))),
|
||||||
reader_threads: None,
|
reader_threads: None,
|
||||||
max_txpool_weight: None,
|
max_txpool_weight: None,
|
||||||
}
|
}
|
||||||
|
@ -53,16 +59,16 @@ impl ConfigBuilder {
|
||||||
/// Build into a [`Config`].
|
/// Build into a [`Config`].
|
||||||
///
|
///
|
||||||
/// # Default values
|
/// # Default values
|
||||||
/// If [`ConfigBuilder::db_directory`] was not called,
|
/// If [`ConfigBuilder::data_directory`] was not called,
|
||||||
/// the default [`CUPRATE_TXPOOL_DIR`] will be used.
|
/// [`txpool_path`] with [`CUPRATE_DATA_DIR`] and [`Network::Mainnet`] will be used.
|
||||||
///
|
///
|
||||||
/// For all other values, [`Default::default`] is used.
|
/// For all other values, [`Default::default`] is used.
|
||||||
pub fn build(self) -> Config {
|
pub fn build(self) -> Config {
|
||||||
// INVARIANT: all PATH safety checks are done
|
// INVARIANT: all PATH safety checks are done
|
||||||
// in `helper::fs`. No need to do them here.
|
// in `helper::fs`. No need to do them here.
|
||||||
let db_directory = self
|
let data_dir = self
|
||||||
.db_directory
|
.data_dir
|
||||||
.unwrap_or_else(|| Cow::Borrowed(&*CUPRATE_TXPOOL_DIR));
|
.unwrap_or_else(|| CUPRATE_DATA_DIR.to_path_buf());
|
||||||
|
|
||||||
let reader_threads = self.reader_threads.unwrap_or_default();
|
let reader_threads = self.reader_threads.unwrap_or_default();
|
||||||
|
|
||||||
|
@ -72,7 +78,7 @@ impl ConfigBuilder {
|
||||||
|
|
||||||
let db_config = self
|
let db_config = self
|
||||||
.db_config
|
.db_config
|
||||||
.db_directory(db_directory)
|
.db_directory(Cow::Owned(txpool_path(&data_dir, self.network)))
|
||||||
.reader_threads(reader_threads.as_threads())
|
.reader_threads(reader_threads.as_threads())
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
|
@ -83,6 +89,13 @@ impl ConfigBuilder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Change the network this database is for.
|
||||||
|
#[must_use]
|
||||||
|
pub const fn network(mut self, network: Network) -> Self {
|
||||||
|
self.network = network;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
/// Sets a new maximum weight for the transaction pool.
|
/// Sets a new maximum weight for the transaction pool.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub const fn max_txpool_weight(mut self, max_txpool_weight: usize) -> Self {
|
pub const fn max_txpool_weight(mut self, max_txpool_weight: usize) -> Self {
|
||||||
|
@ -90,10 +103,10 @@ impl ConfigBuilder {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set a custom database directory (and file) [`Path`].
|
/// Set a custom data directory [`PathBuf`].
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn db_directory(mut self, db_directory: Cow<'static, Path>) -> Self {
|
pub fn data_directory(mut self, db_directory: PathBuf) -> Self {
|
||||||
self.db_directory = Some(db_directory);
|
self.data_dir = Some(db_directory);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -124,9 +137,7 @@ impl ConfigBuilder {
|
||||||
/// Good default for testing, and resource-available machines.
|
/// Good default for testing, and resource-available machines.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn fast(mut self) -> Self {
|
pub fn fast(mut self) -> Self {
|
||||||
self.db_config =
|
self.db_config = self.db_config.fast();
|
||||||
cuprate_database::config::ConfigBuilder::new(Cow::Borrowed(&*CUPRATE_TXPOOL_DIR))
|
|
||||||
.fast();
|
|
||||||
|
|
||||||
self.reader_threads = Some(ReaderThreads::OnePerThread);
|
self.reader_threads = Some(ReaderThreads::OnePerThread);
|
||||||
self
|
self
|
||||||
|
@ -138,9 +149,7 @@ impl ConfigBuilder {
|
||||||
/// Good default for resource-limited machines, e.g. a cheap VPS.
|
/// Good default for resource-limited machines, e.g. a cheap VPS.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn low_power(mut self) -> Self {
|
pub fn low_power(mut self) -> Self {
|
||||||
self.db_config =
|
self.db_config = self.db_config.low_power();
|
||||||
cuprate_database::config::ConfigBuilder::new(Cow::Borrowed(&*CUPRATE_TXPOOL_DIR))
|
|
||||||
.low_power();
|
|
||||||
|
|
||||||
self.reader_threads = Some(ReaderThreads::One);
|
self.reader_threads = Some(ReaderThreads::One);
|
||||||
self
|
self
|
||||||
|
@ -149,10 +158,13 @@ impl ConfigBuilder {
|
||||||
|
|
||||||
impl Default for ConfigBuilder {
|
impl Default for ConfigBuilder {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
let db_directory = Cow::Borrowed(CUPRATE_TXPOOL_DIR.as_path());
|
|
||||||
Self {
|
Self {
|
||||||
db_directory: Some(db_directory.clone()),
|
network: Network::default(),
|
||||||
db_config: cuprate_database::config::ConfigBuilder::new(db_directory),
|
data_dir: Some(CUPRATE_DATA_DIR.to_path_buf()),
|
||||||
|
db_config: cuprate_database::config::ConfigBuilder::new(Cow::Owned(txpool_path(
|
||||||
|
&CUPRATE_DATA_DIR,
|
||||||
|
Network::Mainnet,
|
||||||
|
))),
|
||||||
reader_threads: Some(ReaderThreads::default()),
|
reader_threads: Some(ReaderThreads::default()),
|
||||||
max_txpool_weight: Some(DEFAULT_TXPOOL_WEIGHT_LIMIT),
|
max_txpool_weight: Some(DEFAULT_TXPOOL_WEIGHT_LIMIT),
|
||||||
}
|
}
|
||||||
|
@ -184,7 +196,7 @@ impl Config {
|
||||||
/// Create a new [`Config`] with sane default settings.
|
/// Create a new [`Config`] with sane default settings.
|
||||||
///
|
///
|
||||||
/// The [`DbConfig::db_directory`]
|
/// The [`DbConfig::db_directory`]
|
||||||
/// will be set to [`CUPRATE_TXPOOL_DIR`].
|
/// will be set to [`txpool_path`] with [`CUPRATE_DATA_DIR`] and [`Network::Mainnet`].
|
||||||
///
|
///
|
||||||
/// All other values will be [`Default::default`].
|
/// All other values will be [`Default::default`].
|
||||||
///
|
///
|
||||||
|
@ -197,25 +209,21 @@ impl Config {
|
||||||
/// DATABASE_DATA_FILENAME,
|
/// DATABASE_DATA_FILENAME,
|
||||||
/// };
|
/// };
|
||||||
/// use cuprate_database_service::ReaderThreads;
|
/// use cuprate_database_service::ReaderThreads;
|
||||||
/// use cuprate_helper::fs::*;
|
/// use cuprate_helper::{fs::*, network::Network};
|
||||||
///
|
///
|
||||||
/// use cuprate_txpool::Config;
|
/// use cuprate_txpool::Config;
|
||||||
///
|
///
|
||||||
/// let config = Config::new();
|
/// let config = Config::new();
|
||||||
///
|
///
|
||||||
/// assert_eq!(config.db_config.db_directory(), &*CUPRATE_TXPOOL_DIR);
|
/// assert_eq!(config.db_config.db_directory(), txpool_path(&CUPRATE_DATA_DIR, Network::Mainnet).as_path());
|
||||||
/// assert!(config.db_config.db_file().starts_with(&*CUPRATE_TXPOOL_DIR));
|
/// assert!(config.db_config.db_file().starts_with(&*CUPRATE_DATA_DIR));
|
||||||
/// assert!(config.db_config.db_file().ends_with(DATABASE_DATA_FILENAME));
|
/// assert!(config.db_config.db_file().ends_with(DATABASE_DATA_FILENAME));
|
||||||
/// assert_eq!(config.db_config.sync_mode, SyncMode::default());
|
/// assert_eq!(config.db_config.sync_mode, SyncMode::default());
|
||||||
/// assert_eq!(config.db_config.resize_algorithm, ResizeAlgorithm::default());
|
/// assert_eq!(config.db_config.resize_algorithm, ResizeAlgorithm::default());
|
||||||
/// assert_eq!(config.reader_threads, ReaderThreads::default());
|
/// assert_eq!(config.reader_threads, ReaderThreads::default());
|
||||||
/// ```
|
/// ```
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
ConfigBuilder::new().build()
|
||||||
db_config: DbConfig::new(Cow::Borrowed(&*CUPRATE_TXPOOL_DIR)),
|
|
||||||
reader_threads: ReaderThreads::default(),
|
|
||||||
max_txpool_weight: 0,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -51,7 +51,7 @@
|
||||||
//! let tmp_dir = tempfile::tempdir()?;
|
//! let tmp_dir = tempfile::tempdir()?;
|
||||||
//! let db_dir = tmp_dir.path().to_owned();
|
//! let db_dir = tmp_dir.path().to_owned();
|
||||||
//! let config = ConfigBuilder::new()
|
//! let config = ConfigBuilder::new()
|
||||||
//! .db_directory(db_dir.into())
|
//! .data_directory(db_dir.into())
|
||||||
//! .build();
|
//! .build();
|
||||||
//!
|
//!
|
||||||
//! // Initialize the database environment.
|
//! // Initialize the database environment.
|
||||||
|
|
|
@ -83,7 +83,7 @@
|
||||||
//! let tmp_dir = tempfile::tempdir()?;
|
//! let tmp_dir = tempfile::tempdir()?;
|
||||||
//! let db_dir = tmp_dir.path().to_owned();
|
//! let db_dir = tmp_dir.path().to_owned();
|
||||||
//! let config = ConfigBuilder::new()
|
//! let config = ConfigBuilder::new()
|
||||||
//! .db_directory(db_dir.into())
|
//! .data_directory(db_dir.into())
|
||||||
//! .build();
|
//! .build();
|
||||||
//!
|
//!
|
||||||
//! // Initialize the database thread-pool.
|
//! // Initialize the database thread-pool.
|
||||||
|
|
Loading…
Reference in a new issue