use std::{
net::IpAddr,
path::{Path, PathBuf},
time::Duration,
};
use config::Config;
use serde::{Deserialize, Serialize};
use tari_common::{
ConfigurationError,
DefaultConfigLoader,
SubConfigPath,
configuration::{
CommonConfig,
ConfigList,
Network,
StringList,
bootstrap::wallet_http_service_default_port,
serializers,
serializers::optional_seconds,
},
};
use tari_common_types::grpc_authentication::GrpcAuthentication;
use tari_comms::multiaddr::Multiaddr;
use tari_core::{
base_node::BaseNodeStateMachineConfig,
chain_storage::BlockchainDatabaseConfig,
mempool::MempoolConfig,
};
use tari_p2p::{P2pConfig, PeerSeedsConfig, auto_update::AutoUpdateConfig};
use tari_storage::lmdb_store::LMDBConfig;
use tari_transaction_components::transaction_components::RangeProofType;
use url::Url;
#[cfg(feature = "metrics")]
use crate::metrics::MetricsConfig;
use crate::{HttpCacheConfig, grpc_method::GrpcMethod};
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct ApplicationConfig {
pub common: CommonConfig,
pub auto_update: AutoUpdateConfig,
pub base_node: BaseNodeConfig,
pub peer_seeds: PeerSeedsConfig,
#[cfg(feature = "metrics")]
pub metrics: MetricsConfig,
}
impl ApplicationConfig {
pub fn load_from(cfg: &Config) -> Result<Self, ConfigurationError> {
let mut config = Self {
common: CommonConfig::load_from(cfg)?,
auto_update: AutoUpdateConfig::load_from(cfg)?,
peer_seeds: PeerSeedsConfig::load_from(cfg)?,
base_node: BaseNodeConfig::load_from(cfg)?,
#[cfg(feature = "metrics")]
metrics: MetricsConfig::load_from(cfg)?,
};
config.base_node.set_base_path(config.common.base_path());
Ok(config)
}
pub fn network(&self) -> Network {
self.base_node.network
}
}
#[derive(Clone, Serialize, Deserialize, Debug)]
#[serde(deny_unknown_fields)]
#[allow(clippy::struct_excessive_bools)]
pub struct BaseNodeConfig {
override_from: Option<String>,
pub network: Network,
pub grpc_enabled: bool,
pub grpc_address: Option<Multiaddr>,
pub grpc_server_allow_methods: ConfigList<GrpcMethod>,
pub grpc_authentication: GrpcAuthentication,
pub grpc_tls_enabled: bool,
pub grpc_readiness_enabled: bool,
pub mining_enabled: bool,
pub second_layer_grpc_enabled: bool,
pub identity_file: PathBuf,
pub use_libtor: bool,
pub tor_identity_file: PathBuf,
pub db_type: DatabaseType,
pub lmdb: LMDBConfig,
pub data_dir: PathBuf,
pub config_dir: PathBuf,
pub lmdb_path: PathBuf,
pub max_randomx_vms: usize,
pub bypass_range_proof_verification: bool,
pub p2p: P2pConfig,
pub force_sync_peers: StringList,
pub monitored_peers: StringList,
#[serde(with = "serializers::seconds")]
pub messaging_request_timeout: Duration,
pub storage: BlockchainDatabaseConfig,
pub mempool: MempoolConfig,
#[serde(with = "serializers::seconds")]
pub status_line_interval: Duration,
pub buffer_size: usize,
#[serde(with = "serializers::seconds")]
pub metadata_auto_ping_interval: Duration,
pub state_machine: BaseNodeStateMachineConfig,
pub report_grpc_error: bool,
#[serde(with = "serializers::seconds")]
pub tari_pulse_interval: Duration,
#[serde(with = "optional_seconds")]
pub tari_pulse_health_check: Option<Duration>,
pub http_wallet_query_service: WalletHttpServiceConfig,
pub xmrig_proxy_enabled: bool,
pub xmrig_proxy_address: Multiaddr,
pub xmrig_proxy_wallet_payment_address: String,
pub xmrig_proxy_coinbase_extra: String,
pub xmrig_proxy_range_proof_type: RangeProofType,
}
#[derive(Clone, Serialize, Deserialize, Debug)]
pub struct WalletHttpServiceConfig {
pub port: u16,
#[serde(default)]
pub listen_ip: Option<IpAddr>,
pub external_address: Option<Url>,
#[serde(default)]
pub http_cache: HttpCacheConfig,
}
impl Default for WalletHttpServiceConfig {
fn default() -> Self {
let port = wallet_http_service_default_port(Network::get_current());
Self {
port,
listen_ip: None,
external_address: Some(
Url::parse(format!("http://127.0.0.1:{port}").as_str()).expect("This should be a valid URL"),
),
http_cache: Default::default(),
}
}
}
impl Default for BaseNodeConfig {
fn default() -> Self {
let p2p = P2pConfig {
datastore_path: PathBuf::from("peer_db/base_node"),
..Default::default()
};
Self {
override_from: None,
network: Network::default(),
grpc_enabled: true,
grpc_address: None,
grpc_server_allow_methods: vec![GrpcMethod::GetVersion].into(),
grpc_authentication: GrpcAuthentication::default(),
grpc_tls_enabled: false,
grpc_readiness_enabled: true,
mining_enabled: false,
second_layer_grpc_enabled: false,
identity_file: PathBuf::from("config/base_node_id.json"),
use_libtor: true,
tor_identity_file: PathBuf::from("config/base_node_tor_id.json"),
p2p,
db_type: DatabaseType::Lmdb,
lmdb: Default::default(),
data_dir: PathBuf::from("data/base_node"),
config_dir: PathBuf::from("config/base_node"),
lmdb_path: PathBuf::from("db"),
max_randomx_vms: 5,
bypass_range_proof_verification: false,
force_sync_peers: StringList::default(),
monitored_peers: StringList::default(),
messaging_request_timeout: Duration::from_secs(60),
storage: Default::default(),
mempool: Default::default(),
status_line_interval: Duration::from_secs(5),
buffer_size: 1_500,
metadata_auto_ping_interval: Duration::from_secs(30),
state_machine: Default::default(),
report_grpc_error: false,
tari_pulse_interval: Duration::from_secs(120),
tari_pulse_health_check: None,
http_wallet_query_service: Default::default(),
xmrig_proxy_enabled: false,
xmrig_proxy_address: "/ip4/127.0.0.1/tcp/18085".parse().unwrap(),
xmrig_proxy_wallet_payment_address: String::new(),
xmrig_proxy_coinbase_extra: "tari_base_node_xmrig".to_string(),
xmrig_proxy_range_proof_type: RangeProofType::RevealedValue,
}
}
}
impl SubConfigPath for BaseNodeConfig {
fn main_key_prefix() -> &'static str {
"base_node"
}
}
impl BaseNodeConfig {
pub fn set_base_path<P: AsRef<Path>>(&mut self, base_path: P) {
if !self.identity_file.is_absolute() {
self.identity_file = base_path.as_ref().join(self.identity_file.as_path());
}
if !self.tor_identity_file.is_absolute() {
self.tor_identity_file = base_path.as_ref().join(self.tor_identity_file.as_path());
}
if !self.data_dir.is_absolute() {
self.data_dir = base_path.as_ref().join(self.data_dir.as_path());
}
if !self.config_dir.is_absolute() {
self.config_dir = base_path.as_ref().join(self.config_dir.as_path());
}
if !self.lmdb_path.is_absolute() {
self.lmdb_path = self.data_dir.join(self.lmdb_path.as_path());
}
self.p2p.set_base_path(base_path);
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum DatabaseType {
Lmdb,
}