mirror of
https://github.com/Cuprate/cuprate.git
synced 2025-01-21 02:04:33 +00:00
finish initial config.
This commit is contained in:
parent
8d0c26c8a2
commit
5906e7d4b7
21 changed files with 595 additions and 59 deletions
28
Cargo.lock
generated
28
Cargo.lock
generated
|
@ -798,6 +798,7 @@ dependencies = [
|
|||
"rand",
|
||||
"rand_distr",
|
||||
"rayon",
|
||||
"serde",
|
||||
"thiserror",
|
||||
"tokio",
|
||||
"tokio-stream",
|
||||
|
@ -1018,6 +1019,7 @@ dependencies = [
|
|||
"tokio",
|
||||
"tokio-stream",
|
||||
"tokio-util",
|
||||
"toml",
|
||||
"tower 0.5.1",
|
||||
"tracing",
|
||||
"tracing-subscriber",
|
||||
|
@ -2552,6 +2554,15 @@ dependencies = [
|
|||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_spanned"
|
||||
version = "0.6.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_urlencoded"
|
||||
version = "0.7.1"
|
||||
|
@ -2911,11 +2922,26 @@ dependencies = [
|
|||
"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]]
|
||||
name = "toml_datetime"
|
||||
version = "0.6.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml_edit"
|
||||
|
@ -2924,6 +2950,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "3b072cee73c449a636ffd6f32bd8de3a9f7119139aff882f44943ce2986dc5cf"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"serde",
|
||||
"serde_spanned",
|
||||
"toml_datetime",
|
||||
"winnow",
|
||||
]
|
||||
|
|
|
@ -13,20 +13,20 @@ cuprate-consensus = { path = "../../consensus" }
|
|||
cuprate-fast-sync = { path = "../../consensus/fast-sync" }
|
||||
cuprate-consensus-rules = { path = "../../consensus/rules" }
|
||||
cuprate-cryptonight = { path = "../../cryptonight" }
|
||||
cuprate-helper = { path = "../../helper" }
|
||||
cuprate-helper = { path = "../../helper", features = ["serde"] }
|
||||
cuprate-epee-encoding = { path = "../../net/epee-encoding" }
|
||||
cuprate-fixed-bytes = { path = "../../net/fixed-bytes" }
|
||||
cuprate-levin = { path = "../../net/levin" }
|
||||
cuprate-wire = { path = "../../net/wire" }
|
||||
cuprate-p2p = { path = "../../p2p/p2p" }
|
||||
cuprate-p2p = { path = "../../p2p/p2p", features = ["serde"] }
|
||||
cuprate-p2p-core = { path = "../../p2p/p2p-core", features = ["serde"] }
|
||||
cuprate-dandelion-tower = { path = "../../p2p/dandelion-tower" }
|
||||
cuprate-async-buffer = { path = "../../p2p/async-buffer" }
|
||||
cuprate-address-book = { path = "../../p2p/address-book", features = ["serde_config"] }
|
||||
cuprate-blockchain = { path = "../../storage/blockchain", features = ["service"] }
|
||||
cuprate-database-service = { path = "../../storage/service" }
|
||||
cuprate-database-service = { path = "../../storage/service", features = ["serde"] }
|
||||
cuprate-txpool = { path = "../../storage/txpool" }
|
||||
cuprate-database = { path = "../../storage/database" }
|
||||
cuprate-database = { path = "../../storage/database", features = ["serde"] }
|
||||
cuprate-pruning = { path = "../../pruning" }
|
||||
cuprate-test-utils = { path = "../../test-utils" }
|
||||
cuprate-types = { path = "../../types" }
|
||||
|
@ -71,7 +71,8 @@ tokio-stream = { workspace = true }
|
|||
tokio = { workspace = true }
|
||||
tower = { workspace = true }
|
||||
tracing-subscriber = { workspace = true, features = ["std", "fmt", "default"] }
|
||||
tracing = { workspace = true }
|
||||
tracing = { workspace = true, features = ["default"] }
|
||||
toml = "0.8"
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
|
|
@ -1,52 +1,124 @@
|
|||
//! 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::network::Network;
|
||||
use cuprate_helper::{fs::CUPRATE_CONFIG_DIR, network::Network};
|
||||
use cuprate_p2p::block_downloader::BlockDownloaderConfig;
|
||||
use cuprate_p2p_core::ClearNet;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::time::Duration;
|
||||
|
||||
mod args;
|
||||
mod default;
|
||||
mod p2p;
|
||||
mod storage;
|
||||
mod tracing_config;
|
||||
|
||||
use p2p::P2PConfig;
|
||||
use storage::StorageConfig;
|
||||
use tracing_config::TracingConfig;
|
||||
|
||||
pub fn config() -> Config {
|
||||
Config::default()
|
||||
/// The default name of Cuprate's config file.
|
||||
const DEFAULT_CONFIG_FILE_NAME: &str = "Cuprate.toml";
|
||||
|
||||
/// 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 read it and exit if we can't.
|
||||
match Config::read_from_file(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_err(Into::into)
|
||||
.and_then(Config::read_from_file)
|
||||
.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_file(file)
|
||||
})
|
||||
.inspect_err(|e| {
|
||||
tracing::debug!("Failed to read config from config dir: {e}");
|
||||
tracing::warn!("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,
|
||||
}
|
||||
|
||||
impl Config {
|
||||
pub fn network(&self) -> Network {
|
||||
/// 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_file(file: impl AsRef<Path>) -> Result<Self, anyhow::Error> {
|
||||
let file_text = read_to_string(file.as_ref())?;
|
||||
|
||||
Ok(toml::from_str(&file_text).inspect_err(|_| {
|
||||
tracing::warn!(
|
||||
"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(self.p2p.clear_net.server.clone()),
|
||||
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.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn context_config(&self) -> ContextConfig {
|
||||
/// The [`ContextConfig`].
|
||||
pub const fn context_config(&self) -> ContextConfig {
|
||||
match self.network {
|
||||
Network::Mainnet => ContextConfig::main_net(),
|
||||
Network::Stagenet => ContextConfig::stage_net(),
|
||||
|
@ -54,17 +126,20 @@ impl Config {
|
|||
}
|
||||
}
|
||||
|
||||
/// The [`cuprate_blockchain`] config.
|
||||
pub fn blockchain_config(&self) -> cuprate_blockchain::config::Config {
|
||||
self.storage.blockchain.clone()
|
||||
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)
|
||||
.db_directory(blockchain.shared.path.clone())
|
||||
.sync_mode(blockchain.shared.sync_mode)
|
||||
.build()
|
||||
}
|
||||
|
||||
pub fn block_downloader_config(&self) -> BlockDownloaderConfig {
|
||||
BlockDownloaderConfig {
|
||||
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,
|
||||
initial_batch_size: 1,
|
||||
}
|
||||
/// The [`BlockDownloaderConfig`].
|
||||
pub const fn block_downloader_config(&self) -> BlockDownloaderConfig {
|
||||
self.p2p.block_downloader
|
||||
}
|
||||
}
|
||||
|
|
75
binaries/cuprated/src/config/Cuprate.toml
Normal file
75
binaries/cuprated/src/config/Cuprate.toml
Normal file
|
@ -0,0 +1,75 @@
|
|||
# ____ _
|
||||
# / ___| _ _ __ _ __ __ _| |_ ___
|
||||
# | | | | | | '_ \| '__/ _` | __/ _ \
|
||||
# | |__| |_| | |_) | | | (_| | || __/
|
||||
# \____\__,_| .__/|_| \__,_|\__\___|
|
||||
# |_|
|
||||
#
|
||||
|
||||
## 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.
|
||||
server.ip = "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 folder to store the address book.
|
||||
peer_store_folder = "{cache}"
|
||||
## 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 number of blocks in the first bacth (you probably shouldn't change this).
|
||||
initial_batch_len = 1
|
||||
## 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 txpool storage location.
|
||||
path = "{txpool}"
|
||||
## The database sync mode for the txpool.
|
||||
sync_mode = "Async"
|
||||
## The maximum size of all the txs in the pool (bytes).
|
||||
max_txpool_size = 100_000_000
|
||||
|
||||
## Blockchain storage config.
|
||||
[storage.blockchain]
|
||||
## The blockchain storage location.
|
||||
path = "{blockchain}"
|
||||
## The database sync mode for the blockchain.
|
||||
sync_mode = "Async"
|
45
binaries/cuprated/src/config/args.rs
Normal file
45
binaries/cuprated/src/config/args.rs
Normal file
|
@ -0,0 +1,45 @@
|
|||
use std::{io::Write, path::PathBuf};
|
||||
|
||||
use clap::builder::TypedValueParser;
|
||||
|
||||
use cuprate_helper::network::Network;
|
||||
|
||||
use crate::config::{default::create_default_config_file, Config, DEFAULT_CONFIG_FILE_NAME};
|
||||
|
||||
#[derive(clap::Parser, Debug)]
|
||||
pub struct Args {
|
||||
/// The network we should 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.
|
||||
pub outbound_connections: Option<usize>,
|
||||
/// The location of the Cuprate config file.
|
||||
pub config_file: Option<PathBuf>,
|
||||
/// Generate a config file and place it in the given folder.
|
||||
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
|
||||
}
|
||||
}
|
69
binaries/cuprated/src/config/default.rs
Normal file
69
binaries/cuprated/src/config/default.rs
Normal file
|
@ -0,0 +1,69 @@
|
|||
use std::{
|
||||
io::Write,
|
||||
path::{Path, PathBuf},
|
||||
};
|
||||
|
||||
use cuprate_helper::fs::{CUPRATE_BLOCKCHAIN_DIR, CUPRATE_CACHE_DIR, CUPRATE_TXPOOL_DIR};
|
||||
|
||||
use crate::config::DEFAULT_CONFIG_FILE_NAME;
|
||||
|
||||
/// 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 = generate_config_text();
|
||||
file.write_all(config.as_bytes()).unwrap();
|
||||
|
||||
std::process::exit(0);
|
||||
}
|
||||
|
||||
/// Generates the text of the default config file.
|
||||
fn generate_config_text() -> String {
|
||||
format!(
|
||||
include_str!("Cuprate.toml"),
|
||||
cache = CUPRATE_CACHE_DIR.to_string_lossy(),
|
||||
txpool = CUPRATE_TXPOOL_DIR.to_string_lossy(),
|
||||
blockchain = CUPRATE_BLOCKCHAIN_DIR.to_string_lossy()
|
||||
)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::config::{default::generate_config_text, Config};
|
||||
|
||||
#[test]
|
||||
fn generate_config_text_covers_all_values() {
|
||||
let text = generate_config_text();
|
||||
|
||||
let table: toml::Table = toml::from_str(&text).unwrap();
|
||||
|
||||
let full_config = Config::default();
|
||||
let full_config_table: toml::Table =
|
||||
toml::from_str(&toml::to_string(&full_config).unwrap()).unwrap();
|
||||
|
||||
assert_eq!(full_config_table, table);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn generate_config_text_is_valid() {
|
||||
let text = generate_config_text();
|
||||
|
||||
let config: Config = toml::from_str(&text).unwrap();
|
||||
}
|
||||
}
|
|
@ -1,21 +1,33 @@
|
|||
use cuprate_address_book::AddressBookConfig;
|
||||
use cuprate_p2p_core::ClearNetServerCfg;
|
||||
use std::net::SocketAddr;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use cuprate_address_book::AddressBookConfig;
|
||||
use cuprate_helper::network::Network;
|
||||
use cuprate_p2p::block_downloader::BlockDownloaderConfig;
|
||||
use cuprate_p2p_core::ClearNetServerCfg;
|
||||
|
||||
/// 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,
|
||||
}
|
||||
|
||||
/// The config values for P2P clear-net.
|
||||
#[derive(Default, Deserialize, Serialize)]
|
||||
#[serde(deny_unknown_fields, default)]
|
||||
pub struct ClearNetConfig {
|
||||
/// The server config.
|
||||
pub server: ClearNetServerCfg,
|
||||
#[serde(flatten)]
|
||||
pub general: SharedNetConfig,
|
||||
}
|
||||
|
||||
/// Network config values shared between all network zones.
|
||||
#[derive(Deserialize, Serialize)]
|
||||
#[serde(deny_unknown_fields, default)]
|
||||
pub struct SharedNetConfig {
|
||||
|
@ -25,6 +37,7 @@ pub struct SharedNetConfig {
|
|||
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,
|
||||
|
@ -39,8 +52,46 @@ impl Default for SharedNetConfig {
|
|||
extra_outbound_connections: 8,
|
||||
max_inbound_connections: 128,
|
||||
gray_peers_percent: 0.7,
|
||||
p2p_port: 18080,
|
||||
p2p_port: 0,
|
||||
address_book_config: AddressBookConfig::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 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| str::parse(s))
|
||||
.collect::<Result<_, _>>()
|
||||
.unwrap()
|
||||
}
|
||||
|
|
|
@ -1,8 +1,70 @@
|
|||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use cuprate_database::config::SyncMode;
|
||||
use cuprate_database_service::ReaderThreads;
|
||||
use cuprate_helper::fs::{CUPRATE_BLOCKCHAIN_DIR, CUPRATE_TXPOOL_DIR};
|
||||
|
||||
/// The storage config.
|
||||
#[derive(Default, Deserialize, Serialize)]
|
||||
#[serde(deny_unknown_fields, default)]
|
||||
pub struct StorageConfig {
|
||||
pub blockchain: cuprate_blockchain::config::Config,
|
||||
pub txpool: cuprate_txpool::Config,
|
||||
/// 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 {
|
||||
path: CUPRATE_BLOCKCHAIN_DIR.to_path_buf(),
|
||||
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 (bytes).
|
||||
pub max_txpool_size: usize,
|
||||
}
|
||||
|
||||
impl Default for TxpoolConfig {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
shared: SharedStorageConfig {
|
||||
path: CUPRATE_TXPOOL_DIR.to_path_buf(),
|
||||
sync_mode: SyncMode::Async,
|
||||
},
|
||||
max_txpool_size: 100_000_000,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Config values shared between the tx-pool and blockchain.
|
||||
#[derive(Deserialize, Serialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct SharedStorageConfig {
|
||||
/// The path to the database storage.
|
||||
pub path: std::path::PathBuf,
|
||||
/// The [`SyncMode`] of the database.
|
||||
#[serde(default)]
|
||||
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)
|
||||
}
|
||||
}
|
|
@ -25,6 +25,8 @@ fn main() {
|
|||
// Initialize global static `LazyLock` data.
|
||||
statics::init_lazylock_statics();
|
||||
|
||||
let _config = config::read_config_and_args();
|
||||
|
||||
// TODO: everything else.
|
||||
todo!()
|
||||
}
|
||||
|
|
|
@ -28,6 +28,8 @@
|
|||
//! - <https://docs.rs/dirs>
|
||||
|
||||
//---------------------------------------------------------------------------------------------------- Use
|
||||
use crate::network::Network;
|
||||
use std::path::Path;
|
||||
use std::{path::PathBuf, sync::LazyLock};
|
||||
|
||||
//---------------------------------------------------------------------------------------------------- Const
|
||||
|
@ -178,6 +180,10 @@ impl_path_lazylock! {
|
|||
"txpool",
|
||||
}
|
||||
|
||||
pub fn path_with_network(path: &Path, network: Network) -> PathBuf {
|
||||
path.join(network.to_string())
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------------------------------- Tests
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
|
|
|
@ -7,6 +7,9 @@
|
|||
//! `#[no_std]` compatible.
|
||||
// TODO: move to types crate.
|
||||
|
||||
use std::fmt::{Display, Formatter};
|
||||
use std::str::FromStr;
|
||||
|
||||
const MAINNET_NETWORK_ID: [u8; 16] = [
|
||||
0x12, 0x30, 0xF1, 0x71, 0x61, 0x04, 0x41, 0x61, 0x17, 0x31, 0x00, 0x82, 0x16, 0xA1, 0xA1, 0x10,
|
||||
];
|
||||
|
@ -18,7 +21,7 @@ const STAGENET_NETWORK_ID: [u8; 16] = [
|
|||
];
|
||||
|
||||
/// 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 {
|
||||
/// Mainnet
|
||||
|
@ -40,3 +43,29 @@ 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.to_lowercase().as_str() {
|
||||
"mainnet" => Ok(Self::Mainnet),
|
||||
"testnet" => Ok(Self::Testnet),
|
||||
"stagenet" => Ok(Self::Stagenet),
|
||||
_ => Err(ParseNetworkError),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Network {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
f.write_str(match self {
|
||||
Self::Mainnet => "mainnet",
|
||||
Self::Testnet => "testnet",
|
||||
Self::Stagenet => "stagenet",
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -51,6 +51,8 @@ impl<'a> From<&'a PeerSupportFlags> for &'a u32 {
|
|||
}
|
||||
}
|
||||
|
||||
//15515542498767257178
|
||||
|
||||
/// Basic Node Data, information on the connected peer
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct BasicNodeData {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use std::{
|
||||
net::{IpAddr, SocketAddr},
|
||||
net::{IpAddr, Ipv4Addr, SocketAddr},
|
||||
pin::Pin,
|
||||
task::{Context, Poll},
|
||||
};
|
||||
|
|
|
@ -34,6 +34,8 @@ rand_distr = { workspace = true, features = ["std"] }
|
|||
tracing = { workspace = true, features = ["std", "attributes"] }
|
||||
borsh = { workspace = true, features = ["derive", "std"] }
|
||||
|
||||
serde = { workspace = true, features = ["std", "derive"], optional = true }
|
||||
|
||||
[dev-dependencies]
|
||||
cuprate-test-utils = { path = "../../test-utils" }
|
||||
indexmap = { workspace = true }
|
||||
|
|
|
@ -59,6 +59,8 @@ pub struct BlockBatch {
|
|||
|
||||
/// The block downloader config.
|
||||
#[derive(Debug, Copy, Clone, PartialOrd, PartialEq, Ord, Eq)]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||
#[cfg_attr(feature = "serde", 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.
|
||||
|
@ -70,7 +72,19 @@ pub struct BlockDownloaderConfig {
|
|||
/// The target size of a single batch of blocks (in bytes).
|
||||
pub target_batch_size: usize,
|
||||
/// The initial amount of blocks to request (in number of blocks)
|
||||
pub initial_batch_size: usize,
|
||||
pub initial_batch_len: usize,
|
||||
}
|
||||
|
||||
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,
|
||||
initial_batch_len: 1,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// An error that occurred in the [`BlockDownloader`].
|
||||
|
@ -243,7 +257,7 @@ where
|
|||
Self {
|
||||
client_pool,
|
||||
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_empty_chain_entries: 0,
|
||||
block_download_tasks: JoinSet::new(),
|
||||
|
|
|
@ -69,7 +69,7 @@ proptest! {
|
|||
in_progress_queue_size: 10_000,
|
||||
check_client_pool_interval: Duration::from_secs(5),
|
||||
target_batch_size: 5_000,
|
||||
initial_batch_size: 1,
|
||||
initial_batch_len: 1,
|
||||
});
|
||||
|
||||
let blocks = stream.map(|blocks| blocks.blocks).concat().await;
|
||||
|
|
|
@ -16,6 +16,7 @@ heed = ["cuprate-database/heed"]
|
|||
redb = ["cuprate-database/redb"]
|
||||
redb-memory = ["cuprate-database/redb-memory"]
|
||||
service = ["dep:thread_local", "dep:rayon", "cuprate-helper/thread"]
|
||||
serde = ["dep:serde", "cuprate-helper/serde", "cuprate-database-service/serde", "cuprate-database/serde"]
|
||||
|
||||
[dependencies]
|
||||
cuprate-database = { path = "../database" }
|
||||
|
|
|
@ -41,16 +41,17 @@
|
|||
//! ```
|
||||
|
||||
//---------------------------------------------------------------------------------------------------- Import
|
||||
use std::{borrow::Cow, path::Path};
|
||||
use std::{borrow::Cow, path::PathBuf};
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use cuprate_database::{config::SyncMode, resize::ResizeAlgorithm};
|
||||
use cuprate_helper::fs::CUPRATE_BLOCKCHAIN_DIR;
|
||||
use cuprate_helper::fs::{path_with_network, CUPRATE_BLOCKCHAIN_DIR};
|
||||
|
||||
// re-exports
|
||||
pub use cuprate_database_service::ReaderThreads;
|
||||
use cuprate_helper::network::Network;
|
||||
|
||||
//---------------------------------------------------------------------------------------------------- ConfigBuilder
|
||||
/// Builder for [`Config`].
|
||||
|
@ -59,8 +60,10 @@ pub use cuprate_database_service::ReaderThreads;
|
|||
#[derive(Debug, Clone, PartialEq, PartialOrd)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
pub struct ConfigBuilder {
|
||||
network: Network,
|
||||
|
||||
/// [`Config::db_directory`].
|
||||
db_directory: Option<Cow<'static, Path>>,
|
||||
db_directory: Option<PathBuf>,
|
||||
|
||||
/// [`Config::cuprate_database_config`].
|
||||
db_config: cuprate_database::config::ConfigBuilder,
|
||||
|
@ -76,10 +79,12 @@ impl ConfigBuilder {
|
|||
/// after this function to use default values.
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
network: Network::default(),
|
||||
db_directory: None,
|
||||
db_config: cuprate_database::config::ConfigBuilder::new(Cow::Borrowed(
|
||||
&*CUPRATE_BLOCKCHAIN_DIR,
|
||||
)),
|
||||
db_config: cuprate_database::config::ConfigBuilder::new(Cow::Owned(path_with_network(
|
||||
&CUPRATE_BLOCKCHAIN_DIR,
|
||||
Network::default(),
|
||||
))),
|
||||
reader_threads: None,
|
||||
}
|
||||
}
|
||||
|
@ -96,12 +101,12 @@ impl ConfigBuilder {
|
|||
// in `helper::fs`. No need to do them here.
|
||||
let db_directory = self
|
||||
.db_directory
|
||||
.unwrap_or_else(|| Cow::Borrowed(&*CUPRATE_BLOCKCHAIN_DIR));
|
||||
.unwrap_or_else(|| CUPRATE_BLOCKCHAIN_DIR.to_path_buf());
|
||||
|
||||
let reader_threads = self.reader_threads.unwrap_or_default();
|
||||
let db_config = self
|
||||
.db_config
|
||||
.db_directory(db_directory)
|
||||
.db_directory(Cow::Owned(path_with_network(&db_directory, self.network)))
|
||||
.reader_threads(reader_threads.as_threads())
|
||||
.build();
|
||||
|
||||
|
@ -111,9 +116,16 @@ impl ConfigBuilder {
|
|||
}
|
||||
}
|
||||
|
||||
/// Change the network this blockchain database is for.
|
||||
#[must_use]
|
||||
pub const fn network(mut self, network: Network) -> Self {
|
||||
self.network = network;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set a custom database directory (and file) [`Path`].
|
||||
#[must_use]
|
||||
pub fn db_directory(mut self, db_directory: Cow<'static, Path>) -> Self {
|
||||
pub fn db_directory(mut self, db_directory: PathBuf) -> Self {
|
||||
self.db_directory = Some(db_directory);
|
||||
self
|
||||
}
|
||||
|
@ -170,10 +182,13 @@ impl ConfigBuilder {
|
|||
|
||||
impl Default for ConfigBuilder {
|
||||
fn default() -> Self {
|
||||
let db_directory = Cow::Borrowed(&**CUPRATE_BLOCKCHAIN_DIR);
|
||||
Self {
|
||||
db_directory: Some(db_directory.clone()),
|
||||
db_config: cuprate_database::config::ConfigBuilder::new(db_directory),
|
||||
network: Network::default(),
|
||||
db_directory: Some(CUPRATE_BLOCKCHAIN_DIR.to_path_buf()),
|
||||
db_config: cuprate_database::config::ConfigBuilder::new(Cow::Owned(path_with_network(
|
||||
&CUPRATE_BLOCKCHAIN_DIR,
|
||||
Network::default(),
|
||||
))),
|
||||
reader_threads: Some(ReaderThreads::default()),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,7 +16,7 @@ heed = ["cuprate-database/heed"]
|
|||
redb = ["cuprate-database/redb"]
|
||||
redb-memory = ["cuprate-database/redb-memory"]
|
||||
service = ["dep:tower", "dep:rayon", "dep:cuprate-database-service"]
|
||||
serde = ["dep:serde", "cuprate-database/serde", "cuprate-database-service/serde"]
|
||||
serde = ["dep:serde", "cuprate-helper/serde", "cuprate-database-service/serde", "cuprate-database/serde"]
|
||||
|
||||
[dependencies]
|
||||
cuprate-database = { path = "../database", features = ["heed"] }
|
||||
|
|
|
@ -1,15 +1,18 @@
|
|||
//! 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::{
|
||||
config::{Config as DbConfig, SyncMode},
|
||||
resize::ResizeAlgorithm,
|
||||
};
|
||||
use cuprate_database_service::ReaderThreads;
|
||||
use cuprate_helper::fs::CUPRATE_TXPOOL_DIR;
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
use serde::{Deserialize, Serialize};
|
||||
use cuprate_helper::{
|
||||
fs::{path_with_network, CUPRATE_TXPOOL_DIR},
|
||||
network::Network,
|
||||
};
|
||||
|
||||
/// The default transaction pool weight limit.
|
||||
const DEFAULT_TXPOOL_WEIGHT_LIMIT: usize = 600 * 1024 * 1024;
|
||||
|
@ -21,8 +24,10 @@ const DEFAULT_TXPOOL_WEIGHT_LIMIT: usize = 600 * 1024 * 1024;
|
|||
#[derive(Debug, Clone, PartialEq, PartialOrd)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
pub struct ConfigBuilder {
|
||||
network: Network,
|
||||
|
||||
/// [`Config::db_directory`].
|
||||
db_directory: Option<Cow<'static, Path>>,
|
||||
db_directory: Option<PathBuf>,
|
||||
|
||||
/// [`Config::cuprate_database_config`].
|
||||
db_config: cuprate_database::config::ConfigBuilder,
|
||||
|
@ -41,10 +46,12 @@ impl ConfigBuilder {
|
|||
/// after this function to use default values.
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
network: Network::default(),
|
||||
db_directory: None,
|
||||
db_config: cuprate_database::config::ConfigBuilder::new(Cow::Borrowed(
|
||||
&*CUPRATE_TXPOOL_DIR,
|
||||
)),
|
||||
db_config: cuprate_database::config::ConfigBuilder::new(Cow::Owned(path_with_network(
|
||||
&CUPRATE_TXPOOL_DIR,
|
||||
Network::default(),
|
||||
))),
|
||||
reader_threads: None,
|
||||
max_txpool_weight: None,
|
||||
}
|
||||
|
@ -62,7 +69,7 @@ impl ConfigBuilder {
|
|||
// in `helper::fs`. No need to do them here.
|
||||
let db_directory = self
|
||||
.db_directory
|
||||
.unwrap_or_else(|| Cow::Borrowed(&*CUPRATE_TXPOOL_DIR));
|
||||
.unwrap_or_else(|| CUPRATE_TXPOOL_DIR.to_path_buf());
|
||||
|
||||
let reader_threads = self.reader_threads.unwrap_or_default();
|
||||
|
||||
|
@ -72,7 +79,7 @@ impl ConfigBuilder {
|
|||
|
||||
let db_config = self
|
||||
.db_config
|
||||
.db_directory(db_directory)
|
||||
.db_directory(Cow::Owned(path_with_network(&db_directory, self.network)))
|
||||
.reader_threads(reader_threads.as_threads())
|
||||
.build();
|
||||
|
||||
|
@ -83,6 +90,13 @@ impl ConfigBuilder {
|
|||
}
|
||||
}
|
||||
|
||||
/// Change the network this blockchain 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.
|
||||
#[must_use]
|
||||
pub const fn max_txpool_weight(mut self, max_txpool_weight: usize) -> Self {
|
||||
|
@ -92,7 +106,7 @@ impl ConfigBuilder {
|
|||
|
||||
/// Set a custom database directory (and file) [`Path`].
|
||||
#[must_use]
|
||||
pub fn db_directory(mut self, db_directory: Cow<'static, Path>) -> Self {
|
||||
pub fn db_directory(mut self, db_directory: PathBuf) -> Self {
|
||||
self.db_directory = Some(db_directory);
|
||||
self
|
||||
}
|
||||
|
@ -149,10 +163,13 @@ impl ConfigBuilder {
|
|||
|
||||
impl Default for ConfigBuilder {
|
||||
fn default() -> Self {
|
||||
let db_directory = Cow::Borrowed(CUPRATE_TXPOOL_DIR.as_path());
|
||||
Self {
|
||||
db_directory: Some(db_directory.clone()),
|
||||
db_config: cuprate_database::config::ConfigBuilder::new(db_directory),
|
||||
network: Network::default(),
|
||||
db_directory: Some(CUPRATE_TXPOOL_DIR.to_path_buf()),
|
||||
db_config: cuprate_database::config::ConfigBuilder::new(Cow::Owned(path_with_network(
|
||||
&CUPRATE_TXPOOL_DIR,
|
||||
Network::default(),
|
||||
))),
|
||||
reader_threads: Some(ReaderThreads::default()),
|
||||
max_txpool_weight: Some(DEFAULT_TXPOOL_WEIGHT_LIMIT),
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue