mod node_key;
mod priv_validator_key;
pub use self::{node_key::NodeKey, priv_validator_key::PrivValidatorKey};
use crate::{
abci::tag,
error::{Error, ErrorKind},
genesis::Genesis,
net, node, Moniker, Timeout,
};
use serde::{de, de::Error as _, ser, Deserialize, Serialize};
use std::{
collections::BTreeMap,
fmt, fs,
path::{Path, PathBuf},
str::FromStr,
};
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct TendermintConfig {
pub proxy_app: net::Address,
pub moniker: Moniker,
pub fast_sync: bool,
pub db_backend: DbBackend,
pub db_dir: PathBuf,
pub log_level: LogLevel,
pub log_format: LogFormat,
pub genesis_file: PathBuf,
pub priv_validator_key_file: Option<PathBuf>,
pub priv_validator_state_file: PathBuf,
#[serde(deserialize_with = "deserialize_optional_value")]
pub priv_validator_laddr: Option<net::Address>,
pub node_key_file: PathBuf,
pub abci: AbciMode,
#[serde(deserialize_with = "deserialize_optional_value")]
pub prof_laddr: Option<net::Address>,
pub filter_peers: bool,
pub rpc: RpcConfig,
pub p2p: P2PConfig,
pub mempool: MempoolConfig,
pub consensus: ConsensusConfig,
pub tx_index: TxIndexConfig,
pub instrumentation: InstrumentationConfig,
}
impl TendermintConfig {
pub fn parse_toml<T: AsRef<str>>(toml_string: T) -> Result<Self, Error> {
Ok(toml::from_str(toml_string.as_ref())?)
}
pub fn load_toml_file<P>(path: &P) -> Result<Self, Error>
where
P: AsRef<Path>,
{
let toml_string = fs::read_to_string(path).map_err(|e| {
err!(
ErrorKind::Parse,
"couldn't open {}: {}",
path.as_ref().display(),
e
)
})?;
Self::parse_toml(toml_string)
}
pub fn load_genesis_file(&self, home: impl AsRef<Path>) -> Result<Genesis, Error> {
let path = home.as_ref().join(&self.genesis_file);
let genesis_json = fs::read_to_string(&path)
.map_err(|e| err!(ErrorKind::Parse, "couldn't open {}: {}", path.display(), e))?;
Ok(serde_json::from_str(genesis_json.as_ref())?)
}
pub fn load_node_key(&self, home: impl AsRef<Path>) -> Result<NodeKey, Error> {
let path = home.as_ref().join(&self.node_key_file);
NodeKey::load_json_file(&path)
}
}
#[derive(Copy, Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
pub enum DbBackend {
#[serde(rename = "leveldb")]
LevelDb,
#[serde(rename = "memdb")]
MemDb,
#[serde(rename = "cleveldb")]
CLevelDb,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct LogLevel(BTreeMap<String, String>);
impl LogLevel {
pub fn get<S>(&self, key: S) -> Option<&str>
where
S: AsRef<str>,
{
self.0.get(key.as_ref()).map(AsRef::as_ref)
}
pub fn iter(&self) -> LogLevelIter {
self.0.iter()
}
}
pub type LogLevelIter<'a> = std::collections::btree_map::Iter<'a, String, String>;
impl FromStr for LogLevel {
type Err = Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let mut levels = BTreeMap::new();
for level in s.split(',') {
let parts = level.split(':').collect::<Vec<_>>();
if parts.len() != 2 {
Err(err!(ErrorKind::Parse, "error parsing log level: {}", level))?;
}
let key = parts[0].to_owned();
let value = parts[1].to_owned();
if levels.insert(key, value).is_some() {
Err(err!(
ErrorKind::Parse,
"duplicate log level setting for: {}",
level
))?;
}
}
Ok(LogLevel(levels))
}
}
impl fmt::Display for LogLevel {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
for (i, (k, v)) in self.0.iter().enumerate() {
write!(f, "{}:{}", k, v)?;
if i < self.0.len() - 1 {
write!(f, ",")?;
}
}
Ok(())
}
}
impl<'de> Deserialize<'de> for LogLevel {
fn deserialize<D: de::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
let levels = String::deserialize(deserializer)?;
Ok(Self::from_str(&levels).map_err(|e| D::Error::custom(format!("{}", e)))?)
}
}
impl Serialize for LogLevel {
fn serialize<S: ser::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
self.to_string().serialize(serializer)
}
}
#[derive(Copy, Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
pub enum LogFormat {
#[serde(rename = "plain")]
Plain,
#[serde(rename = "json")]
Json,
}
#[derive(Copy, Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
pub enum AbciMode {
#[serde(rename = "socket")]
Socket,
#[serde(rename = "grpc")]
Grpc,
}
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct RpcConfig {
pub laddr: net::Address,
pub cors_allowed_origins: Vec<CorsOrigin>,
pub cors_allowed_methods: Vec<CorsMethod>,
pub cors_allowed_headers: Vec<CorsHeader>,
#[serde(deserialize_with = "deserialize_optional_value")]
pub grpc_laddr: Option<net::Address>,
pub grpc_max_open_connections: u64,
#[serde(rename = "unsafe")]
pub unsafe_commands: bool,
pub max_open_connections: u64,
pub max_subscription_clients: u64,
pub max_subscriptions_per_client: u64,
pub timeout_broadcast_tx_commit: Timeout,
#[serde(deserialize_with = "deserialize_optional_value")]
pub tls_cert_file: Option<PathBuf>,
#[serde(deserialize_with = "deserialize_optional_value")]
pub tls_key_file: Option<PathBuf>,
}
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct CorsOrigin(String);
impl AsRef<str> for CorsOrigin {
fn as_ref(&self) -> &str {
self.0.as_ref()
}
}
impl fmt::Display for CorsOrigin {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", &self.0)
}
}
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct CorsMethod(String);
impl AsRef<str> for CorsMethod {
fn as_ref(&self) -> &str {
self.0.as_ref()
}
}
impl fmt::Display for CorsMethod {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", &self.0)
}
}
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct CorsHeader(String);
impl AsRef<str> for CorsHeader {
fn as_ref(&self) -> &str {
self.0.as_ref()
}
}
impl fmt::Display for CorsHeader {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", &self.0)
}
}
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct P2PConfig {
pub laddr: net::Address,
#[serde(deserialize_with = "deserialize_optional_value")]
pub external_address: Option<net::Address>,
#[serde(
serialize_with = "serialize_comma_separated_list",
deserialize_with = "deserialize_comma_separated_list"
)]
pub seeds: Vec<net::Address>,
#[serde(
serialize_with = "serialize_comma_separated_list",
deserialize_with = "deserialize_comma_separated_list"
)]
pub persistent_peers: Vec<net::Address>,
pub upnp: bool,
pub addr_book_file: PathBuf,
pub addr_book_strict: bool,
pub max_num_inbound_peers: u64,
pub max_num_outbound_peers: u64,
pub flush_throttle_timeout: Timeout,
pub max_packet_msg_payload_size: u64,
pub send_rate: TransferRate,
pub recv_rate: TransferRate,
pub pex: bool,
pub seed_mode: bool,
#[serde(
serialize_with = "serialize_comma_separated_list",
deserialize_with = "deserialize_comma_separated_list"
)]
pub private_peer_ids: Vec<node::Id>,
pub allow_duplicate_ip: bool,
pub handshake_timeout: Timeout,
pub dial_timeout: Timeout,
}
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct MempoolConfig {
pub recheck: bool,
pub broadcast: bool,
#[serde(deserialize_with = "deserialize_optional_value")]
pub wal_dir: Option<PathBuf>,
pub size: u64,
pub max_txs_bytes: u64,
pub cache_size: u64,
}
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct ConsensusConfig {
pub wal_file: PathBuf,
pub timeout_propose: Timeout,
pub timeout_propose_delta: Timeout,
pub timeout_prevote: Timeout,
pub timeout_prevote_delta: Timeout,
pub timeout_precommit: Timeout,
pub timeout_precommit_delta: Timeout,
pub timeout_commit: Timeout,
pub skip_timeout_commit: bool,
pub create_empty_blocks: bool,
pub create_empty_blocks_interval: Timeout,
pub peer_gossip_sleep_duration: Timeout,
pub peer_query_maj23_sleep_duration: Timeout,
}
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct TxIndexConfig {
#[serde(default)]
pub indexer: TxIndexer,
#[serde(
serialize_with = "serialize_comma_separated_list",
deserialize_with = "deserialize_comma_separated_list"
)]
pub index_tags: Vec<tag::Key>,
pub index_all_tags: bool,
}
#[derive(Copy, Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
pub enum TxIndexer {
#[serde(rename = "null")]
Null,
#[serde(rename = "kv")]
Kv,
}
impl Default for TxIndexer {
fn default() -> TxIndexer {
TxIndexer::Kv
}
}
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct InstrumentationConfig {
pub prometheus: bool,
pub prometheus_listen_addr: String,
pub max_open_connections: u64,
pub namespace: String,
}
#[derive(Copy, Clone, Debug, Deserialize, Serialize)]
pub struct TransferRate(u64);
impl TransferRate {
pub fn bytes_per_sec(self) -> u64 {
self.0
}
}
fn deserialize_optional_value<'de, D, T, E>(deserializer: D) -> Result<Option<T>, D::Error>
where
D: de::Deserializer<'de>,
T: FromStr<Err = E>,
E: fmt::Display,
{
let string = String::deserialize(deserializer)?;
if string.is_empty() {
return Ok(None);
}
string
.parse()
.map(Some)
.map_err(|e| D::Error::custom(format!("{}", e)))
}
fn deserialize_comma_separated_list<'de, D, T, E>(deserializer: D) -> Result<Vec<T>, D::Error>
where
D: de::Deserializer<'de>,
T: FromStr<Err = E>,
E: fmt::Display,
{
let mut result = vec![];
let string = String::deserialize(deserializer)?;
if string.is_empty() {
return Ok(result);
}
for item in string.split(',') {
result.push(
item.parse()
.map_err(|e| D::Error::custom(format!("{}", e)))?,
);
}
Ok(result)
}
fn serialize_comma_separated_list<S, T>(list: &[T], serializer: S) -> Result<S::Ok, S::Error>
where
S: ser::Serializer,
T: ToString,
{
let str_list = list.iter().map(|addr| addr.to_string()).collect::<Vec<_>>();
str_list.join(",").serialize(serializer)
}