diff --git a/Cargo.lock b/Cargo.lock index 8edfbfc5495..cb530583859 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1800,6 +1800,7 @@ dependencies = [ "color-eyre", "dialoguer", "iroha_client", + "iroha_config", "iroha_crypto", "iroha_data_model", "serde_json", @@ -1808,6 +1809,25 @@ dependencies = [ [[package]] name = "iroha_config" version = "2.0.0-pre-rc.5" +dependencies = [ + "crossbeam", + "derive_more", + "eyre", + "iroha_config_base", + "iroha_crypto", + "iroha_data_model", + "iroha_primitives", + "serde", + "serde_json", + "thiserror", + "tracing", + "tracing-subscriber 0.3.11", + "url", +] + +[[package]] +name = "iroha_config_base" +version = "2.0.0-pre-rc.5" dependencies = [ "crossbeam", "derive_more", @@ -1988,6 +2008,7 @@ dependencies = [ "color-eyre", "derive_more", "iroha_config", + "iroha_data_model", "once_cell", "serde", "serde_json", @@ -2104,6 +2125,7 @@ dependencies = [ "eyre", "futures", "iroha_config", + "iroha_data_model", "iroha_futures", "iroha_logger", "iroha_telemetry_derive", @@ -2226,7 +2248,6 @@ version = "2.0.0-pre-rc.5" dependencies = [ "clap 3.1.18", "color-eyre", - "iroha", "iroha_config", "iroha_core", "iroha_crypto", @@ -3630,6 +3651,7 @@ dependencies = [ "iroha", "iroha_actor", "iroha_client", + "iroha_config", "iroha_core", "iroha_data_model", "iroha_logger", diff --git a/Cargo.toml b/Cargo.toml index 1a6377b343d..42b1aa7c584 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,7 +8,8 @@ members = [ "client", "client_cli", "config", - "config/derive", + "config/base", + "config/base/derive", "core", "core/test_network", "crypto", diff --git a/cli/src/config.rs b/cli/src/config.rs deleted file mode 100644 index f1f610f2945..00000000000 --- a/cli/src/config.rs +++ /dev/null @@ -1,178 +0,0 @@ -//! This module contains [`Configuration`] structure and related implementation. -use std::{fmt::Debug, fs::File, io::BufReader, path::Path}; - -use eyre::{Result, WrapErr}; -use iroha_config::derive::Configurable; -use iroha_core::{ - block_sync::config::BlockSyncConfiguration, genesis::config::GenesisConfiguration, - kura::config::KuraConfiguration, queue::Configuration as QueueConfiguration, - sumeragi::config::SumeragiConfiguration, - wsv::config::Configuration as WorldStateViewConfiguration, -}; -use iroha_crypto::prelude::*; -use iroha_data_model::prelude::*; -use iroha_logger::Configuration as LoggerConfiguration; -use serde::{Deserialize, Serialize}; - -use super::torii::config::ToriiConfiguration; - -/// Configuration parameters container. -#[derive(Debug, Clone, Deserialize, Serialize, Configurable)] -#[serde(default)] -#[serde(rename_all = "UPPERCASE")] -#[config(env_prefix = "IROHA_")] -pub struct Configuration { - /// Public key of this peer. - #[config(serde_as_str)] - pub public_key: PublicKey, - /// Private key of this peer. - pub private_key: PrivateKey, - /// Disable coloring of the backtrace and error report on panic. - pub disable_panic_terminal_colors: bool, - /// Iroha will shutdown on any panic if this option is set to `true`. - pub shutdown_on_panic: bool, - /// `Kura` related configuration. - #[config(inner)] - pub kura: KuraConfiguration, - /// `Sumeragi` related configuration. - #[config(inner)] - pub sumeragi: SumeragiConfiguration, - /// `Torii` related configuration. - #[config(inner)] - pub torii: ToriiConfiguration, - /// `BlockSynchronizer` configuration. - #[config(inner)] - pub block_sync: BlockSyncConfiguration, - /// `Queue` configuration. - #[config(inner)] - pub queue: QueueConfiguration, - /// `Logger` configuration. - #[config(inner)] - pub logger: LoggerConfiguration, - /// Configuration for `GenesisBlock`. - #[config(inner)] - pub genesis: GenesisConfiguration, - /// Configuration for `WorldStateView`. - #[config(inner)] - pub wsv: WorldStateViewConfiguration, - /// Network configuration - #[config(inner)] - pub network: NetworkConfiguration, - /// Configuration for telemetry - #[config(inner)] - #[cfg(feature = "telemetry")] - pub telemetry: iroha_telemetry::Configuration, -} - -impl Default for Configuration { - fn default() -> Self { - let sumeragi_configuration = SumeragiConfiguration::default(); - let (public_key, private_key) = sumeragi_configuration.key_pair.clone().into(); - - Self { - public_key, - private_key, - disable_panic_terminal_colors: bool::default(), - shutdown_on_panic: false, - kura: KuraConfiguration::default(), - sumeragi: sumeragi_configuration, - torii: ToriiConfiguration::default(), - block_sync: BlockSyncConfiguration::default(), - queue: QueueConfiguration::default(), - logger: LoggerConfiguration::default(), - genesis: GenesisConfiguration::default(), - wsv: WorldStateViewConfiguration::default(), - network: NetworkConfiguration::default(), - #[cfg(feature = "telemetry")] - telemetry: iroha_telemetry::Configuration::default(), - } - } -} - -/// Network Configuration parameters container. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize, Configurable)] -#[serde(default)] -#[serde(rename_all = "UPPERCASE")] -#[config(env_prefix = "IROHA_NETWORK_")] -pub struct NetworkConfiguration { - /// Buffer capacity of actor's MPSC channel - pub actor_channel_capacity: u32, -} - -const DEFAULT_ACTOR_CHANNEL_CAPACITY: u32 = 100; - -impl Default for NetworkConfiguration { - fn default() -> Self { - Self { - actor_channel_capacity: DEFAULT_ACTOR_CHANNEL_CAPACITY, - } - } -} - -impl Configuration { - /// Construct [`Self`] from a path-like object. - /// - /// # Errors - /// - File not found. - /// - File found, but peer configuration parsing failed. - /// - Length of the array in raw json representation is different - /// to the lenght of the array in - /// [`self.sumeragi.trusted_peers.peers`], most likely due to two - /// (or more) peers having the same public key. - pub fn from_path + Debug + Clone>(path: P) -> Result { - let file = File::open(path.clone()) - .wrap_err(format!("Failed to open the config file {:?}", path))?; - let reader = BufReader::new(file); - let mut configuration: Configuration = serde_json::from_reader(reader).wrap_err( - format!("Failed to parse {:?} as Iroha peer configuration.", path), - )?; - configuration.finalize()?; - Ok(configuration) - } - - fn finalize(&mut self) -> Result<()> { - self.sumeragi.key_pair = KeyPair::new(self.public_key.clone(), self.private_key.clone())?; - self.sumeragi.peer_id = PeerId::new(&self.torii.p2p_addr, &self.public_key.clone()); - - Ok(()) - } - - /// Loads configuration from environment - /// - /// # Errors - /// If Configuration deserialize fails: - /// - Configuration `TrustedPeers` contains entries with duplicate public keys - pub fn load_environment(&mut self) -> Result<()> { - iroha_config::Configurable::load_environment(self)?; - self.finalize()?; - Ok(()) - } -} - -#[cfg(test)] -mod tests { - #![allow(clippy::restriction)] - - use iroha_core::sumeragi::config::TrustedPeers; - - use super::*; - - const CONFIGURATION_PATH: &str = "../configs/peer/config.json"; - - #[test] - fn parse_example_json() -> Result<()> { - let configuration = Configuration::from_path(CONFIGURATION_PATH) - .wrap_err("Failed to read configuration from example config")?; - assert_eq!("127.0.0.1:1337", configuration.torii.p2p_addr); - assert_eq!(1000, configuration.sumeragi.block_time_ms); - Ok(()) - } - - #[test] - #[should_panic] - fn parse_trusted_peers_fail_duplicate_peer_id() { - let trusted_peers_string = r#"[{"address":"127.0.0.1:1337", "public_key": "ed0120954c83a4220faffb2c1d23fc5225b3e7952d53acbb2a065ff30c631e5e1d6b10"}, {"address":"127.0.0.1:1337", "public_key": "ed0120954c83a4220faffb2c1d23fc5225b3e7952d53acbb2a065ff30c631e5e1d6b10"}, {"address":"localhost:1338", "public_key": "ed0120954c83a4220faffb2c1d23fc5225b3e7952d53acbb2a065ff30c631e5e1d6b10"}, {"address": "195.162.0.1:23", "public_key": "ed0120954c83a4220faffb2c1d23fc5225b3e7952d53acbb2a065ff30c631e5e1d6b10"}]"#; - let _result: TrustedPeers = - serde_json::from_str(trusted_peers_string).expect("Failed to parse Trusted Peers"); - } -} diff --git a/cli/src/lib.rs b/cli/src/lib.rs index baaf41a3560..ffe28501889 100644 --- a/cli/src/lib.rs +++ b/cli/src/lib.rs @@ -7,8 +7,8 @@ use std::{panic, path::PathBuf, sync::Arc}; use color_eyre::eyre::{eyre, Result, WrapErr}; -use config::Configuration; use iroha_actor::{broker::*, prelude::*}; +use iroha_config::iroha::Configuration; use iroha_core::{ block_sync::{BlockSynchronizer, BlockSynchronizerTrait}, genesis::{GenesisNetwork, GenesisNetworkTrait, RawGenesisBlock}, @@ -28,7 +28,6 @@ use tokio::{ }; use torii::Torii; -pub mod config; mod event; pub mod samples; mod stream; @@ -360,7 +359,7 @@ where /// /// # Errors /// - Genesis account public key not specified. -fn domains(configuration: &config::Configuration) -> [Domain; 1] { +fn domains(configuration: &Configuration) -> [Domain; 1] { let key = configuration.genesis.account_public_key.clone(); [Domain::from(GenesisDomain::new(key))] } diff --git a/cli/src/samples.rs b/cli/src/samples.rs index 40759b331c4..64d4408ee81 100644 --- a/cli/src/samples.rs +++ b/cli/src/samples.rs @@ -2,23 +2,20 @@ //! This module contains the sample configurations used for testing and benchmarking throghout Iroha. use std::{collections::HashSet, str::FromStr}; -use iroha_core::{ - block_sync::config::BlockSyncConfiguration, - genesis::config::GenesisConfiguration, - kura::config::KuraConfiguration, +use iroha_config::{ + block_sync::Configuration as BlockSyncConfiguration, + genesis::Configuration as GenesisConfiguration, + iroha::Configuration, + kura::Configuration as KuraConfiguration, queue::Configuration as QueueConfiguration, - smartcontracts::wasm::config::Configuration as WasmConfiguration, - sumeragi::config::{SumeragiConfiguration, TrustedPeers}, - wsv::config::Configuration as WsvConfiguration, + sumeragi::{Configuration as SumeragiConfiguration, TrustedPeers}, + torii::{Configuration as ToriiConfiguration, DEFAULT_TORII_P2P_ADDR}, + wasm::Configuration as WasmConfiguration, + wsv::Configuration as WsvConfiguration, }; use iroha_crypto::{KeyPair, PublicKey}; use iroha_data_model::peer::Id as PeerId; -use crate::{ - config::Configuration, - torii::config::{ToriiConfiguration, DEFAULT_TORII_P2P_ADDR}, -}; - /// Get sample trusted peers. The public key must be the same as `configuration.public_key` /// /// # Panics @@ -72,7 +69,7 @@ pub fn get_config(trusted_peers: HashSet, key_pair: Option) -> public_key: public_key.clone(), private_key: private_key.clone(), kura: KuraConfiguration { - init_mode: iroha_core::kura::Mode::Strict, + init_mode: iroha_config::kura::Mode::Strict, block_store_path: "./blocks".into(), ..KuraConfiguration::default() }, diff --git a/cli/src/torii/config.rs b/cli/src/torii/config.rs deleted file mode 100644 index 9e719cdf3d8..00000000000 --- a/cli/src/torii/config.rs +++ /dev/null @@ -1,45 +0,0 @@ -//! Configuration as well as the default values for the URLs used for the main endpoints: `p2p`, `telemetry`, but not `api`. -use iroha_config::derive::Configurable; -use iroha_data_model::uri::DEFAULT_API_URL; -use serde::{Deserialize, Serialize}; - -/// Default socket for p2p communication -pub const DEFAULT_TORII_P2P_ADDR: &str = "127.0.0.1:1337"; -/// Default socket for reporting internal status and metrics -pub const DEFAULT_TORII_TELEMETRY_URL: &str = "127.0.0.1:8180"; -/// Default maximum size of single transaction -pub const DEFAULT_TORII_MAX_TRANSACTION_SIZE: u32 = 2_u32.pow(15); -/// Default upper bound on `content-length` specified in the HTTP request header -pub const DEFAULT_TORII_MAX_CONTENT_LENGTH: u32 = 2_u32.pow(12) * 4000; - -/// Structure that defines the configuration parameters of `Torii` which is the routing module. -/// For example the `p2p_addr`, which is used for consensus and block-synchronisation purposes, -/// as well as `max_transaction_size`. -#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize, Configurable)] -#[serde(rename_all = "UPPERCASE")] -#[serde(default)] -#[config(env_prefix = "TORII_")] -pub struct ToriiConfiguration { - /// Torii URL for p2p communication for consensus and block synchronization purposes. - pub p2p_addr: String, - /// Torii URL for client API. - pub api_url: String, - /// Torii URL for reporting internal status and metrics for administration. - pub telemetry_url: String, - /// Maximum number of bytes in raw transaction. Used to prevent from DOS attacks. - pub max_transaction_size: u32, - /// Maximum number of bytes in raw message. Used to prevent from DOS attacks. - pub max_content_len: u32, -} - -impl Default for ToriiConfiguration { - fn default() -> Self { - Self { - p2p_addr: DEFAULT_TORII_P2P_ADDR.to_owned(), - api_url: DEFAULT_API_URL.to_owned(), - telemetry_url: DEFAULT_TORII_TELEMETRY_URL.to_owned(), - max_transaction_size: DEFAULT_TORII_MAX_TRANSACTION_SIZE, - max_content_len: DEFAULT_TORII_MAX_CONTENT_LENGTH, - } - } -} diff --git a/cli/src/torii/mod.rs b/cli/src/torii/mod.rs index 9ed0dc39e47..5bd1eb5db40 100644 --- a/cli/src/torii/mod.rs +++ b/cli/src/torii/mod.rs @@ -24,7 +24,6 @@ use warp::{ #[macro_use] pub(crate) mod utils; -pub mod config; pub mod routing; /// Main network handler and the only entrypoint of the Iroha. @@ -74,7 +73,7 @@ pub enum Error { Status(#[from] iroha_actor::Error), /// Configuration change error. #[error("Attempt to change configuration failed")] - ConfigurationReload(#[from] iroha_config::runtime_upgrades::ReloadError), + ConfigurationReload(#[from] iroha_config::base::runtime_upgrades::ReloadError), #[cfg(feature = "telemetry")] /// Error while getting Prometheus metrics #[error("Failed to produce Prometheus metrics: {0}")] diff --git a/cli/src/torii/routing.rs b/cli/src/torii/routing.rs index b8fdec1ad7d..2e86f43de06 100644 --- a/cli/src/torii/routing.rs +++ b/cli/src/torii/routing.rs @@ -6,7 +6,9 @@ use std::num::TryFromIntError; use eyre::WrapErr; use iroha_actor::Addr; -use iroha_config::{Configurable, GetConfiguration, PostConfiguration}; +use iroha_config::{ + base::Configurable, iroha::ConfigurationView, torii::uri, GetConfiguration, PostConfiguration, +}; use iroha_core::{ block::stream::{ BlockPublisherMessage, BlockSubscriberMessage, VersionedBlockPublisherMessage, @@ -189,7 +191,9 @@ async fn handle_get_configuration( .wrap_err("Failed to get docs {:?field}") .and_then(|doc| serde_json::to_value(doc).wrap_err("Failed to serialize docs")) } - Value => serde_json::to_value(iroha_cfg).wrap_err("Failed to serialize value"), + // Cast to configuration view to hide private keys. + Value => serde_json::to_value(ConfigurationView::from(iroha_cfg)) + .wrap_err("Failed to serialize value"), } .map(|v| reply::json(&v)) .map_err(Error::Config) @@ -200,13 +204,13 @@ async fn handle_post_configuration( iroha_cfg: Configuration, cfg: PostConfiguration, ) -> Result { - use iroha_config::runtime_upgrades::Reload; + use iroha_config::base::runtime_upgrades::Reload; use PostConfiguration::*; iroha_logger::debug!(?cfg); match cfg { LogLevel(level) => { - iroha_cfg.logger.max_log_level.reload(level.into())?; + iroha_cfg.logger.max_log_level.reload(level)?; } }; diff --git a/client/benches/torii.rs b/client/benches/torii.rs index dac47d49627..9994de6d31d 100644 --- a/client/benches/torii.rs +++ b/client/benches/torii.rs @@ -5,7 +5,7 @@ use std::thread; use criterion::{criterion_group, criterion_main, Criterion, Throughput}; use iroha::samples::get_config; use iroha_client::client::{asset, Client}; -use iroha_config::runtime_upgrades::Reload; +use iroha_config::{base::runtime_upgrades::Reload, logger}; use iroha_core::{ genesis::{GenesisNetwork, GenesisNetworkTrait, RawGenesisBlock}, prelude::*, @@ -46,7 +46,7 @@ fn query_requests(criterion: &mut Criterion) { configuration .logger .max_log_level - .reload(iroha_logger::Level(iroha_config::logger::Level::ERROR)) + .reload(logger::Level::ERROR) .expect("Should not fail"); let mut group = criterion.benchmark_group("query-requests"); let domain_id: DomainId = "domain".parse().expect("Valid"); diff --git a/client/src/client.rs b/client/src/client.rs index 00eb1f9b4b5..b34dff6226f 100644 --- a/client/src/client.rs +++ b/client/src/client.rs @@ -7,7 +7,7 @@ use std::{ use derive_more::{DebugCustom, Display}; use eyre::{eyre, Result, WrapErr}; use http_default::WebSocketStream; -use iroha_config::{GetConfiguration, PostConfiguration}; +use iroha_config::{client::Configuration, torii::uri, GetConfiguration, PostConfiguration}; use iroha_core::smartcontracts::isi::query::Error as QueryError; use iroha_crypto::{HashOf, KeyPair}; use iroha_data_model::{predicate::PredicateBox, prelude::*, query::SignedQueryRequest}; @@ -20,7 +20,6 @@ use rand::Rng; use serde::de::DeserializeOwned; use crate::{ - config::Configuration, http::{Method as HttpMethod, RequestBuilder, Response, StatusCode}, http_default::{self, DefaultRequestBuilder, WebSocketError, WebSocketMessage}, }; @@ -248,7 +247,7 @@ pub struct Client { torii_url: SmallStr, /// Url to report status for administration telemetry_url: SmallStr, - /// Limits to which transactions must adhere to + /// The limits to which transactions must adhere to transaction_limits: TransactionLimits, /// Accounts keypair key_pair: KeyPair, @@ -1222,8 +1221,9 @@ mod tests { #![allow(clippy::restriction)] use std::str::FromStr; + use iroha_config::client::{BasicAuth, WebLogin}; + use super::*; - use crate::config::{BasicAuth, WebLogin}; const LOGIN: &str = "mad_hatter"; const PASSWORD: &str = "ilovetea"; diff --git a/client/src/lib.rs b/client/src/lib.rs index 3f47b7b1be1..c0a5c21df25 100644 --- a/client/src/lib.rs +++ b/client/src/lib.rs @@ -1,18 +1,17 @@ //! Crate contains iroha client which talks to iroha network via http +use iroha_config::client::Configuration; + /// Module with iroha client itself pub mod client; -/// Module with iroha client config -pub mod config; -pub use config::Configuration; /// Module with general communication primitives like an HTTP request builder. pub mod http; mod http_default; /// Module containing sample configurations for tests and benchmarks. pub mod samples { + use iroha_config::torii::uri; use iroha_crypto::KeyPair; - use iroha_data_model::uri; use super::Configuration; diff --git a/client/tests/integration/mod.rs b/client/tests/integration/mod.rs index 09d3b9d5663..9c10990048a 100644 --- a/client/tests/integration/mod.rs +++ b/client/tests/integration/mod.rs @@ -1,4 +1,4 @@ -pub use iroha::config::Configuration; +pub use iroha_config::iroha::Configuration; mod add_account; mod add_domain; diff --git a/client/tests/integration/multisignature_transaction.rs b/client/tests/integration/multisignature_transaction.rs index 416bd8f14d6..ab857c842de 100644 --- a/client/tests/integration/multisignature_transaction.rs +++ b/client/tests/integration/multisignature_transaction.rs @@ -2,10 +2,8 @@ use std::{str::FromStr as _, thread, time::Duration}; -use iroha_client::{ - client::{self, Client}, - config::Configuration as ClientConfiguration, -}; +use iroha_client::client::{self, Client}; +use iroha_config::client::Configuration as ClientConfiguration; use iroha_core::prelude::*; use iroha_data_model::{account::TRANSACTION_SIGNATORIES_VALUE, prelude::*}; use iroha_primitives::small::SmallStr; diff --git a/client/tests/integration/unstable_network.rs b/client/tests/integration/unstable_network.rs index 38409702332..a2f98afd9ee 100644 --- a/client/tests/integration/unstable_network.rs +++ b/client/tests/integration/unstable_network.rs @@ -3,7 +3,6 @@ use std::{thread, time::Duration}; use iroha_client::client::{self, Client}; -use iroha_config::logger; use iroha_data_model::prelude::*; use iroha_logger::Level; use test_network::*; @@ -64,7 +63,7 @@ fn unstable_network( let (network, mut iroha_client) = rt.block_on(async { let mut configuration = Configuration::test(); configuration.queue.maximum_transactions_in_block = MAXIMUM_TRANSACTIONS_IN_BLOCK; - configuration.logger.max_log_level = Level(logger::Level::ERROR).into(); + configuration.logger.max_log_level = Level::ERROR.into(); let network = ::new_with_offline_peers(Some(configuration), n_peers, n_offline_peers) .await diff --git a/client_cli/Cargo.toml b/client_cli/Cargo.toml index acb9d6f0ddb..d66b9c375ab 100644 --- a/client_cli/Cargo.toml +++ b/client_cli/Cargo.toml @@ -18,6 +18,7 @@ maintenance = { status = "actively-developed" } [dependencies] iroha_client = { version = "=2.0.0-pre-rc.5", path = "../client" } +iroha_config = { version = "=2.0.0-pre-rc.5", path = "../config" } iroha_data_model = { version = "=2.0.0-pre-rc.5", path = "../data_model" } iroha_crypto = { version = "=2.0.0-pre-rc.5", path = "../crypto" } diff --git a/client_cli/src/main.rs b/client_cli/src/main.rs index a7b0428ac2c..a602a15a35f 100644 --- a/client_cli/src/main.rs +++ b/client_cli/src/main.rs @@ -15,7 +15,8 @@ use color_eyre::{ Result, }; use dialoguer::Confirm; -use iroha_client::{client::Client, config::Configuration as ClientConfiguration}; +use iroha_client::client::Client; +use iroha_config::client::Configuration as ClientConfiguration; use iroha_crypto::prelude::*; use iroha_data_model::prelude::*; @@ -190,7 +191,8 @@ pub fn submit( } mod events { - use iroha_client::{client::Client, config::Configuration}; + use iroha_client::client::Client; + use iroha_config::client::Configuration; use super::*; @@ -230,7 +232,8 @@ mod events { } mod domain { - use iroha_client::{client, config::Configuration}; + use iroha_client::client; + use iroha_config::client::Configuration; use super::*; diff --git a/config/Cargo.toml b/config/Cargo.toml index 12b34aefb20..7bde1496e98 100644 --- a/config/Cargo.toml +++ b/config/Cargo.toml @@ -5,7 +5,14 @@ authors = ["Iroha 2 team "] edition = "2021" [dependencies] -iroha_config_derive = { path = "derive" } +iroha_config_base = { path = "base" } +iroha_data_model = { version = "=2.0.0-pre-rc.5", path = "../data_model" } +iroha_primitives = { version = "=2.0.0-pre-rc.5", path = "../primitives" } +iroha_crypto = { version = "=2.0.0-pre-rc.5", path = "../crypto" } +eyre = "0.6.5" +tracing = "0.1.13" +tracing-subscriber = { version = "0.3.0", default-features = false, features = ["fmt", "ansi"] } +url = { version = "2.2.2", features = ["serde"] } serde = { version = "1.0", default-features = false, features = ["derive"] } serde_json = "1.0" diff --git a/config/base/Cargo.toml b/config/base/Cargo.toml new file mode 100644 index 00000000000..bdeee1bcc23 --- /dev/null +++ b/config/base/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "iroha_config_base" +version = "2.0.0-pre-rc.5" +authors = ["Iroha 2 team "] +edition = "2021" + +[dependencies] +iroha_config_derive = { path = "derive" } + +serde = { version = "1.0", default-features = false, features = ["derive"] } +serde_json = "1.0" +thiserror = "1.0.30" +crossbeam = "0.8.1" +derive_more = "0.99.17" diff --git a/config/derive/Cargo.toml b/config/base/derive/Cargo.toml similarity index 100% rename from config/derive/Cargo.toml rename to config/base/derive/Cargo.toml diff --git a/config/derive/src/lib.rs b/config/base/derive/src/lib.rs similarity index 55% rename from config/derive/src/lib.rs rename to config/base/derive/src/lib.rs index 21f2d0b9fcf..0d8dd02c7e8 100644 --- a/config/derive/src/lib.rs +++ b/config/base/derive/src/lib.rs @@ -3,11 +3,11 @@ use proc_macro::TokenStream; use proc_macro2::Span; use proc_macro_error::{abort, abort_call_site}; -use quote::quote; +use quote::{format_ident, quote, ToTokens}; use syn::{ parse::{Parse, ParseStream}, - Data, DataStruct, DeriveInput, Fields, GenericArgument, Ident, Lit, LitStr, Meta, - PathArguments, Token, Type, TypePath, + Attribute, Data, DataStruct, DeriveInput, Field, Fields, GenericArgument, Ident, Lit, LitStr, + Meta, NestedMeta, PathArguments, Token, Type, TypePath, }; struct EnvPrefix { @@ -99,7 +99,7 @@ impl Parse for SerdeAsStr { } } -/// Derive for config. Check other doc in `iroha_config` reexport +/// Derive for config. More details in `iroha_config_base` reexport #[proc_macro_derive(Configurable, attributes(config))] pub fn configurable_derive(input: TokenStream) -> TokenStream { let ast = match syn::parse(input) { @@ -135,12 +135,12 @@ fn impl_load_env( } else if as_str_attr { quote! { #l_value = serde_json::from_value(var.into()) - .map_err(|e| iroha_config::derive::Error::field_error(stringify!(#ident), e))? + .map_err(|e| iroha_config_base::derive::Error::field_error(stringify!(#ident), e))? } } else { quote! { #l_value = serde_json::from_str(&var) - .map_err(|e| iroha_config::derive::Error::field_error(stringify!(#ident), e))? + .map_err(|e| iroha_config_base::derive::Error::field_error(stringify!(#ident), e))? } }; (set_field, l_value) @@ -166,7 +166,7 @@ fn impl_load_env( quote! { fn load_environment( &'_ mut self - ) -> core::result::Result<(), iroha_config::derive::Error> { + ) -> core::result::Result<(), iroha_config_base::derive::Error> { #(#set_field)* Ok(()) } @@ -183,9 +183,9 @@ fn impl_get_doc_recursive( return quote! { fn get_doc_recursive<'a>( inner_field: impl AsRef<[&'a str]>, - ) -> core::result::Result, iroha_config::derive::Error> + ) -> core::result::Result, iroha_config_base::derive::Error> { - Err(iroha_config::derive::Error::UnknownField( + Err(iroha_config_base::derive::Error::UnknownField( inner_field.as_ref().iter().map(ToString::to_string).collect() )) } @@ -201,11 +201,11 @@ fn impl_get_doc_recursive( quote! { [stringify!(#ident)] => { let curr_doc = #documentation; - let inner_docs = <#ty as iroha_config::Configurable>::get_inner_docs(); + let inner_docs = <#ty as iroha_config_base::Configurable>::get_inner_docs(); let total_docs = format!("{}\n\nHas following fields:\n\n{}\n", curr_doc, inner_docs); Some(total_docs) }, - [stringify!(#ident), rest @ ..] => <#ty as iroha_config::Configurable>::get_doc_recursive(rest)?, + [stringify!(#ident), rest @ ..] => <#ty as iroha_config_base::Configurable>::get_doc_recursive(rest)?, } } else { quote! { [stringify!(#ident)] => Some(#documentation.to_owned()), } @@ -218,12 +218,12 @@ fn impl_get_doc_recursive( quote! { fn get_doc_recursive<'a>( inner_field: impl AsRef<[&'a str]>, - ) -> core::result::Result, iroha_config::derive::Error> + ) -> core::result::Result, iroha_config_base::derive::Error> { let inner_field = inner_field.as_ref(); let doc = match inner_field { #variants - field => return Err(iroha_config::derive::Error::UnknownField( + field => return Err(iroha_config_base::derive::Error::UnknownField( field.iter().map(ToString::to_string).collect() )), }; @@ -245,7 +245,7 @@ fn impl_get_inner_docs( .zip(field_ty) .map(|(((ident, inner_thing), documentation), ty)| { let doc = if inner_thing { - quote!{ <#ty as iroha_config::Configurable>::get_inner_docs().as_str() } + quote!{ <#ty as iroha_config_base::Configurable>::get_inner_docs().as_str() } } else { quote!{ #documentation.into() } }; @@ -283,7 +283,7 @@ fn impl_get_docs( .zip(field_ty) .map(|(((ident, inner_thing), documentation), ty)| { let doc = if inner_thing { - quote!{ <#ty as iroha_config::Configurable>::get_docs().into() } + quote!{ <#ty as iroha_config_base::Configurable>::get_docs().into() } } else { quote!{ #documentation.into() } }; @@ -313,11 +313,11 @@ fn impl_get_recursive( fn get_recursive<'a, T>( &self, inner_field: T, - ) -> iroha_config::BoxedFuture<'a, core::result::Result> + ) -> iroha_config_base::BoxedFuture<'a, core::result::Result> where T: AsRef<[&'a str]> + Send + 'a, { - Err(iroha_config::derive::Error::UnknownField( + Err(iroha_config_base::derive::Error::UnknownField( inner_field.as_ref().iter().map(ToString::to_string).collect() )) } @@ -340,7 +340,7 @@ fn impl_get_recursive( quote! { [stringify!(#ident)] => { serde_json::to_value(&#l_value) - .map_err(|e| iroha_config::derive::Error::field_error(stringify!(#ident), e))? + .map_err(|e| iroha_config_base::derive::Error::field_error(stringify!(#ident), e))? } #inner_thing2 } @@ -360,7 +360,7 @@ fn impl_get_recursive( let inner_field = inner_field.as_ref(); let value = match inner_field { #variants - field => return Err(iroha_config::derive::Error::UnknownField( + field => return Err(iroha_config_base::derive::Error::UnknownField( field.iter().map(ToString::to_string).collect() )), }; @@ -488,8 +488,8 @@ fn impl_configurable(ast: &DeriveInput) -> TokenStream { let get_docs = impl_get_docs(&field_ty, &field_idents, inner, docs); let out = quote! { - impl iroha_config::Configurable for #name { - type Error = iroha_config::derive::Error; + impl iroha_config_base::Configurable for #name { + type Error = iroha_config_base::derive::Error; #get_recursive #get_doc_recursive @@ -500,3 +500,336 @@ fn impl_configurable(ast: &DeriveInput) -> TokenStream { }; out.into() } + +// Take struct with named fields as input +#[derive(Debug, Clone)] +struct ViewInput { + attrs: Vec, + vis: syn::Visibility, + _struct_token: Token![struct], + ident: Ident, + generics: syn::Generics, + fields: Vec, + _semi_token: Option, +} + +impl Parse for ViewInput { + fn parse(input: ParseStream) -> syn::Result { + Ok(Self { + attrs: input.call(Attribute::parse_outer)?, + vis: input.parse()?, + _struct_token: input.parse()?, + ident: input.parse()?, + generics: input.parse()?, + fields: input + .parse::()? + .named + .into_iter() + .collect(), + _semi_token: input.parse()?, + }) + } +} + +// Recreate struct +impl ToTokens for ViewInput { + fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) { + let ViewInput { + attrs, + vis, + ident, + generics, + fields, + .. + } = self; + let stream = quote! { + #(#attrs)* + #vis struct #ident #generics { + #(#fields),* + } + }; + tokens.extend(stream); + } +} + +/// Keywords used inside `#[view(...)]` +mod kw { + syn::custom_keyword!(ignore); + syn::custom_keyword!(into); +} + +/// Structure to parse `#[view(...)]` attributes +/// [`Inner`] is responsible for parsing attribute arguments +struct View(std::marker::PhantomData); + +impl View { + fn parse(attr: &Attribute) -> syn::Result { + attr.path + .is_ident("view") + .then(|| attr.parse_args::()) + .map_or_else( + || { + Err(syn::Error::new_spanned( + attr, + "Attribute must be in form #[view...]", + )) + }, + |inner| inner, + ) + } +} + +struct ViewIgnore { + _kw: kw::ignore, +} + +impl Parse for ViewIgnore { + fn parse(input: ParseStream) -> syn::Result { + Ok(Self { + _kw: input.parse()?, + }) + } +} + +struct ViewFieldType { + _kw: kw::into, + _eq: Token![=], + ty: Type, +} + +impl Parse for ViewFieldType { + fn parse(input: ParseStream) -> syn::Result { + Ok(Self { + _kw: input.parse()?, + _eq: input.parse()?, + ty: input.parse()?, + }) + } +} + +impl From for Type { + fn from(value: ViewFieldType) -> Self { + value.ty + } +} + +/// Generate view for given struct and convert from type to its view. +/// More details in `iroha_config_base` reexport. +#[proc_macro] +pub fn view(input: TokenStream) -> TokenStream { + let ast = syn::parse_macro_input!(input as ViewInput); + let original = gen_original_struct(ast.clone()); + let view = gen_view_struct(ast); + let impl_from = gen_impl_from(&original, &view); + let impl_default = gen_impl_default(&original, &view); + let impl_has_view = gen_impl_has_view(&original); + let assertions = gen_assertions(&view); + let out = quote! { + #original + #impl_has_view + #view + #impl_from + #impl_default + #assertions + }; + out.into() +} + +fn gen_original_struct(mut ast: ViewInput) -> ViewInput { + remove_attr_struct(&mut ast, "view"); + ast +} + +#[allow(clippy::str_to_string, clippy::expect_used)] +fn gen_view_struct(mut ast: ViewInput) -> ViewInput { + // Remove fields with #[view(ignore)] + ast.fields.retain(is_view_field_ignored); + // Change field type to `Type` if it has attribute #[view(into = Type)] + ast.fields.iter_mut().for_each(view_field_change_type); + // Replace doc-string for view + remove_attr(&mut ast.attrs, "doc"); + let view_doc = format!("View for {}", ast.ident); + ast.attrs.push(syn::parse_quote!( + #[doc = #view_doc] + )); + // Remove `Default` from #[derive(..., Default, ...)] or #[derive(Default)] because we implement `Default` inside macro + ast.attrs + .iter_mut() + .filter(|attr| attr.path.is_ident("derive")) + .for_each(|attr| { + let meta = attr + .parse_meta() + .expect("derive macro must be in one of the meta forms"); + match meta { + Meta::List(list) => { + let items: Vec = list + .nested + .into_iter() + .filter(|nested| { + if let NestedMeta::Meta(Meta::Path(path)) = nested { + if path.is_ident("Default") { + return false; + } + } + true + }) + .collect(); + *attr = syn::parse_quote!( + #[derive(#(#items),*)] + ) + } + Meta::Path(path) if path.is_ident("Default") => { + *attr = syn::parse_quote!( + #[derive()] + ) + } + _ => {} + } + }); + remove_attr_struct(&mut ast, "view"); + ast.ident = format_ident!("{}View", ast.ident); + ast +} + +fn gen_impl_from(original: &ViewInput, view: &ViewInput) -> proc_macro2::TokenStream { + let ViewInput { + ident: original_ident, + .. + } = original; + let ViewInput { + generics, + ident: view_ident, + fields, + .. + } = view; + let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); + let field_idents = extract_field_idents(fields); + + quote! { + impl #impl_generics core::convert::From<#original_ident> for #view_ident #ty_generics #where_clause { + fn from(config: #original_ident) -> Self { + let #original_ident { + #( + #field_idents, + )* + .. + } = config; + Self { + #( + #field_idents: core::convert::From::<_>::from(#field_idents), + )* + } + } + } + } +} + +fn gen_impl_default(original: &ViewInput, view: &ViewInput) -> proc_macro2::TokenStream { + let ViewInput { + ident: original_ident, + .. + } = original; + let ViewInput { + generics, + ident: view_ident, + .. + } = view; + let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); + + quote! { + impl #impl_generics core::default::Default for #view_ident #ty_generics #where_clause { + fn default() -> Self { + core::convert::From::<_>::from(<#original_ident as core::default::Default>::default()) + } + } + } +} + +fn gen_impl_has_view(original: &ViewInput) -> proc_macro2::TokenStream { + let ViewInput { + generics, + ident: view_ident, + .. + } = original; + let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); + + quote! { + impl #impl_generics iroha_config_base::view::HasView for #view_ident #ty_generics #where_clause {} + } +} + +fn gen_assertions(view: &ViewInput) -> proc_macro2::TokenStream { + let ViewInput { fields, .. } = view; + let field_types = extract_field_types(fields); + let messages: Vec = extract_field_idents(fields) + .iter() + .map(|ident| { + format!("Field `{ident}` has it's own view, consider adding attribute #[view(into = ViewType)]") + }) + .collect(); + quote! { + /// Assert that every field of 'View' doesn't implement `HasView` trait + const _: () = { + use iroha_config_base::view::NoView; + #( + const _: () = assert!(!iroha_config_base::view::IsHasView::<#field_types>::IS_HAS_VIEW, #messages); + )* + }; + } +} + +/// Change [`Field`] type to `Type` if `#[view(type = Type)]` is present +fn view_field_change_type(field: &mut Field) { + if let Some(ty) = field + .attrs + .iter() + .map(View::::parse) + .find_map(Result::ok) + .map(ViewFieldType::into) + { + field.ty = ty; + } +} + +/// Check if [`Field`] has `#[view(ignore)]` +fn is_view_field_ignored(field: &Field) -> bool { + field + .attrs + .iter() + .map(View::::parse) + .find_map(Result::ok) + .is_none() +} + +/// Remove attributes with ident [`attr_ident`] from struct attributes and field attributes +fn remove_attr_struct(ast: &mut ViewInput, attr_ident: &str) { + let ViewInput { attrs, fields, .. } = ast; + for field in fields { + remove_attr(&mut field.attrs, attr_ident) + } + remove_attr(attrs, attr_ident); +} + +/// Remove attributes with ident [`attr_ident`] from attributes +fn remove_attr(attrs: &mut Vec, attr_ident: &str) { + attrs.retain(|attr| !attr.path.is_ident(attr_ident)); +} + +/// Return [`Vec`] of fields idents +fn extract_field_idents(fields: &[Field]) -> Vec<&Ident> { + fields + .iter() + .map(|field| { + #[allow(clippy::expect_used)] + field + .ident + .as_ref() + .expect("Should always be set for named structures") + }) + .collect::>() +} + +/// Return [`Vec`] of fields types +fn extract_field_types(fields: &[Field]) -> Vec<&Type> { + fields.iter().map(|field| &field.ty).collect::>() +} diff --git a/config/base/src/lib.rs b/config/base/src/lib.rs new file mode 100644 index 00000000000..3336a2c400d --- /dev/null +++ b/config/base/src/lib.rs @@ -0,0 +1,258 @@ +//! Package for managing iroha configuration + +use serde::{de::DeserializeOwned, Serialize}; +use serde_json::Value; + +pub mod derive { + //! Modules for `Configurable` entities + + use std::{error::Error as StdError, fmt}; + + use derive_more::Display; + /// Generate view for the type and implement conversion `Type -> View`. + /// View contains a subset of the fields that the type has. + /// + /// Works only with structs. + /// Type must implement [`Default`]. + /// + /// ## Container attributes + /// + /// ## Field attributes + /// ### `#[view(ignore)]` + /// Marks fields to ignore when converting to view type. + /// + /// ### `#[view(into = Ty)]` + /// Sets view's field type to Ty. + /// + /// ## Examples + /// + /// ```rust + /// use iroha_config_base::derive::view; + /// + /// view! { + /// #[derive(Default)] + /// struct Structure { + /// #[view(type = u64)] + /// a: u32, + /// // `View` shouldn't have field `b` so we must exclude it. + /// #[view(ignore)] + /// b: u32, + /// } + /// } + /// + /// // Will generate something like + /// // --//-- original struct + /// // struct StructureView { + /// // a: u64, + /// // } + /// // + /// // impl From for StructureView { + /// // fn from(value: Structure) -> Self { + /// // let Structure { + /// // a, + /// // .. + /// // } = value; + /// // Self { + /// // a: From::<_>::from(a), + /// // } + /// // } + /// // } + /// // + /// // impl Default for StructureView { + /// // fn default() -> Self { + /// // Self::from(::default()) + /// // } + /// // } + /// + /// + /// let structure = Structure { a: 13, b: 37 }; + /// let view: StructureView = structure.into(); + /// assert_eq!(view.a, 13); + /// let structure_default = Structure::default(); + /// let view_default = StructureView::default(); + /// assert_eq!(structure_default.a, view_default.a); + /// ``` + pub use iroha_config_derive::view; + /// Derive macro for implementing [`iroha_config::Configurable`](`crate::Configurable`) for config structures. + /// + /// Has several attributes: + /// + /// ## `env_prefix` + /// Sets prefix for env variable + /// ``` rust + /// use iroha_config_base::{Configurable, derive::Configurable}; + /// + /// #[derive(serde::Deserialize, serde::Serialize, Configurable)] + /// #[config(env_prefix = "PREFIXED_")] + /// struct Prefixed { a: String } + /// + /// std::env::set_var("PREFIXED_A", "B"); + /// let mut prefixed = Prefixed { a: "a".to_owned() }; + /// prefixed.load_environment(); + /// assert_eq!(prefixed.a, "B"); + /// ``` + /// + /// ## `inner` + /// Tells macro that the structure stores another config inside + /// ```rust + /// use iroha_config_base::{Configurable, derive::Configurable}; + /// + /// #[derive(serde::Deserialize, serde::Serialize, Configurable)] + /// struct Outer { #[config(inner)] inner: Inner } + /// + /// #[derive(serde::Deserialize, serde::Serialize, Configurable)] + /// struct Inner { b: String } + /// + /// let outer = Outer { inner: Inner { b: "a".to_owned() }}; + /// assert_eq!(outer.get_recursive(["inner", "b"]).unwrap(), "a"); + /// ``` + /// + /// ## `serde_as_str` + /// Tells macro to deserialize from env variable as a bare string: + /// ``` + /// use iroha_config_base::{Configurable, derive::Configurable}; + /// use std::net::Ipv4Addr; + /// + /// #[derive(serde::Deserialize, serde::Serialize, Configurable)] + /// struct IpAddr { #[config(serde_as_str)] ip: Ipv4Addr, } + /// + /// std::env::set_var("IP", "127.0.0.1"); + /// let mut ip = IpAddr { ip: Ipv4Addr::new(10, 0, 0, 1) }; + /// ip.load_environment().expect("String loading never fails"); + /// assert_eq!(ip.ip, Ipv4Addr::new(127, 0, 0, 1)); + /// ``` + pub use iroha_config_derive::Configurable; + + /// Error related to deserializing specific field + #[derive(Debug, Display)] + #[display(fmt = "Failed to deserialize the field {field}")] + pub struct FieldError { + /// Field name (known at compile time) + pub field: &'static str, + /// Serde-json error + pub error: serde_json::Error, + } + + impl StdError for FieldError { + fn source(&self) -> Option<&(dyn StdError + 'static)> { + Some(&self.error) + } + } + + /// Derive `Configurable` error + #[derive(Debug)] + pub enum Error { + /// Got unknown field + UnknownField(Vec), + /// Failed to deserialize or serialize a field + FieldError(FieldError), + } + + impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::UnknownField(field) => { + let field = field + .iter() + .skip(1) + .fold(field[0].clone(), |mut prev, suc| { + prev += "."; + prev += suc; + prev + }); + write!(f, "Failed to deserialize: Unknown field {}", field) + } + Self::FieldError(_) => write!(f, "Failed to deserialize"), + } + } + } + + impl StdError for Error { + fn source(&self) -> Option<&(dyn StdError + 'static)> { + if let Error::FieldError(field) = self { + Some(field) + } else { + None + } + } + } + + impl Error { + /// Construct a field error + pub const fn field_error(field: &'static str, error: serde_json::Error) -> Self { + Self::FieldError(FieldError { field, error }) + } + } +} + +pub mod runtime_upgrades; + +/// Trait for dynamic and asynchronous configuration via maintenance endpoint for Rust structures +pub trait Configurable: Serialize + DeserializeOwned { + /// Error type returned by methods of this trait + type Error; + + /// Return the JSON value of a given field + /// # Errors + /// Fails if field was unknown + fn get(&self, field: &'_ str) -> Result { + self.get_recursive([field]) + } + + /// Return the JSON value of a given inner field of arbitrary inner depth + /// # Errors + /// Fails if field was unknown + fn get_recursive<'tl, T>(&self, inner_field: T) -> Result + where + T: AsRef<[&'tl str]> + Send + 'tl; + + /// Load configuration from the environment + /// + /// # Errors + /// Fails if fails to deserialize from environment + fn load_environment(&mut self) -> Result<(), Self::Error>; + + /// Get documentation of a given inner field of arbitrary depth + /// + /// # Errors + /// Fails if field was unknown + fn get_doc_recursive<'tl>(field: impl AsRef<[&'tl str]>) + -> Result, Self::Error>; + + /// Get documentation of a given field + /// # Errors + /// Fails if field was unknown + fn get_doc(field: &str) -> Result, Self::Error> { + Self::get_doc_recursive([field]) + } + + /// Return documentation for all fields in a form of a JSON object + fn get_docs() -> Value; + + /// Get inner documentation for non-leaf fields + fn get_inner_docs() -> String; +} + +pub mod view { + //! Module for view related traits and structs + + /// Marker trait to set default value `IS_HAS_VIEW` to `false` + pub trait NoView { + /// [`Self`] doesn't implement [`HasView`] + const IS_HAS_VIEW: bool = false; + } + impl NoView for T {} + + /// Marker traits for types for which views are implemented + pub trait HasView {} + + /// Wrapper structure used to check if type implements `[HasView]` + /// If `T` doesn't implement [`HasView`] then `NoView::IS_HAS_VIEW` (`false`) will be used + /// Otherwise `IsHasView::IS_HAS_VIEW` (`true`) from `impl` block will shadow `NoView::IS_HAS_VIEW` + pub struct IsHasView(std::marker::PhantomData); + + impl IsHasView { + /// `T` implements trait [`HasView`] + pub const IS_HAS_VIEW: bool = true; + } +} diff --git a/config/src/runtime_upgrades.rs b/config/base/src/runtime_upgrades.rs similarity index 98% rename from config/src/runtime_upgrades.rs rename to config/base/src/runtime_upgrades.rs index f7ff951fcff..f14131e5a00 100644 --- a/config/src/runtime_upgrades.rs +++ b/config/base/src/runtime_upgrades.rs @@ -228,9 +228,9 @@ pub mod handle { /// # Examples /// ```ignore /// use serde::{Serialize, Deserialize}; - /// use iroha_config::runtime_upgrades::{handle::Value, Reload}; + /// use iroha_config_base::runtime_upgrades::{handle::Value, Reload}; /// - /// #[derive(iroha_config::derive::Configurable, Serialize, Deserialize)] + /// #[derive(iroha_config_base::derive::Configurable, Serialize, Deserialize)] /// pub struct Config { option: Value } /// /// fn main() { diff --git a/config/tests/simple.rs b/config/base/tests/simple.rs similarity index 95% rename from config/tests/simple.rs rename to config/base/tests/simple.rs index 5dd15ddc65a..d93d13becfd 100644 --- a/config/tests/simple.rs +++ b/config/base/tests/simple.rs @@ -1,6 +1,6 @@ #![allow(clippy::restriction)] -use iroha_config::{derive::Configurable, Configurable}; +use iroha_config_base::{derive::Configurable, Configurable}; use serde::{Deserialize, Serialize}; #[derive(Clone, Debug, Deserialize, Serialize, Configurable)] diff --git a/config/src/block_sync.rs b/config/src/block_sync.rs new file mode 100644 index 00000000000..6650dc92a1d --- /dev/null +++ b/config/src/block_sync.rs @@ -0,0 +1,32 @@ +//! Module for `BlockSynchronizer`-related configuration and structs. +use iroha_config_base::derive::Configurable; +use serde::{Deserialize, Serialize}; + +const DEFAULT_BLOCK_BATCH_SIZE: u32 = 4; +const DEFAULT_GOSSIP_PERIOD_MS: u64 = 10000; +const DEFAULT_ACTOR_CHANNEL_CAPACITY: u32 = 100; + +/// Configuration for `BlockSynchronizer`. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize, Configurable)] +#[serde(rename_all = "UPPERCASE")] +#[serde(default)] +#[config(env_prefix = "BLOCK_SYNC_")] +pub struct Configuration { + /// The period of time to wait between sending requests for the latest block. + pub gossip_period_ms: u64, + /// The number of blocks that can be sent in one message. + /// Underlying network (`iroha_network`) should support transferring messages this large. + pub block_batch_size: u32, + /// Buffer capacity of actor's MPSC channel + pub actor_channel_capacity: u32, +} + +impl Default for Configuration { + fn default() -> Self { + Self { + gossip_period_ms: DEFAULT_GOSSIP_PERIOD_MS, + block_batch_size: DEFAULT_BLOCK_BATCH_SIZE, + actor_channel_capacity: DEFAULT_ACTOR_CHANNEL_CAPACITY, + } + } +} diff --git a/client/src/config.rs b/config/src/client.rs similarity index 94% rename from client/src/config.rs rename to config/src/client.rs index b70340de470..a26e3a96be5 100644 --- a/client/src/config.rs +++ b/config/src/client.rs @@ -1,14 +1,16 @@ +//! Module for client-related configuration and structs use std::{fmt, fs::File, io::BufReader, path::Path, str::FromStr}; use derive_more::Display; use eyre::{eyre, Result, WrapErr}; -use iroha_config::derive::Configurable; +use iroha_config_base::derive::Configurable; use iroha_crypto::prelude::*; use iroha_data_model::{prelude::*, transaction}; -use iroha_logger::Configuration as LoggerConfiguration; use iroha_primitives::small::SmallStr; use serde::{Deserialize, Serialize}; +use crate::torii::uri; + const DEFAULT_TORII_TELEMETRY_URL: &str = "127.0.0.1:8180"; const DEFAULT_TRANSACTION_TIME_TO_LIVE_MS: u64 = 100_000; const DEFAULT_TRANSACTION_STATUS_TIMEOUT_MS: u64 = 10_000; @@ -82,13 +84,13 @@ pub struct Configuration { pub transaction_time_to_live_ms: u64, /// Transaction status wait timeout in milliseconds. pub transaction_status_timeout_ms: u64, - /// Limits to which transactions must adhere to + /// The limits to which transactions must adhere to pub transaction_limits: TransactionLimits, /// If `true` add nonce, which make different hashes for transactions which occur repeatedly and simultaneously pub add_transaction_nonce: bool, /// `Logger` configuration. #[config(inner)] - pub logger_configuration: LoggerConfiguration, + pub logger_configuration: crate::logger::Configuration, } impl Default for Configuration { @@ -109,7 +111,7 @@ impl Default for Configuration { max_wasm_size_bytes: transaction::DEFAULT_MAX_WASM_SIZE_BYTES, }, add_transaction_nonce: DEFAULT_ADD_TRANSACTION_NONCE, - logger_configuration: LoggerConfiguration::default(), + logger_configuration: crate::logger::Configuration::default(), } } } diff --git a/config/src/genesis.rs b/config/src/genesis.rs new file mode 100644 index 00000000000..535acdbd0fb --- /dev/null +++ b/config/src/genesis.rs @@ -0,0 +1,77 @@ +//! Module with genesis configuration logic. +use iroha_config_base::derive::{view, Configurable}; +use iroha_crypto::{KeyPair, PrivateKey, PublicKey}; +use serde::{Deserialize, Serialize}; + +const DEFAULT_WAIT_FOR_PEERS_RETRY_COUNT_LIMIT: u64 = 100; +const DEFAULT_WAIT_FOR_PEERS_RETRY_PERIOD_MS: u64 = 500; +const DEFAULT_GENESIS_SUBMISSION_DELAY_MS: u64 = 1000; + +// Generate `ConfigurationView` without the private key +view! { + /// Configuration of the genesis block and the process of its submission. + #[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize, Configurable)] + #[serde(default)] + #[serde(rename_all = "UPPERCASE")] + #[config(env_prefix = "IROHA_GENESIS_")] + pub struct Configuration { + /// The public key of the genesis account, should be supplied to all peers. + #[config(serde_as_str)] + pub account_public_key: PublicKey, + /// The private key of the genesis account, only needed for the peer that submits the genesis block. + #[view(ignore)] + pub account_private_key: Option, + /// The number of attempts to connect to peers while waiting for them to submit genesis. + #[serde(default = "default_wait_for_peers_retry_count_limit")] + pub wait_for_peers_retry_count_limit: u64, + /// The period in milliseconds in which to retry connecting to peers while waiting for them to submit genesis. + #[serde(default = "default_wait_for_peers_retry_period_ms")] + pub wait_for_peers_retry_period_ms: u64, + /// The delay before genesis block submission after minimum number of peers were discovered to be online. + /// The delay between submissions, which is used to ensure that other peers had time to connect to each other. + #[serde(default = "default_genesis_submission_delay_ms")] + pub genesis_submission_delay_ms: u64, + } +} + +impl Default for Configuration { + fn default() -> Self { + let (public_key, private_key) = Self::placeholder_keypair().into(); + + Self { + account_public_key: public_key, + account_private_key: Some(private_key), + wait_for_peers_retry_count_limit: DEFAULT_WAIT_FOR_PEERS_RETRY_COUNT_LIMIT, + wait_for_peers_retry_period_ms: DEFAULT_WAIT_FOR_PEERS_RETRY_PERIOD_MS, + genesis_submission_delay_ms: DEFAULT_GENESIS_SUBMISSION_DELAY_MS, + } + } +} + +impl Configuration { + /// Key-pair used by default for demo purposes + #[allow(clippy::expect_used)] + fn placeholder_keypair() -> KeyPair { + let public_key = "ed01204cffd0ee429b1bdd36b3910ec570852b8bb63f18750341772fb46bc856c5caaf" + .parse() + .expect("Public key not in mulithash format"); + let private_key = PrivateKey::from_hex( + iroha_crypto::Algorithm::Ed25519, + "d748e18ce60cb30dea3e73c9019b7af45a8d465e3d71bcc9a5ef99a008205e534cffd0ee429b1bdd36b3910ec570852b8bb63f18750341772fb46bc856c5caaf" + ).expect("Private key not hex encoded"); + + KeyPair::new(public_key, private_key).expect("Key pair mismatch") + } +} + +const fn default_wait_for_peers_retry_count_limit() -> u64 { + DEFAULT_WAIT_FOR_PEERS_RETRY_COUNT_LIMIT +} + +const fn default_wait_for_peers_retry_period_ms() -> u64 { + DEFAULT_WAIT_FOR_PEERS_RETRY_PERIOD_MS +} + +const fn default_genesis_submission_delay_ms() -> u64 { + DEFAULT_GENESIS_SUBMISSION_DELAY_MS +} diff --git a/config/src/iroha.rs b/config/src/iroha.rs new file mode 100644 index 00000000000..0c8aedaa9b8 --- /dev/null +++ b/config/src/iroha.rs @@ -0,0 +1,153 @@ +//! This module contains [`Configuration`] structure and related implementation. +use std::{fmt::Debug, fs::File, io::BufReader, path::Path}; + +use eyre::{Result, WrapErr}; +use iroha_config_base::derive::{view, Configurable}; +use iroha_crypto::prelude::*; +use serde::{Deserialize, Serialize}; + +use super::*; + +// Generate `ConfigurationView` without the private key +view! { + /// Configuration parameters for a peer + #[derive(Debug, Clone, Deserialize, Serialize, Configurable)] + #[serde(default)] + #[serde(rename_all = "UPPERCASE")] + #[config(env_prefix = "IROHA_")] + pub struct Configuration { + /// Public key of this peer + #[config(serde_as_str)] + pub public_key: PublicKey, + /// Private key of this peer + #[view(ignore)] + pub private_key: PrivateKey, + /// Disable coloring of the backtrace and error report on panic + pub disable_panic_terminal_colors: bool, + /// Iroha will shutdown on any panic if this option is set to `true`. + pub shutdown_on_panic: bool, + /// `Kura` configuration + #[config(inner)] + pub kura: kura::Configuration, + /// `Sumeragi` configuration + #[config(inner)] + #[view(into = sumeragi::ConfigurationView)] + pub sumeragi: sumeragi::Configuration, + /// `Torii` configuration + #[config(inner)] + pub torii: torii::Configuration, + /// `BlockSynchronizer` configuration + #[config(inner)] + pub block_sync: block_sync::Configuration, + /// `Queue` configuration + #[config(inner)] + pub queue: queue::Configuration, + /// `Logger` configuration + #[config(inner)] + pub logger: logger::Configuration, + /// `GenesisBlock` configuration + #[config(inner)] + #[view(into = genesis::ConfigurationView)] + pub genesis: genesis::Configuration, + /// `WorldStateView` configuration + #[config(inner)] + pub wsv: wsv::Configuration, + /// Network configuration + #[config(inner)] + pub network: network::Configuration, + /// Telemetry configuration + #[config(inner)] + pub telemetry: telemetry::Configuration, + } +} + +impl Default for Configuration { + fn default() -> Self { + let sumeragi_configuration = sumeragi::Configuration::default(); + let (public_key, private_key) = sumeragi_configuration.key_pair.clone().into(); + + Self { + public_key, + private_key, + disable_panic_terminal_colors: bool::default(), + shutdown_on_panic: false, + kura: kura::Configuration::default(), + sumeragi: sumeragi_configuration, + torii: torii::Configuration::default(), + block_sync: block_sync::Configuration::default(), + queue: queue::Configuration::default(), + logger: logger::Configuration::default(), + genesis: genesis::Configuration::default(), + wsv: wsv::Configuration::default(), + network: network::Configuration::default(), + telemetry: telemetry::Configuration::default(), + } + } +} + +impl Configuration { + /// Construct [`Self`] from a path-like object. + /// + /// # Errors + /// - File not found. + /// - File found, but peer configuration parsing failed. + /// - The length of the array in raw JSON representation is different + /// from the length of the array in + /// [`self.sumeragi.trusted_peers.peers`], most likely due to two + /// (or more) peers having the same public key. + pub fn from_path + Debug + Clone>(path: P) -> Result { + let file = File::open(path.clone()) + .wrap_err(format!("Failed to open the config file {:?}", path))?; + let reader = BufReader::new(file); + let mut configuration: Configuration = serde_json::from_reader(reader).wrap_err( + format!("Failed to parse {:?} as Iroha peer configuration.", path), + )?; + configuration.finalize()?; + Ok(configuration) + } + + fn finalize(&mut self) -> Result<()> { + self.sumeragi.key_pair = KeyPair::new(self.public_key.clone(), self.private_key.clone())?; + self.sumeragi.peer_id = + iroha_data_model::peer::Id::new(&self.torii.p2p_addr, &self.public_key.clone()); + + Ok(()) + } + + /// Load configuration from the environment + /// + /// # Errors + /// Fails if Configuration deserialization fails (e.g. if `TrustedPeers` contains entries with duplicate public keys) + pub fn load_environment(&mut self) -> Result<()> { + iroha_config_base::Configurable::load_environment(self)?; + self.finalize()?; + Ok(()) + } +} + +#[cfg(test)] +mod tests { + #![allow(clippy::restriction)] + + use super::*; + use crate::sumeragi::TrustedPeers; + + const CONFIGURATION_PATH: &str = "../configs/peer/config.json"; + + #[test] + fn parse_example_json() -> Result<()> { + let configuration = Configuration::from_path(CONFIGURATION_PATH) + .wrap_err("Failed to read configuration from example config")?; + assert_eq!("127.0.0.1:1337", configuration.torii.p2p_addr); + assert_eq!(1000, configuration.sumeragi.block_time_ms); + Ok(()) + } + + #[test] + #[should_panic] + fn parse_trusted_peers_fail_duplicate_peer_id() { + let trusted_peers_string = r#"[{"address":"127.0.0.1:1337", "public_key": "ed0120954c83a4220faffb2c1d23fc5225b3e7952d53acbb2a065ff30c631e5e1d6b10"}, {"address":"127.0.0.1:1337", "public_key": "ed0120954c83a4220faffb2c1d23fc5225b3e7952d53acbb2a065ff30c631e5e1d6b10"}, {"address":"localhost:1338", "public_key": "ed0120954c83a4220faffb2c1d23fc5225b3e7952d53acbb2a065ff30c631e5e1d6b10"}, {"address": "195.162.0.1:23", "public_key": "ed0120954c83a4220faffb2c1d23fc5225b3e7952d53acbb2a065ff30c631e5e1d6b10"}]"#; + let _result: TrustedPeers = + serde_json::from_str(trusted_peers_string).expect("Failed to parse Trusted Peers"); + } +} diff --git a/config/src/kura.rs b/config/src/kura.rs new file mode 100644 index 00000000000..ae80736e6f4 --- /dev/null +++ b/config/src/kura.rs @@ -0,0 +1,84 @@ +//! Module for kura-related configuration and structs +use std::{num::NonZeroU64, path::Path}; + +use eyre::{eyre, Result}; +use iroha_config_base::derive::Configurable; +use serde::{Deserialize, Serialize}; + +const DEFAULT_BLOCKS_PER_STORAGE_FILE: u64 = 1000_u64; +const DEFAULT_BLOCK_STORE_PATH: &str = "./blocks"; +const DEFAULT_ACTOR_CHANNEL_CAPACITY: u32 = 100; + +/// `Kura` configuration. +#[derive(Clone, Deserialize, Serialize, Debug, Configurable, PartialEq, Eq)] +#[serde(rename_all = "UPPERCASE")] +#[config(env_prefix = "KURA_")] +pub struct Configuration { + /// Initialization mode: `strict` or `fast`. + #[serde(default)] + pub init_mode: Mode, + /// Path to the existing block store folder or path to create new folder. + #[serde(default = "default_block_store_path")] + pub block_store_path: String, + /// Maximum number of blocks to write into a single storage file. + #[serde(default = "default_blocks_per_storage_file")] + pub blocks_per_storage_file: NonZeroU64, + /// Default buffer capacity of actor's MPSC channel. + #[serde(default = "default_actor_channel_capacity")] + pub actor_channel_capacity: u32, +} + +impl Default for Configuration { + fn default() -> Self { + Self { + init_mode: Mode::default(), + block_store_path: default_block_store_path(), + blocks_per_storage_file: default_blocks_per_storage_file(), + actor_channel_capacity: default_actor_channel_capacity(), + } + } +} + +impl Configuration { + /// Set `block_store_path` configuration parameter. Will overwrite the existing one. + /// + /// # Errors + /// Fails if the path is not valid + pub fn block_store_path(&mut self, path: &Path) -> Result<()> { + self.block_store_path = path + .to_str() + .ok_or_else(|| eyre!("Failed to yield slice from path"))? + .to_owned(); + Ok(()) + } +} + +fn default_block_store_path() -> String { + DEFAULT_BLOCK_STORE_PATH.to_owned() +} + +fn default_blocks_per_storage_file() -> NonZeroU64 { + #![allow(clippy::expect_used)] + NonZeroU64::new(DEFAULT_BLOCKS_PER_STORAGE_FILE) + .expect("BLOCKS_PER_STORAGE cannot be set to a non-positive value.") +} + +const fn default_actor_channel_capacity() -> u32 { + DEFAULT_ACTOR_CHANNEL_CAPACITY +} + +/// Kura initialization mode. +#[derive(Debug, Clone, Copy, Deserialize, Serialize, PartialEq, Eq)] +#[serde(rename_all = "snake_case")] +pub enum Mode { + /// Strict validation of all blocks. + Strict, + /// Fast initialization with basic checks. + Fast, +} + +impl Default for Mode { + fn default() -> Self { + Mode::Strict + } +} diff --git a/config/src/lib.rs b/config/src/lib.rs index 4701cc9a8f6..0615ebe15f3 100644 --- a/config/src/lib.rs +++ b/config/src/lib.rs @@ -1,203 +1,21 @@ -//! Package for managing iroha configuration - -use serde::{de::DeserializeOwned, Deserialize, Serialize}; -use serde_json::Value; - -pub mod derive { - //! Modules with things related with deriving `Configurable` - - use std::{error::Error as StdError, fmt}; - - use derive_more::Display; - /// Derive macro for implementing [`iroha_config::Configurable`](`crate::Configurable`) for config structures. - /// - /// Has several attributes: - /// - /// ## `env_prefix` - /// Sets prefix for env variable - /// ``` rust - /// use iroha_config::{Configurable, derive::Configurable}; - /// - /// #[derive(serde::Deserialize, serde::Serialize, Configurable)] - /// #[config(env_prefix = "PREFIXED_")] - /// struct Prefixed { a: String } - /// - /// std::env::set_var("PREFIXED_A", "B"); - /// let mut prefixed = Prefixed { a: "a".to_owned() }; - /// prefixed.load_environment(); - /// assert_eq!(prefixed.a, "B"); - /// ``` - /// - /// ## `inner` - /// Tells macro that structure stores another config inside - /// ```rust - /// use iroha_config::{Configurable, derive::Configurable}; - /// - /// #[derive(serde::Deserialize, serde::Serialize, Configurable)] - /// struct Outer { #[config(inner)] inner: Inner } - /// - /// #[derive(serde::Deserialize, serde::Serialize, Configurable)] - /// struct Inner { b: String } - /// - /// let outer = Outer { inner: Inner { b: "a".to_owned() }}; - /// assert_eq!(outer.get_recursive(["inner", "b"]).unwrap(), "a"); - /// ``` - /// - /// ## `serde_as_str` - /// Tells macro to deserialize from env variable as bare string: - /// ``` - /// use iroha_config::{Configurable, derive::Configurable}; - /// use std::net::Ipv4Addr; - /// - /// #[derive(serde::Deserialize, serde::Serialize, Configurable)] - /// struct IpAddr { #[config(serde_as_str)] ip: Ipv4Addr, } - /// - /// std::env::set_var("IP", "127.0.0.1"); - /// let mut ip = IpAddr { ip: Ipv4Addr::new(10, 0, 0, 1) }; - /// ip.load_environment().expect("String loading never fails"); - /// assert_eq!(ip.ip, Ipv4Addr::new(127, 0, 0, 1)); - /// ``` - pub use iroha_config_derive::Configurable; - - /// Error related to deserializing specific field - #[derive(Debug, Display)] - #[display(fmt = "Failed to deserialize the field {field}")] - pub struct FieldError { - /// Field name (known at compile time) - pub field: &'static str, - /// Serde-json error - pub error: serde_json::Error, - } - - impl StdError for FieldError { - fn source(&self) -> Option<&(dyn StdError + 'static)> { - Some(&self.error) - } - } - - /// Derive `Configurable` error - #[derive(Debug)] - pub enum Error { - /// Got unknown field - UnknownField(Vec), - /// Failed to deserialize or serialize field - FieldError(FieldError), - } - - impl fmt::Display for Error { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Self::UnknownField(field) => { - let field = field - .iter() - .skip(1) - .fold(field[0].clone(), |mut prev, suc| { - prev += "."; - prev += suc; - prev - }); - write!(f, "Failed to deserialize: Unknown field {}", field) - } - Self::FieldError(_) => write!(f, "Failed to deserialize"), - } - } - } - - impl StdError for Error { - fn source(&self) -> Option<&(dyn StdError + 'static)> { - if let Error::FieldError(field) = self { - Some(field) - } else { - None - } - } - } - - impl Error { - /// Constructs field error - pub const fn field_error(field: &'static str, error: serde_json::Error) -> Self { - Self::FieldError(FieldError { field, error }) - } - } -} - -pub mod runtime_upgrades; - -pub mod logger { - //! Module containing configuration structures for logger - - use serde::{Deserialize, Serialize}; - - const DEFAULT_MAX_LOG_LEVEL: Level = Level::INFO; - - /// Log level for reading from environment and (de)serializing - #[allow(clippy::upper_case_acronyms)] - #[derive(Debug, Deserialize, Serialize, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] - pub enum Level { - /// Error - ERROR, - /// Warn - WARN, - /// Info (Default) - INFO, - /// Debug - DEBUG, - /// Trace - TRACE, - } - - impl Default for Level { - fn default() -> Self { - DEFAULT_MAX_LOG_LEVEL - } - } -} - -/// Trait for dynamic and asynchronous configuration via maintenance endpoint for rust structures -pub trait Configurable: Serialize + DeserializeOwned { - /// Error type returned by methods of trait - type Error; - - /// Gets field of structure and returns as json-value - /// # Errors - /// Fails if field was unknown - fn get(&self, field: &'_ str) -> Result { - self.get_recursive([field]) - } - - /// Gets inner field of arbitrary inner depth and returns as json-value - /// # Errors - /// Fails if field was unknown - fn get_recursive<'tl, T>(&self, inner_field: T) -> Result - where - T: AsRef<[&'tl str]> + Send + 'tl; - - /// Fails if fails to deserialize from environment - /// - /// # Errors - /// Fails if fails to deserialize from environment - fn load_environment(&mut self) -> Result<(), Self::Error>; - - /// Gets docs of inner field of arbitrary depth - /// - /// # Errors - /// Fails if field was unknown - fn get_doc_recursive<'tl>(field: impl AsRef<[&'tl str]>) - -> Result, Self::Error>; - - /// Gets docs of field - /// # Errors - /// Fails if field was unknown - fn get_doc(field: &str) -> Result, Self::Error> { - Self::get_doc_recursive([field]) - } - - /// Returns documentation for all fields in form of json object - fn get_docs() -> Value; - - /// Gets inner docs for non-leaf fields - fn get_inner_docs() -> String; -} +//! Aggregate configuration for different Iroha modules. + +pub use iroha_config_base as base; +use serde::{Deserialize, Serialize}; + +pub mod block_sync; +pub mod client; +pub mod genesis; +pub mod iroha; +pub mod kura; +pub mod logger; +pub mod network; +pub mod queue; +pub mod sumeragi; +pub mod telemetry; +pub mod torii; +pub mod wasm; +pub mod wsv; /// Json config for getting configuration #[derive(Clone, Debug, Deserialize, Serialize)] diff --git a/logger/src/config.rs b/config/src/logger.rs similarity index 65% rename from logger/src/config.rs rename to config/src/logger.rs index 9e46e779e49..37a7477b5ce 100644 --- a/logger/src/config.rs +++ b/config/src/logger.rs @@ -2,9 +2,9 @@ //! configuration, as well as run-time reloading of the log-level. use std::fmt::Debug; -use iroha_config::{ +use derive_more::{Deref, DerefMut}; +use iroha_config_base::{ derive::Configurable, - logger as config, runtime_upgrades::{handle, ReloadError, ReloadMut}, }; use serde::{Deserialize, Serialize}; @@ -14,26 +14,39 @@ use tracing_subscriber::{filter::LevelFilter, reload::Handle}; const TELEMETRY_CAPACITY: u32 = 1000; const DEFAULT_COMPACT_MODE: bool = false; const DEFAULT_TERMINAL_COLORS: bool = true; +const DEFAULT_MAX_LOG_LEVEL: Level = Level::INFO; /// Log level for reading from environment and (de)serializing -#[derive(Debug, Deserialize, Serialize, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Default)] -#[serde(transparent)] -pub struct Level(pub config::Level); +#[allow(clippy::upper_case_acronyms)] +#[derive(Debug, Deserialize, Serialize, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] +pub enum Level { + /// Error + ERROR, + /// Warn + WARN, + /// Info (Default) + INFO, + /// Debug + DEBUG, + /// Trace + TRACE, +} -impl From for Level { - fn from(level: config::Level) -> Self { - Self(level) +// TODO: derive when bump version to 1.62 +impl Default for Level { + fn default() -> Self { + DEFAULT_MAX_LOG_LEVEL } } impl From for tracing::Level { fn from(level: Level) -> Self { - match level.0 { - config::Level::ERROR => Self::ERROR, - config::Level::TRACE => Self::TRACE, - config::Level::INFO => Self::INFO, - config::Level::DEBUG => Self::DEBUG, - config::Level::WARN => Self::WARN, + match level { + Level::ERROR => Self::ERROR, + Level::TRACE => Self::TRACE, + Level::INFO => Self::INFO, + Level::DEBUG => Self::DEBUG, + Level::WARN => Self::WARN, } } } @@ -51,14 +64,26 @@ impl ReloadMut for Handle { } } -/// Configuration for [`crate`]. +/// Wrapper around [`Level`] for runtime upgrades. +#[derive(Clone, Debug, Serialize, Deserialize, Deref, DerefMut, Default)] +#[repr(transparent)] +#[serde(transparent)] +pub struct SyncLevel(handle::SyncValue>); + +impl From for SyncLevel { + fn from(level: Level) -> Self { + Self(level.into()) + } +} + +/// 'Logger' configuration. #[derive(Clone, Deserialize, Serialize, Debug, Configurable)] #[serde(rename_all = "UPPERCASE")] #[serde(default)] pub struct Configuration { /// Maximum log level #[config(serde_as_str)] - pub max_log_level: handle::SyncValue>, + pub max_log_level: SyncLevel, /// Capacity (or batch size) for telemetry channel pub telemetry_capacity: u32, /// Compact mode (no spans from telemetry) @@ -73,7 +98,7 @@ pub struct Configuration { impl Default for Configuration { fn default() -> Self { Self { - max_log_level: handle::SyncValue::default(), + max_log_level: SyncLevel::default(), telemetry_capacity: TELEMETRY_CAPACITY, compact_mode: DEFAULT_COMPACT_MODE, log_file_path: None, diff --git a/config/src/network.rs b/config/src/network.rs new file mode 100644 index 00000000000..6f05879d068 --- /dev/null +++ b/config/src/network.rs @@ -0,0 +1,23 @@ +//! Module for network-related configuration and structs +use iroha_config_base::derive::Configurable; +use serde::{Deserialize, Serialize}; + +const DEFAULT_ACTOR_CHANNEL_CAPACITY: u32 = 100; + +/// Network Configuration parameters +#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize, Configurable)] +#[serde(default)] +#[serde(rename_all = "UPPERCASE")] +#[config(env_prefix = "IROHA_NETWORK_")] +pub struct Configuration { + /// Buffer capacity of actor's MPSC channel + pub actor_channel_capacity: u32, +} + +impl Default for Configuration { + fn default() -> Self { + Self { + actor_channel_capacity: DEFAULT_ACTOR_CHANNEL_CAPACITY, + } + } +} diff --git a/config/src/queue.rs b/config/src/queue.rs new file mode 100644 index 00000000000..ccb5047a3f7 --- /dev/null +++ b/config/src/queue.rs @@ -0,0 +1,36 @@ +//! Module for `Queue`-related configuration and structs. +use iroha_config_base::derive::Configurable; +use serde::{Deserialize, Serialize}; + +const DEFAULT_MAXIMUM_TRANSACTIONS_IN_BLOCK: u32 = 2_u32.pow(13); +const DEFAULT_MAXIMUM_TRANSACTIONS_IN_QUEUE: u32 = 2_u32.pow(16); +// 24 hours +const DEFAULT_TRANSACTION_TIME_TO_LIVE_MS: u64 = 24 * 60 * 60 * 1000; +const DEFAULT_FUTURE_THRESHOLD_MS: u64 = 1000; + +/// `Queue` configuration. +#[derive(Copy, Clone, Deserialize, Serialize, Debug, Configurable, PartialEq, Eq)] +#[serde(rename_all = "UPPERCASE")] +#[serde(default)] +#[config(env_prefix = "QUEUE_")] +pub struct Configuration { + /// The upper limit of the number of transactions per block. + pub maximum_transactions_in_block: u32, + /// The upper limit of the number of transactions waiting in the queue. + pub maximum_transactions_in_queue: u32, + /// The transaction will be dropped after this time if it is still in the queue. + pub transaction_time_to_live_ms: u64, + /// The threshold to determine if a transaction has been tampered to have a future timestamp. + pub future_threshold_ms: u64, +} + +impl Default for Configuration { + fn default() -> Self { + Self { + maximum_transactions_in_block: DEFAULT_MAXIMUM_TRANSACTIONS_IN_BLOCK, + maximum_transactions_in_queue: DEFAULT_MAXIMUM_TRANSACTIONS_IN_QUEUE, + transaction_time_to_live_ms: DEFAULT_TRANSACTION_TIME_TO_LIVE_MS, + future_threshold_ms: DEFAULT_FUTURE_THRESHOLD_MS, + } + } +} diff --git a/core/src/sumeragi/config.rs b/config/src/sumeragi.rs similarity index 76% rename from core/src/sumeragi/config.rs rename to config/src/sumeragi.rs index ca757007ade..ebb9d8897cb 100644 --- a/core/src/sumeragi/config.rs +++ b/config/src/sumeragi.rs @@ -2,7 +2,7 @@ use std::{collections::HashSet, fmt::Debug, fs::File, io::BufReader, path::Path}; use eyre::{Result, WrapErr}; -use iroha_config::derive::Configurable; +use iroha_config_base::derive::{view, Configurable}; use iroha_crypto::prelude::*; use iroha_data_model::{prelude::*, transaction}; use serde::{Deserialize, Serialize}; @@ -18,37 +18,42 @@ const DEFAULT_ACTOR_CHANNEL_CAPACITY: u32 = 100; const DEFAULT_GOSSIP_PERIOD_MS: u64 = 1000; const DEFAULT_GOSSIP_BATCH_SIZE: u32 = 500; -/// `SumeragiConfiguration` provides an ability to define parameters such as `BLOCK_TIME_MS` -/// and list of `TRUSTED_PEERS`. -#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize, Configurable)] -#[serde(default)] -#[serde(rename_all = "UPPERCASE")] -#[config(env_prefix = "SUMERAGI_")] -pub struct SumeragiConfiguration { - /// Key pair of private and public keys. - #[serde(skip)] - pub key_pair: KeyPair, - /// Current Peer Identification. - pub peer_id: PeerId, - /// Amount of time peer waits for the `CreatedBlock` message after getting a `TransactionReceipt` - pub block_time_ms: u64, - /// Optional list of predefined trusted peers. - pub trusted_peers: TrustedPeers, - /// Amount of time Peer waits for CommitMessage from the proxy tail. - pub commit_time_limit_ms: u64, - /// Amount of time Peer waits for TxReceipt from the leader. - pub tx_receipt_time_limit_ms: u64, - /// Limits to which transactions must adhere - pub transaction_limits: TransactionLimits, - /// Buffer capacity of actor's MPSC channel - pub actor_channel_capacity: u32, - /// Maximum number of transactions in tx gossip batch message. While configuring this, attention should be payed to `p2p` max message size. - pub gossip_batch_size: u32, - /// Period in milliseconds for pending transaction gossiping between peers. - pub gossip_period_ms: u64, +// Generate `ConfigurationView` without keys +view! { + /// `Sumeragi` configuration. + /// [`Configuration`] provides an ability to define parameters such as `BLOCK_TIME_MS` + /// and a list of `TRUSTED_PEERS`. + #[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize, Configurable)] + #[serde(default)] + #[serde(rename_all = "UPPERCASE")] + #[config(env_prefix = "SUMERAGI_")] + pub struct Configuration { + /// The key pair consisting of a private and a public key. + #[serde(skip)] + #[view(ignore)] + pub key_pair: KeyPair, + /// Current Peer Identification. + pub peer_id: PeerId, + /// The period of time a peer waits for the `CreatedBlock` message after getting a `TransactionReceipt` + pub block_time_ms: u64, + /// Optional list of predefined trusted peers. + pub trusted_peers: TrustedPeers, + /// The period of time a peer waits for `CommitMessage` from the proxy tail. + pub commit_time_limit_ms: u64, + /// The period of time a peer waits for `TxReceipt` from the leader. + pub tx_receipt_time_limit_ms: u64, + /// The limits to which transactions must adhere + pub transaction_limits: TransactionLimits, + /// Buffer capacity of actor's MPSC channel + pub actor_channel_capacity: u32, + /// Maximum number of transactions in tx gossip batch message. While configuring this, pay attention to `p2p` max message size. + pub gossip_batch_size: u32, + /// Period in milliseconds for pending transaction gossiping between peers. + pub gossip_period_ms: u64, + } } -impl Default for SumeragiConfiguration { +impl Default for Configuration { fn default() -> Self { Self { key_pair: Self::placeholder_keypair(), @@ -68,7 +73,7 @@ impl Default for SumeragiConfiguration { } } -impl SumeragiConfiguration { +impl Configuration { /// Key-pair used by default for demo purposes #[allow(clippy::expect_used)] fn placeholder_keypair() -> KeyPair { @@ -115,7 +120,7 @@ impl SumeragiConfiguration { } /// `SumeragiConfiguration` provides an ability to define parameters -/// such as `BLOCK_TIME_MS` and list of `TRUSTED_PEERS`. +/// such as `BLOCK_TIME_MS` and a list of `TRUSTED_PEERS`. #[derive(Debug, Clone, Default, PartialEq, Eq, Deserialize, Serialize)] #[serde(rename_all = "UPPERCASE")] #[serde(transparent)] diff --git a/telemetry/src/config.rs b/config/src/telemetry.rs similarity index 65% rename from telemetry/src/config.rs rename to config/src/telemetry.rs index 253f8d4fafc..f28e78fbfe6 100644 --- a/telemetry/src/config.rs +++ b/config/src/telemetry.rs @@ -1,12 +1,9 @@ -#[cfg(feature = "dev-telemetry")] -use std::path::PathBuf; +//! Module for telemetry-related configuration and structs. -use iroha_config::derive::Configurable; +use iroha_config_base::derive::Configurable; use serde::{Deserialize, Serialize}; use url::Url; -use crate::retry_period::RetryPeriod; - /// Configuration parameters container #[derive(Clone, Deserialize, Serialize, Debug, Configurable, PartialEq, Eq)] #[serde(rename_all = "UPPERCASE")] @@ -26,9 +23,8 @@ pub struct Configuration { #[serde(default = "default_max_retry_delay_exponent")] pub max_retry_delay_exponent: u8, /// The filepath that to write dev-telemetry to - #[cfg(feature = "dev-telemetry")] #[config(serde_as_str)] - pub file: Option, + pub file: Option, } impl Default for Configuration { @@ -36,18 +32,25 @@ impl Default for Configuration { Self { name: None, url: None, - min_retry_period: RetryPeriod::DEFAULT_MIN_RETRY_PERIOD, - max_retry_delay_exponent: RetryPeriod::DEFAULT_MAX_RETRY_DELAY_EXPONENT, - #[cfg(feature = "dev-telemetry")] + min_retry_period: retry_period::DEFAULT_MIN_RETRY_PERIOD, + max_retry_delay_exponent: retry_period::DEFAULT_MAX_RETRY_DELAY_EXPONENT, file: None, } } } const fn default_min_retry_period() -> u64 { - RetryPeriod::DEFAULT_MIN_RETRY_PERIOD + retry_period::DEFAULT_MIN_RETRY_PERIOD } const fn default_max_retry_delay_exponent() -> u8 { - RetryPeriod::DEFAULT_MAX_RETRY_DELAY_EXPONENT + retry_period::DEFAULT_MAX_RETRY_DELAY_EXPONENT +} + +/// `RetryPeriod` configuration +pub mod retry_period { + /// Default minimal retry period + pub const DEFAULT_MIN_RETRY_PERIOD: u64 = 1; + /// Default maximum exponent for the retry delay + pub const DEFAULT_MAX_RETRY_DELAY_EXPONENT: u8 = 4; } diff --git a/config/src/torii.rs b/config/src/torii.rs new file mode 100644 index 00000000000..8bae8c177ac --- /dev/null +++ b/config/src/torii.rs @@ -0,0 +1,78 @@ +//! `Torii` configuration as well as the default values for the URLs used for the main endpoints: `p2p`, `telemetry`, but not `api`. +use iroha_config_base::derive::Configurable; +use serde::{Deserialize, Serialize}; + +/// Default socket for p2p communication +pub const DEFAULT_TORII_P2P_ADDR: &str = "127.0.0.1:1337"; +/// Default socket for reporting internal status and metrics +pub const DEFAULT_TORII_TELEMETRY_URL: &str = "127.0.0.1:8180"; +/// Default maximum size of single transaction +pub const DEFAULT_TORII_MAX_TRANSACTION_SIZE: u32 = 2_u32.pow(15); +/// Default upper bound on `content-length` specified in the HTTP request header +pub const DEFAULT_TORII_MAX_CONTENT_LENGTH: u32 = 2_u32.pow(12) * 4000; + +/// Structure that defines the configuration parameters of `Torii` which is the routing module. +/// For example the `p2p_addr`, which is used for consensus and block-synchronisation purposes, +/// as well as `max_transaction_size`. +#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize, Configurable)] +#[serde(rename_all = "UPPERCASE")] +#[serde(default)] +#[config(env_prefix = "TORII_")] +pub struct Configuration { + /// Torii URL for p2p communication for consensus and block synchronization purposes. + pub p2p_addr: String, + /// Torii URL for client API. + pub api_url: String, + /// Torii URL for reporting internal status and metrics for administration. + pub telemetry_url: String, + /// Maximum number of bytes in raw transaction. Used to prevent from DOS attacks. + pub max_transaction_size: u32, + /// Maximum number of bytes in raw message. Used to prevent from DOS attacks. + pub max_content_len: u32, +} + +impl Default for Configuration { + fn default() -> Self { + Self { + p2p_addr: DEFAULT_TORII_P2P_ADDR.to_owned(), + api_url: uri::DEFAULT_API_URL.to_owned(), + telemetry_url: DEFAULT_TORII_TELEMETRY_URL.to_owned(), + max_transaction_size: DEFAULT_TORII_MAX_TRANSACTION_SIZE, + max_content_len: DEFAULT_TORII_MAX_CONTENT_LENGTH, + } + } +} + +pub mod uri { + //! URI that `Torii` uses to route incoming requests. + + /// Default socket for listening on external requests + pub const DEFAULT_API_URL: &str = "127.0.0.1:8080"; + /// Query URI is used to handle incoming Query requests. + pub const QUERY: &str = "query"; + /// Transaction URI is used to handle incoming ISI requests. + pub const TRANSACTION: &str = "transaction"; + /// Block URI is used to handle incoming Block requests. + pub const CONSENSUS: &str = "consensus"; + /// Health URI is used to handle incoming Healthcheck requests. + pub const HEALTH: &str = "health"; + /// The URI used for block synchronization. + pub const BLOCK_SYNC: &str = "block/sync"; + /// The web socket uri used to subscribe to block and transactions statuses. + pub const SUBSCRIPTION: &str = "events"; + /// The web socket uri used to subscribe to blocks stream. + pub const BLOCKS_STREAM: &str = "block/stream"; + /// Get pending transactions. + pub const PENDING_TRANSACTIONS: &str = "pending_transactions"; + /// The URI for local config changing inspecting + pub const CONFIGURATION: &str = "configuration"; + /// URI to report status for administration + pub const STATUS: &str = "status"; + /// Metrics URI is used to export metrics according to [Prometheus + /// Guidance](https://prometheus.io/docs/instrumenting/writing_exporters/). + pub const METRICS: &str = "metrics"; + /// URI for retrieving the schema with which Iroha was built. + pub const SCHEMA: &str = "schema"; + /// URI for getting the API version currently used + pub const API_VERSION: &str = "api_version"; +} diff --git a/config/src/wasm.rs b/config/src/wasm.rs new file mode 100644 index 00000000000..48739790521 --- /dev/null +++ b/config/src/wasm.rs @@ -0,0 +1,28 @@ +//! Module for wasm-related configuration and structs. +use iroha_config_base::derive::Configurable; +use serde::{Deserialize, Serialize}; + +const DEFAULT_FUEL_LIMIT: u64 = 1_000_000; +const DEFAULT_MAX_MEMORY: u32 = 500 * 2_u32.pow(20); // 500 MiB + +/// `WebAssembly Runtime` configuration. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize, Configurable)] +#[config(env_prefix = "WASM_")] +#[serde(rename_all = "UPPERCASE", default)] +pub struct Configuration { + /// The fuel limit determines the maximum number of instructions that can be executed during the execution of a smart contract. + /// Every WASM instruction costs approximately 1 unit of fuel. See + /// [`wasmtime` reference](https://docs.rs/wasmtime/0.29.0/wasmtime/struct.Store.html#method.add_fuel) + pub fuel_limit: u64, + /// Maximum amount of linear memory a given smartcontract can allocate + pub max_memory: u32, +} + +impl Default for Configuration { + fn default() -> Self { + Configuration { + fuel_limit: DEFAULT_FUEL_LIMIT, + max_memory: DEFAULT_MAX_MEMORY, + } + } +} diff --git a/config/src/wsv.rs b/config/src/wsv.rs new file mode 100644 index 00000000000..24d0a4166aa --- /dev/null +++ b/config/src/wsv.rs @@ -0,0 +1,42 @@ +//! Module for `WorldStateView`-related configuration and structs. + +use iroha_config_base::derive::Configurable; +use iroha_data_model::{metadata::Limits as MetadataLimits, LengthLimits}; +use serde::{Deserialize, Serialize}; + +use crate::wasm; + +const DEFAULT_METADATA_LIMITS: MetadataLimits = MetadataLimits::new(2_u32.pow(20), 2_u32.pow(12)); +const DEFAULT_IDENT_LENGTH_LIMITS: LengthLimits = LengthLimits::new(1, 2_u32.pow(7)); + +/// `WorldStateView` configuration. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize, Configurable)] +#[config(env_prefix = "WSV_")] +#[serde(rename_all = "UPPERCASE", default)] +pub struct Configuration { + /// [`MetadataLimits`] for every asset with store. + pub asset_metadata_limits: MetadataLimits, + /// [`MetadataLimits`] of any asset definition metadata. + pub asset_definition_metadata_limits: MetadataLimits, + /// [`MetadataLimits`] of any account metadata. + pub account_metadata_limits: MetadataLimits, + /// [`MetadataLimits`] of any domain metadata. + pub domain_metadata_limits: MetadataLimits, + /// [`LengthLimits`] for the number of chars in identifiers that can be stored in the WSV. + pub ident_length_limits: LengthLimits, + /// WASM runtime configuration + pub wasm_runtime_config: wasm::Configuration, +} + +impl Default for Configuration { + fn default() -> Self { + Configuration { + asset_metadata_limits: DEFAULT_METADATA_LIMITS, + asset_definition_metadata_limits: DEFAULT_METADATA_LIMITS, + account_metadata_limits: DEFAULT_METADATA_LIMITS, + domain_metadata_limits: DEFAULT_METADATA_LIMITS, + ident_length_limits: DEFAULT_IDENT_LENGTH_LIMITS, + wasm_runtime_config: wasm::Configuration::default(), + } + } +} diff --git a/core/src/block.rs b/core/src/block.rs index 2b56d210e79..20ea49d79ad 100644 --- a/core/src/block.rs +++ b/core/src/block.rs @@ -10,6 +10,9 @@ use std::{collections::BTreeSet, error::Error, iter, marker::PhantomData}; use dashmap::{mapref::one::Ref as MapRef, DashMap}; use eyre::{eyre, Context, Result}; +use iroha_config::sumeragi::{ + DEFAULT_BLOCK_TIME_MS, DEFAULT_COMMIT_TIME_LIMIT_MS, DEFAULT_TX_RECEIPT_TIME_LIMIT_MS, +}; use iroha_crypto::{HashOf, KeyPair, MerkleTree, SignatureOf, SignaturesOf}; use iroha_data_model::{ block_value::{BlockHeaderValue, BlockValue}, @@ -24,7 +27,6 @@ use parity_scale_codec::{Decode, Encode}; use crate::{ prelude::*, sumeragi::{ - config::*, network_topology::Topology, view_change::{Proof, ProofChain as ViewChangeProofs}, }, diff --git a/core/src/block_sync.rs b/core/src/block_sync.rs index cfc0d9682e4..223cb7392bc 100644 --- a/core/src/block_sync.rs +++ b/core/src/block_sync.rs @@ -3,15 +3,13 @@ use std::{fmt::Debug, sync::Arc, time::Duration}; use iroha_actor::{broker::*, prelude::*, Context}; +use iroha_config::block_sync::Configuration; use iroha_crypto::SignatureOf; use iroha_data_model::prelude::*; use iroha_logger::prelude::*; use rand::{prelude::SliceRandom, SeedableRng}; -use self::{ - config::BlockSyncConfiguration, - message::{Message, *}, -}; +use self::message::{Message, *}; use crate::{ prelude::*, sumeragi::{ @@ -52,7 +50,7 @@ pub trait BlockSynchronizerTrait: Actor + Handler + Handler, sumeragi: AlwaysAddr, peer_id: PeerId, @@ -64,7 +62,7 @@ impl BlockSynchronizerTrait for BlockSynchronizer { type Sumeragi = S; fn from_configuration( - config: &BlockSyncConfiguration, + config: &Configuration, wsv: Arc, sumeragi: AlwaysAddr, peer_id: PeerId, @@ -333,38 +331,3 @@ pub mod message { } } } - -/// This module contains all configuration related logic. -pub mod config { - use iroha_config::derive::Configurable; - use serde::{Deserialize, Serialize}; - - const DEFAULT_BLOCK_BATCH_SIZE: u32 = 4; - const DEFAULT_GOSSIP_PERIOD_MS: u64 = 10000; - const DEFAULT_ACTOR_CHANNEL_CAPACITY: u32 = 100; - - /// Configuration for `BlockSynchronizer`. - #[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize, Configurable)] - #[serde(rename_all = "UPPERCASE")] - #[serde(default)] - #[config(env_prefix = "BLOCK_SYNC_")] - pub struct BlockSyncConfiguration { - /// The time between sending requests for latest block. - pub gossip_period_ms: u64, - /// The number of blocks that can be sent in one message. - /// Underlying network (`iroha_network`) should support transferring messages this large. - pub block_batch_size: u32, - /// Buffer capacity of actor's MPSC channel - pub actor_channel_capacity: u32, - } - - impl Default for BlockSyncConfiguration { - fn default() -> Self { - Self { - gossip_period_ms: DEFAULT_GOSSIP_PERIOD_MS, - block_batch_size: DEFAULT_BLOCK_BATCH_SIZE, - actor_channel_capacity: DEFAULT_ACTOR_CHANNEL_CAPACITY, - } - } - } -} diff --git a/core/src/genesis.rs b/core/src/genesis.rs index 72305228327..b080d9a4e46 100644 --- a/core/src/genesis.rs +++ b/core/src/genesis.rs @@ -8,6 +8,7 @@ use std::{collections::HashSet, fmt::Debug, fs::File, io::BufReader, ops::Deref, use derive_more::Deref; use eyre::{eyre, Result, WrapErr}; use iroha_actor::Addr; +use iroha_config::genesis::Configuration; use iroha_crypto::{KeyPair, PublicKey}; use iroha_data_model::{asset::AssetDefinition, prelude::*}; use iroha_primitives::small::{smallvec, SmallVec}; @@ -15,7 +16,6 @@ use iroha_schema::prelude::*; use serde::{Deserialize, Serialize}; use tokio::{time, time::Duration}; -pub use self::config::GenesisConfiguration; use crate::{ sumeragi::{ fault::{FaultInjection, SumeragiWithFault}, @@ -45,7 +45,7 @@ pub trait GenesisNetworkTrait: fn from_configuration( submit_genesis: bool, raw_block: RawGenesisBlock, - genesis_config: &Option, + genesis_config: &Option, transaction_limits: &TransactionLimits, ) -> Result>; @@ -85,7 +85,7 @@ pub trait GenesisNetworkTrait: .await } - /// See [`GenesisConfiguration`] docs. + /// See [`Configuration`] docs. fn genesis_submission_delay_ms(&self) -> u64; } @@ -165,7 +165,7 @@ impl GenesisNetworkTrait for GenesisNetwork { fn from_configuration( submit_genesis: bool, raw_block: RawGenesisBlock, - genesis_config: &Option, + genesis_config: &Option, tx_limits: &TransactionLimits, ) -> Result> { #![allow(clippy::unwrap_in_result)] @@ -322,84 +322,6 @@ impl GenesisTransaction { } } -/// Module with genesis configuration logic. -pub mod config { - use iroha_config::derive::Configurable; - use iroha_crypto::{KeyPair, PrivateKey, PublicKey}; - use serde::{Deserialize, Serialize}; - - const DEFAULT_WAIT_FOR_PEERS_RETRY_COUNT_LIMIT: u64 = 100; - const DEFAULT_WAIT_FOR_PEERS_RETRY_PERIOD_MS: u64 = 500; - const DEFAULT_GENESIS_SUBMISSION_DELAY_MS: u64 = 1000; - - #[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize, Configurable)] - #[serde(default)] - #[serde(rename_all = "UPPERCASE")] - #[config(env_prefix = "IROHA_GENESIS_")] - /// Configuration of the genesis block and the process of its submission. - pub struct GenesisConfiguration { - /// The genesis account public key, should be supplied to all peers. - #[config(serde_as_str)] - pub account_public_key: PublicKey, - /// Genesis account private key, only needed on the peer that submits the genesis block. - pub account_private_key: Option, - /// Number of attempts to connect to peers, while waiting for them to submit genesis. - #[serde(default = "default_wait_for_peers_retry_count_limit")] - pub wait_for_peers_retry_count_limit: u64, - /// Period in milliseconds in which to retry connecting to peers, while waiting for them to submit genesis. - #[serde(default = "default_wait_for_peers_retry_period_ms")] - pub wait_for_peers_retry_period_ms: u64, - /// Delay before genesis block submission after minimum number of peers were discovered to be online. - /// Used to ensure that other peers had time to connect to each other. - #[serde(default = "default_genesis_submission_delay_ms")] - pub genesis_submission_delay_ms: u64, - } - - #[allow(clippy::expect_used)] - impl Default for GenesisConfiguration { - fn default() -> Self { - let (public_key, private_key) = Self::placeholder_keypair().into(); - - Self { - account_public_key: public_key, - account_private_key: Some(private_key), - wait_for_peers_retry_count_limit: DEFAULT_WAIT_FOR_PEERS_RETRY_COUNT_LIMIT, - wait_for_peers_retry_period_ms: DEFAULT_WAIT_FOR_PEERS_RETRY_PERIOD_MS, - genesis_submission_delay_ms: DEFAULT_GENESIS_SUBMISSION_DELAY_MS, - } - } - } - - impl GenesisConfiguration { - /// Key-pair used by default for demo purposes - #[allow(clippy::expect_used)] - fn placeholder_keypair() -> KeyPair { - let public_key = - "ed01204cffd0ee429b1bdd36b3910ec570852b8bb63f18750341772fb46bc856c5caaf" - .parse() - .expect("Public key not in mulithash format"); - let private_key = PrivateKey::from_hex( - iroha_crypto::Algorithm::Ed25519, - "d748e18ce60cb30dea3e73c9019b7af45a8d465e3d71bcc9a5ef99a008205e534cffd0ee429b1bdd36b3910ec570852b8bb63f18750341772fb46bc856c5caaf" - ).expect("Private key not hex encoded"); - - KeyPair::new(public_key, private_key).expect("Key pair mismatch") - } - } - - const fn default_wait_for_peers_retry_count_limit() -> u64 { - DEFAULT_WAIT_FOR_PEERS_RETRY_COUNT_LIMIT - } - - const fn default_wait_for_peers_retry_period_ms() -> u64 { - DEFAULT_WAIT_FOR_PEERS_RETRY_PERIOD_MS - } - - const fn default_genesis_submission_delay_ms() -> u64 { - DEFAULT_GENESIS_SUBMISSION_DELAY_MS - } -} - /// Builder type for `RawGenesisBlock` that does /// not perform any correctness checking on the block /// produced. Use with caution in tests and other things @@ -505,10 +427,10 @@ mod tests { let _genesis_block = GenesisNetwork::from_configuration( true, RawGenesisBlock::default(), - &Some(GenesisConfiguration { + &Some(Configuration { account_public_key: public_key, account_private_key: Some(private_key), - ..GenesisConfiguration::default() + ..Configuration::default() }), &tx_limits, )?; diff --git a/core/src/kura.rs b/core/src/kura.rs index 21434505ed9..84108611e78 100644 --- a/core/src/kura.rs +++ b/core/src/kura.rs @@ -12,10 +12,10 @@ use std::{ use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; use iroha_actor::broker::*; +use iroha_config::kura::{Configuration, Mode}; use iroha_crypto::HashOf; use iroha_logger::prelude::*; use iroha_version::scale::{DecodeVersioned, EncodeVersioned}; -use serde::{Deserialize, Serialize}; use tokio::sync::mpsc::{channel, Receiver, Sender}; use crate::{block::VersionedCommittedBlock, block_sync::ContinueSync, prelude::*, sumeragi}; @@ -87,7 +87,7 @@ impl Kura { /// to access the block store indicated by the /// path in the configuration. pub fn from_configuration( - configuration: &config::KuraConfiguration, + configuration: &Configuration, wsv: Arc, broker: Broker, ) -> Result> { @@ -520,22 +520,6 @@ impl BlockStoreTrait for StdFileBlockStore { } } -/// Kura work mode. -#[derive(Debug, Clone, Copy, Deserialize, Serialize, PartialEq, Eq)] -#[serde(rename_all = "snake_case")] -pub enum Mode { - /// Strict validation of all blocks. - Strict, - /// Fast initialization with basic checks. - Fast, -} - -impl Default for Mode { - fn default() -> Self { - Mode::Strict - } -} - type Result = std::result::Result; /// Error variants for persistent storage logic #[derive(thiserror::Error, Debug)] @@ -555,80 +539,6 @@ pub enum Error { OutOfBoundsBlockRead(u64, u64), } -/// This module contains all configuration related logic. -pub mod config { - use std::{num::NonZeroU64, path::Path}; - - use eyre::{eyre, Result}; - use iroha_config::derive::Configurable; - use serde::{Deserialize, Serialize}; - - use super::Mode; - - const DEFAULT_BLOCKS_PER_STORAGE_FILE: u64 = 1000_u64; - const DEFAULT_BLOCK_STORE_PATH: &str = "./blocks"; - const DEFAULT_ACTOR_CHANNEL_CAPACITY: u32 = 100; - - /// Configuration of kura - #[derive(Clone, Deserialize, Serialize, Debug, Configurable, PartialEq, Eq)] - #[serde(rename_all = "UPPERCASE")] - #[config(env_prefix = "KURA_")] - pub struct KuraConfiguration { - /// Possible modes: `strict`, `fast`. - #[serde(default)] - pub init_mode: Mode, - /// Path to the existing block store folder or path to create new folder. - #[serde(default = "default_block_store_path")] - pub block_store_path: String, - /// Maximum number of blocks to write into single storage file - #[serde(default = "default_blocks_per_storage_file")] - pub blocks_per_storage_file: NonZeroU64, - /// Default buffer capacity of actor's MPSC channel - #[serde(default = "default_actor_channel_capacity")] - pub actor_channel_capacity: u32, - } - - impl Default for KuraConfiguration { - fn default() -> Self { - Self { - init_mode: Mode::default(), - block_store_path: default_block_store_path(), - blocks_per_storage_file: default_blocks_per_storage_file(), - actor_channel_capacity: default_actor_channel_capacity(), - } - } - } - - impl KuraConfiguration { - /// Set `block_store_path` configuration parameter - will overwrite the existing one. - /// - /// # Errors - /// If path is not valid this method will fail. - pub fn block_store_path(&mut self, path: &Path) -> Result<()> { - self.block_store_path = path - .to_str() - .ok_or_else(|| eyre!("Failed to yield slice from path"))? - .to_owned(); - Ok(()) - } - } - - fn default_block_store_path() -> String { - DEFAULT_BLOCK_STORE_PATH.to_owned() - } - - fn default_blocks_per_storage_file() -> NonZeroU64 { - #![allow(clippy::expect_used)] - NonZeroU64::new(DEFAULT_BLOCKS_PER_STORAGE_FILE).expect( - "Default BLOCKS_PER_STORAGE value is set to non-positive value. This must not happen", - ) - } - - const fn default_actor_channel_capacity() -> u32 { - DEFAULT_ACTOR_CHANNEL_CAPACITY - } -} - #[allow(clippy::unwrap_used)] #[cfg(test)] mod tests { diff --git a/core/src/queue.rs b/core/src/queue.rs index fcd90d48f5b..b4dc3dee424 100644 --- a/core/src/queue.rs +++ b/core/src/queue.rs @@ -6,12 +6,12 @@ use std::{sync::Arc, time::Duration}; use crossbeam_queue::ArrayQueue; use dashmap::{mapref::entry::Entry, DashMap}; use eyre::{Report, Result}; +use iroha_config::queue::Configuration; use iroha_crypto::HashOf; use iroha_data_model::transaction::prelude::*; use rand::seq::IteratorRandom; use thiserror::Error; -pub use self::config::Configuration; use crate::prelude::*; /// Lockfree queue for transactions @@ -215,45 +215,6 @@ impl Queue { } } -/// This module contains all configuration related logic. -pub mod config { - use iroha_config::derive::Configurable; - use serde::{Deserialize, Serialize}; - - const DEFAULT_MAXIMUM_TRANSACTIONS_IN_BLOCK: u32 = 2_u32.pow(13); - const DEFAULT_MAXIMUM_TRANSACTIONS_IN_QUEUE: u32 = 2_u32.pow(16); - // 24 hours - const DEFAULT_TRANSACTION_TIME_TO_LIVE_MS: u64 = 24 * 60 * 60 * 1000; - const DEFAULT_FUTURE_THRESHOLD_MS: u64 = 1000; - - /// Configuration for `Queue`. - #[derive(Copy, Clone, Deserialize, Serialize, Debug, Configurable, PartialEq, Eq)] - #[serde(rename_all = "UPPERCASE")] - #[serde(default)] - #[config(env_prefix = "QUEUE_")] - pub struct Configuration { - /// The upper limit of the number of transactions per block. - pub maximum_transactions_in_block: u32, - /// The upper limit of the number of transactions waiting in this queue. - pub maximum_transactions_in_queue: u32, - /// The transaction will be dropped after this time if it is still in a `Queue`. - pub transaction_time_to_live_ms: u64, - /// The threshold to determine if a transaction has been tampered to have a future timestamp. - pub future_threshold_ms: u64, - } - - impl Default for Configuration { - fn default() -> Self { - Self { - maximum_transactions_in_block: DEFAULT_MAXIMUM_TRANSACTIONS_IN_BLOCK, - maximum_transactions_in_queue: DEFAULT_MAXIMUM_TRANSACTIONS_IN_QUEUE, - transaction_time_to_live_ms: DEFAULT_TRANSACTION_TIME_TO_LIVE_MS, - future_threshold_ms: DEFAULT_FUTURE_THRESHOLD_MS, - } - } - } -} - #[cfg(test)] mod tests { #![allow(clippy::restriction, clippy::all, clippy::pedantic)] diff --git a/core/src/smartcontracts/wasm.rs b/core/src/smartcontracts/wasm.rs index 47068c8e8aa..371ff9fad8c 100644 --- a/core/src/smartcontracts/wasm.rs +++ b/core/src/smartcontracts/wasm.rs @@ -3,8 +3,8 @@ //! to wasm format and submitted in a transaction #![allow(clippy::expect_used)] -use config::Configuration; use eyre::WrapErr; +use iroha_config::wasm::Configuration; use iroha_data_model::{prelude::*, ParseError}; use iroha_logger::prelude::*; use parity_scale_codec::{Decode, Encode}; @@ -518,37 +518,6 @@ impl<'wrld> Runtime<'wrld> { } } -/// This module contains all configuration related logic. -pub mod config { - use iroha_config::derive::Configurable; - use serde::{Deserialize, Serialize}; - - const DEFAULT_FUEL_LIMIT: u64 = 1_000_000; - const DEFAULT_MAX_MEMORY: u32 = 500 * 2_u32.pow(20); // 500 MiB - - /// [`WebAssembly Runtime`](super::Runtime) configuration. - #[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize, Configurable)] - #[config(env_prefix = "WASM_")] - #[serde(rename_all = "UPPERCASE", default)] - pub struct Configuration { - /// Every WASM instruction costs approximately 1 unit of fuel. See - /// [`wasmtime` reference](https://docs.rs/wasmtime/0.29.0/wasmtime/struct.Store.html#method.add_fuel) - pub fuel_limit: u64, - - /// Maximum amount of linear memory a given smartcontract can allocate - pub max_memory: u32, - } - - impl Default for Configuration { - fn default() -> Self { - Configuration { - fuel_limit: DEFAULT_FUEL_LIMIT, - max_memory: DEFAULT_MAX_MEMORY, - } - } - } -} - #[cfg(test)] mod tests { #![allow(clippy::restriction)] diff --git a/core/src/sumeragi/fault.rs b/core/src/sumeragi/fault.rs index 4263b16e761..cb5129f41cd 100644 --- a/core/src/sumeragi/fault.rs +++ b/core/src/sumeragi/fault.rs @@ -2,7 +2,9 @@ //! should be reserved for testing, and only [`NoFault`], should be //! used in code. -use super::{config::SumeragiConfiguration, *}; +use iroha_config::sumeragi::Configuration; + +use super::*; /// Fault injection for consensus tests pub trait FaultInjection: Send + Sync + Sized + 'static { @@ -92,7 +94,7 @@ impl SumeragiTrait for SumeragiWithFa type GenesisNetwork = G; fn from_configuration( - configuration: &SumeragiConfiguration, + configuration: &Configuration, events_sender: EventsSender, wsv: Arc, transaction_validator: TransactionValidator, diff --git a/core/src/sumeragi/mod.rs b/core/src/sumeragi/mod.rs index 304984d5011..dcffce9cbc6 100644 --- a/core/src/sumeragi/mod.rs +++ b/core/src/sumeragi/mod.rs @@ -12,6 +12,7 @@ use std::{ use eyre::{eyre, Result}; use iroha_actor::{broker::*, prelude::*, Context}; +use iroha_config::sumeragi::Configuration; use iroha_crypto::{HashOf, KeyPair}; use iroha_data_model::prelude::*; use iroha_logger::prelude::*; @@ -19,7 +20,6 @@ use iroha_p2p::{ConnectPeer, DisconnectPeer}; use network_topology::{Role, Topology}; use rand::prelude::SliceRandom; -pub mod config; pub mod fault; pub mod message; pub mod network_topology; @@ -73,7 +73,7 @@ pub trait SumeragiTrait: /// Can fail during initing network topology #[allow(clippy::too_many_arguments)] fn from_configuration( - configuration: &config::SumeragiConfiguration, + configuration: &Configuration, events_sender: EventsSender, wsv: Arc, transaction_validator: TransactionValidator, diff --git a/core/src/wsv.rs b/core/src/wsv.rs index ef810adc915..8ffae3373ae 100644 --- a/core/src/wsv.rs +++ b/core/src/wsv.rs @@ -3,13 +3,13 @@ use std::{convert::Infallible, fmt::Debug, sync::Arc, time::Duration}; -use config::Configuration; use dashmap::{ mapref::one::{Ref as DashMapRef, RefMut as DashMapRefMut}, DashSet, }; use eyre::Result; use getset::Getters; +use iroha_config::wsv::Configuration; use iroha_crypto::HashOf; use iroha_data_model::prelude::*; use iroha_logger::prelude::*; @@ -802,51 +802,6 @@ impl WorldStateView { } } -/// This module contains all configuration related logic. -pub mod config { - use iroha_config::derive::Configurable; - use iroha_data_model::{metadata::Limits as MetadataLimits, LengthLimits}; - use serde::{Deserialize, Serialize}; - - use crate::smartcontracts::wasm; - - const DEFAULT_METADATA_LIMITS: MetadataLimits = - MetadataLimits::new(2_u32.pow(20), 2_u32.pow(12)); - const DEFAULT_IDENT_LENGTH_LIMITS: LengthLimits = LengthLimits::new(1, 2_u32.pow(7)); - - /// [`WorldStateView`](super::WorldStateView) configuration. - #[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize, Configurable)] - #[config(env_prefix = "WSV_")] - #[serde(rename_all = "UPPERCASE", default)] - pub struct Configuration { - /// [`MetadataLimits`] for every asset with store. - pub asset_metadata_limits: MetadataLimits, - /// [`MetadataLimits`] of any asset definition's metadata. - pub asset_definition_metadata_limits: MetadataLimits, - /// [`MetadataLimits`] of any account's metadata. - pub account_metadata_limits: MetadataLimits, - /// [`MetadataLimits`] of any domain's metadata. - pub domain_metadata_limits: MetadataLimits, - /// [`LengthLimits`] for the number of chars in identifiers that can be stored in the WSV. - pub ident_length_limits: LengthLimits, - /// [`WASM Runtime`](wasm::Runtime) configuration - pub wasm_runtime_config: wasm::config::Configuration, - } - - impl Default for Configuration { - fn default() -> Self { - Configuration { - asset_metadata_limits: DEFAULT_METADATA_LIMITS, - asset_definition_metadata_limits: DEFAULT_METADATA_LIMITS, - account_metadata_limits: DEFAULT_METADATA_LIMITS, - domain_metadata_limits: DEFAULT_METADATA_LIMITS, - ident_length_limits: DEFAULT_IDENT_LENGTH_LIMITS, - wasm_runtime_config: wasm::config::Configuration::default(), - } - } - } -} - #[cfg(test)] mod tests { #![allow(clippy::restriction)] diff --git a/core/test_network/Cargo.toml b/core/test_network/Cargo.toml index fbe73f8eafc..1d1e1e484f6 100644 --- a/core/test_network/Cargo.toml +++ b/core/test_network/Cargo.toml @@ -13,6 +13,7 @@ query = [] iroha = { path = "../../cli", features = ["test-network"] } iroha_actor = { version = "=2.0.0-pre-rc.5", path = "../../actor" } iroha_client = { version = "=2.0.0-pre-rc.5", path = "../../client" } +iroha_config = { version = "=2.0.0-pre-rc.5", path = "../../config" } iroha_core = { version = "=2.0.0-pre-rc.5", path = "../../core" } iroha_data_model = { version = "=2.0.0-pre-rc.5", path = "../../data_model" } iroha_primitives = { version = "=2.0.0-pre-rc.5", path = "../../primitives" } diff --git a/core/test_network/src/lib.rs b/core/test_network/src/lib.rs index 469dd6faf57..0aabe8f4f61 100644 --- a/core/test_network/src/lib.rs +++ b/core/test_network/src/lib.rs @@ -7,15 +7,19 @@ use std::{collections::HashMap, sync::Arc, thread}; use eyre::{Error, Result}; use futures::{prelude::*, stream::FuturesUnordered}; -use iroha::{config::Configuration, torii::config::ToriiConfiguration, Iroha}; +use iroha::Iroha; use iroha_actor::{broker::*, prelude::*}; -use iroha_client::{client::Client, config::Configuration as ClientConfiguration}; +use iroha_client::client::Client; +use iroha_config::{ + client::Configuration as ClientConfiguration, iroha::Configuration, + sumeragi::Configuration as SumeragiConfiguration, torii::Configuration as ToriiConfiguration, +}; use iroha_core::{ block_sync::{BlockSynchronizer, BlockSynchronizerTrait}, genesis::{GenesisNetwork, GenesisNetworkTrait, RawGenesisBlock}, prelude::*, smartcontracts::permissions::judge::{InstructionJudgeBoxed, QueryJudgeBoxed}, - sumeragi::{config::SumeragiConfiguration, Sumeragi, SumeragiTrait}, + sumeragi::{Sumeragi, SumeragiTrait}, }; use iroha_data_model::{peer::Peer as DataModelPeer, prelude::*}; use iroha_logger::{Configuration as LoggerConfiguration, InstrumentFutures}; diff --git a/data_model/src/lib.rs b/data_model/src/lib.rs index 9d17d814882..cca399e2c19 100644 --- a/data_model/src/lib.rs +++ b/data_model/src/lib.rs @@ -54,7 +54,6 @@ pub mod query; pub mod role; pub mod transaction; pub mod trigger; -pub mod uri; /// Error which occurs when parsing string into a data model entity #[derive(Debug, Display, Clone, Copy)] @@ -863,7 +862,7 @@ pub mod prelude { peer::prelude::*, role::prelude::*, trigger::prelude::*, - uri, EnumTryAsError, HasMetadata, IdBox, Identifiable, IdentifiableBox, Parameter, + EnumTryAsError, HasMetadata, IdBox, Identifiable, IdentifiableBox, Parameter, PredicateTrait, RegistrableBox, TryAsMut, TryAsRef, ValidationError, Value, }; pub use crate::{ diff --git a/data_model/src/uri.rs b/data_model/src/uri.rs deleted file mode 100644 index 9506a214a8f..00000000000 --- a/data_model/src/uri.rs +++ /dev/null @@ -1,31 +0,0 @@ -//! URI that `Torii` uses to route incoming requests. - -/// Default socket for listening on external requests -pub const DEFAULT_API_URL: &str = "127.0.0.1:8080"; -/// Query URI is used to handle incoming Query requests. -pub const QUERY: &str = "query"; -/// Transaction URI is used to handle incoming ISI requests. -pub const TRANSACTION: &str = "transaction"; -/// Block URI is used to handle incoming Block requests. -pub const CONSENSUS: &str = "consensus"; -/// Health URI is used to handle incoming Healthcheck requests. -pub const HEALTH: &str = "health"; -/// The URI used for block synchronization. -pub const BLOCK_SYNC: &str = "block/sync"; -/// The web socket uri used to subscribe to block and transactions statuses. -pub const SUBSCRIPTION: &str = "events"; -/// The web socket uri used to subscribe to blocks stream. -pub const BLOCKS_STREAM: &str = "block/stream"; -/// Get pending transactions. -pub const PENDING_TRANSACTIONS: &str = "pending_transactions"; -/// The URI for local config changing inspecting -pub const CONFIGURATION: &str = "configuration"; -/// URI to report status for administration -pub const STATUS: &str = "status"; -/// Metrics URI is used to export metrics according to [Prometheus -/// Guidance](https://prometheus.io/docs/instrumenting/writing_exporters/). -pub const METRICS: &str = "metrics"; -/// URI for retrieving the schema with which Iroha was built. -pub const SCHEMA: &str = "schema"; -/// URI for getting the API version currently used -pub const API_VERSION: &str = "api_version"; diff --git a/docs/source/references/config.md b/docs/source/references/config.md index 5cd547af4bc..16cabc981d3 100644 --- a/docs/source/references/config.md +++ b/docs/source/references/config.md @@ -119,9 +119,9 @@ The following is the default configuration used by Iroha. ## `block_sync` -`BlockSynchronizer` configuration. +`BlockSynchronizer` configuration -Has type `BlockSyncConfiguration`. Can be configured via environment variable `IROHA_BLOCK_SYNC` +Has type `block_sync::Configuration`. Can be configured via environment variable `IROHA_BLOCK_SYNC` ```json { @@ -153,7 +153,7 @@ Has type `u32`. Can be configured via environment variable `BLOCK_SYNC_BLOCK_BAT ### `block_sync.gossip_period_ms` -The time between sending requests for latest block. +The period of time to wait between sending requests for the latest block. Has type `u64`. Can be configured via environment variable `BLOCK_SYNC_GOSSIP_PERIOD_MS` @@ -163,7 +163,7 @@ Has type `u64`. Can be configured via environment variable `BLOCK_SYNC_GOSSIP_PE ## `disable_panic_terminal_colors` -Disable coloring of the backtrace and error report on panic. +Disable coloring of the backtrace and error report on panic Has type `bool`. Can be configured via environment variable `IROHA_DISABLE_PANIC_TERMINAL_COLORS` @@ -173,9 +173,9 @@ false ## `genesis` -Configuration for `GenesisBlock`. +`GenesisBlock` configuration -Has type `GenesisConfiguration`. Can be configured via environment variable `IROHA_GENESIS` +Has type `genesis::Configuration`. Can be configured via environment variable `IROHA_GENESIS` ```json { @@ -192,7 +192,7 @@ Has type `GenesisConfiguration`. Can be configured via environment variable `IRO ### `genesis.account_private_key` -Genesis account private key, only needed on the peer that submits the genesis block. +The private key of the genesis account, only needed for the peer that submits the genesis block. Has type `Option`. Can be configured via environment variable `IROHA_GENESIS_ACCOUNT_PRIVATE_KEY` @@ -205,7 +205,7 @@ Has type `Option`. Can be configured via environment variable `IROHA ### `genesis.account_public_key` -The genesis account public key, should be supplied to all peers. +The public key of the genesis account, should be supplied to all peers. Has type `PublicKey`. Can be configured via environment variable `IROHA_GENESIS_ACCOUNT_PUBLIC_KEY` @@ -215,7 +215,7 @@ Has type `PublicKey`. Can be configured via environment variable `IROHA_GENESIS_ ### `genesis.genesis_submission_delay_ms` -Delay before genesis block submission after minimum number of peers were discovered to be online. +The delay before genesis block submission after minimum number of peers were discovered to be online. Has type `u64`. Can be configured via environment variable `IROHA_GENESIS_GENESIS_SUBMISSION_DELAY_MS` @@ -225,7 +225,7 @@ Has type `u64`. Can be configured via environment variable `IROHA_GENESIS_GENESI ### `genesis.wait_for_peers_retry_count_limit` -Number of attempts to connect to peers, while waiting for them to submit genesis. +The number of attempts to connect to peers while waiting for them to submit genesis. Has type `u64`. Can be configured via environment variable `IROHA_GENESIS_WAIT_FOR_PEERS_RETRY_COUNT_LIMIT` @@ -235,7 +235,7 @@ Has type `u64`. Can be configured via environment variable `IROHA_GENESIS_WAIT_F ### `genesis.wait_for_peers_retry_period_ms` -Period in milliseconds in which to retry connecting to peers, while waiting for them to submit genesis. +The period in milliseconds in which to retry connecting to peers while waiting for them to submit genesis. Has type `u64`. Can be configured via environment variable `IROHA_GENESIS_WAIT_FOR_PEERS_RETRY_PERIOD_MS` @@ -245,9 +245,9 @@ Has type `u64`. Can be configured via environment variable `IROHA_GENESIS_WAIT_F ## `kura` -`Kura` related configuration. +`Kura` configuration -Has type `KuraConfiguration`. Can be configured via environment variable `IROHA_KURA` +Has type `kura::Configuration`. Can be configured via environment variable `IROHA_KURA` ```json { @@ -260,7 +260,7 @@ Has type `KuraConfiguration`. Can be configured via environment variable `IROHA_ ### `kura.actor_channel_capacity` -Default buffer capacity of actor's MPSC channel +Default buffer capacity of actor's MPSC channel. Has type `u32`. Can be configured via environment variable `KURA_ACTOR_CHANNEL_CAPACITY` @@ -280,7 +280,7 @@ Has type `String`. Can be configured via environment variable `KURA_BLOCK_STORE_ ### `kura.blocks_per_storage_file` -Maximum number of blocks to write into single storage file +Maximum number of blocks to write into a single storage file. Has type `NonZeroU64`. Can be configured via environment variable `KURA_BLOCKS_PER_STORAGE_FILE` @@ -290,7 +290,7 @@ Has type `NonZeroU64`. Can be configured via environment variable `KURA_BLOCKS_P ### `kura.init_mode` -Possible modes: `strict`, `fast`. +Initialization mode: `strict` or `fast`. Has type `Mode`. Can be configured via environment variable `KURA_INIT_MODE` @@ -300,9 +300,9 @@ Has type `Mode`. Can be configured via environment variable `KURA_INIT_MODE` ## `logger` -`Logger` configuration. +`Logger` configuration -Has type `LoggerConfiguration`. Can be configured via environment variable `IROHA_LOGGER` +Has type `logger::Configuration`. Can be configured via environment variable `IROHA_LOGGER` ```json { @@ -338,7 +338,7 @@ null Maximum log level -Has type `handle::SyncValue>`. Can be configured via environment variable `MAX_LOG_LEVEL` +Has type `SyncLevel`. Can be configured via environment variable `MAX_LOG_LEVEL` ```json "INFO" @@ -368,7 +368,7 @@ true Network configuration -Has type `NetworkConfiguration`. Can be configured via environment variable `IROHA_NETWORK` +Has type `network::Configuration`. Can be configured via environment variable `IROHA_NETWORK` ```json { @@ -388,7 +388,7 @@ Has type `u32`. Can be configured via environment variable `IROHA_NETWORK_ACTOR_ ## `private_key` -Private key of this peer. +Private key of this peer Has type `PrivateKey`. Can be configured via environment variable `IROHA_PRIVATE_KEY` @@ -401,7 +401,7 @@ Has type `PrivateKey`. Can be configured via environment variable `IROHA_PRIVATE ## `public_key` -Public key of this peer. +Public key of this peer Has type `PublicKey`. Can be configured via environment variable `IROHA_PUBLIC_KEY` @@ -411,9 +411,9 @@ Has type `PublicKey`. Can be configured via environment variable `IROHA_PUBLIC_K ## `queue` -`Queue` configuration. +`Queue` configuration -Has type `QueueConfiguration`. Can be configured via environment variable `IROHA_QUEUE` +Has type `queue::Configuration`. Can be configured via environment variable `IROHA_QUEUE` ```json { @@ -446,7 +446,7 @@ Has type `u32`. Can be configured via environment variable `QUEUE_MAXIMUM_TRANSA ### `queue.maximum_transactions_in_queue` -The upper limit of the number of transactions waiting in this queue. +The upper limit of the number of transactions waiting in the queue. Has type `u32`. Can be configured via environment variable `QUEUE_MAXIMUM_TRANSACTIONS_IN_QUEUE` @@ -456,7 +456,7 @@ Has type `u32`. Can be configured via environment variable `QUEUE_MAXIMUM_TRANSA ### `queue.transaction_time_to_live_ms` -The transaction will be dropped after this time if it is still in a `Queue`. +The transaction will be dropped after this time if it is still in the queue. Has type `u64`. Can be configured via environment variable `QUEUE_TRANSACTION_TIME_TO_LIVE_MS` @@ -476,9 +476,9 @@ false ## `sumeragi` -`Sumeragi` related configuration. +`Sumeragi` configuration -Has type `SumeragiConfiguration`. Can be configured via environment variable `IROHA_SUMERAGI` +Has type `sumeragi::Configuration`. Can be configured via environment variable `IROHA_SUMERAGI` ```json { @@ -517,7 +517,7 @@ Has type `u32`. Can be configured via environment variable `SUMERAGI_ACTOR_CHANN ### `sumeragi.block_time_ms` -Amount of time peer waits for the `CreatedBlock` message after getting a `TransactionReceipt` +The period of time a peer waits for the `CreatedBlock` message after getting a `TransactionReceipt` Has type `u64`. Can be configured via environment variable `SUMERAGI_BLOCK_TIME_MS` @@ -527,7 +527,7 @@ Has type `u64`. Can be configured via environment variable `SUMERAGI_BLOCK_TIME_ ### `sumeragi.commit_time_limit_ms` -Amount of time Peer waits for CommitMessage from the proxy tail. +The period of time a peer waits for `CommitMessage` from the proxy tail. Has type `u64`. Can be configured via environment variable `SUMERAGI_COMMIT_TIME_LIMIT_MS` @@ -537,7 +537,7 @@ Has type `u64`. Can be configured via environment variable `SUMERAGI_COMMIT_TIME ### `sumeragi.gossip_batch_size` -Maximum number of transactions in tx gossip batch message. While configuring this, attention should be payed to `p2p` max message size. +Maximum number of transactions in tx gossip batch message. While configuring this, pay attention to `p2p` max message size. Has type `u32`. Can be configured via environment variable `SUMERAGI_GOSSIP_BATCH_SIZE` @@ -557,7 +557,7 @@ Has type `u64`. Can be configured via environment variable `SUMERAGI_GOSSIP_PERI ### `sumeragi.key_pair` -Key pair of private and public keys. +The key pair consisting of a private and a public key. Has type `KeyPair`. Can be configured via environment variable `SUMERAGI_KEY_PAIR` @@ -586,7 +586,7 @@ Has type `PeerId`. Can be configured via environment variable `SUMERAGI_PEER_ID` ### `sumeragi.transaction_limits` -Limits to which transactions must adhere +The limits to which transactions must adhere Has type `TransactionLimits`. Can be configured via environment variable `SUMERAGI_TRANSACTION_LIMITS` @@ -614,7 +614,7 @@ Has type `TrustedPeers`. Can be configured via environment variable `SUMERAGI_TR ### `sumeragi.tx_receipt_time_limit_ms` -Amount of time Peer waits for TxReceipt from the leader. +The period of time a peer waits for `TxReceipt` from the leader. Has type `u64`. Can be configured via environment variable `SUMERAGI_TX_RECEIPT_TIME_LIMIT_MS` @@ -624,9 +624,9 @@ Has type `u64`. Can be configured via environment variable `SUMERAGI_TX_RECEIPT_ ## `telemetry` -Configuration for telemetry +Telemetry configuration -Has type `iroha_telemetry::Configuration`. Can be configured via environment variable `IROHA_TELEMETRY` +Has type `telemetry::Configuration`. Can be configured via environment variable `IROHA_TELEMETRY` ```json { @@ -642,7 +642,7 @@ Has type `iroha_telemetry::Configuration`. Can be configured via environment var The filepath that to write dev-telemetry to -Has type `Option`. Can be configured via environment variable `TELEMETRY_FILE` +Has type `Option`. Can be configured via environment variable `TELEMETRY_FILE` ```json null @@ -690,9 +690,9 @@ null ## `torii` -`Torii` related configuration. +`Torii` configuration -Has type `ToriiConfiguration`. Can be configured via environment variable `IROHA_TORII` +Has type `torii::Configuration`. Can be configured via environment variable `IROHA_TORII` ```json { @@ -756,9 +756,9 @@ Has type `String`. Can be configured via environment variable `TORII_TELEMETRY_U ## `wsv` -Configuration for `WorldStateView`. +`WorldStateView` configuration -Has type `WorldStateViewConfiguration`. Can be configured via environment variable `IROHA_WSV` +Has type `wsv::Configuration`. Can be configured via environment variable `IROHA_WSV` ```json { @@ -791,7 +791,7 @@ Has type `WorldStateViewConfiguration`. Can be configured via environment variab ### `wsv.account_metadata_limits` -[`MetadataLimits`] of any account's metadata. +[`MetadataLimits`] of any account metadata. Has type `MetadataLimits`. Can be configured via environment variable `WSV_ACCOUNT_METADATA_LIMITS` @@ -804,7 +804,7 @@ Has type `MetadataLimits`. Can be configured via environment variable `WSV_ACCOU ### `wsv.asset_definition_metadata_limits` -[`MetadataLimits`] of any asset definition's metadata. +[`MetadataLimits`] of any asset definition metadata. Has type `MetadataLimits`. Can be configured via environment variable `WSV_ASSET_DEFINITION_METADATA_LIMITS` @@ -830,7 +830,7 @@ Has type `MetadataLimits`. Can be configured via environment variable `WSV_ASSET ### `wsv.domain_metadata_limits` -[`MetadataLimits`] of any domain's metadata. +[`MetadataLimits`] of any domain metadata. Has type `MetadataLimits`. Can be configured via environment variable `WSV_DOMAIN_METADATA_LIMITS` @@ -856,9 +856,9 @@ Has type `LengthLimits`. Can be configured via environment variable `WSV_IDENT_L ### `wsv.wasm_runtime_config` -[`WASM Runtime`](wasm::Runtime) configuration +WASM runtime configuration -Has type `wasm::config::Configuration`. Can be configured via environment variable `WSV_WASM_RUNTIME_CONFIG` +Has type `wasm::Configuration`. Can be configured via environment variable `WSV_WASM_RUNTIME_CONFIG` ```json { diff --git a/logger/Cargo.toml b/logger/Cargo.toml index ce4a7893bd0..2cd71b5f420 100644 --- a/logger/Cargo.toml +++ b/logger/Cargo.toml @@ -6,6 +6,7 @@ edition = "2021" [dependencies] iroha_config = { version = "=2.0.0-pre-rc.5", path = "../config" } +iroha_data_model = { version = "=2.0.0-pre-rc.5", path = "../data_model" } color-eyre = "0.5.11" serde = { version = "1.0", features = ["derive"] } diff --git a/logger/src/lib.rs b/logger/src/lib.rs index f22d8b15df3..31d142deace 100644 --- a/logger/src/lib.rs +++ b/logger/src/lib.rs @@ -1,7 +1,6 @@ //! Iroha's logging utilities. #![allow(clippy::expect_used)] -pub mod config; pub mod layer; pub mod telemetry; @@ -16,6 +15,7 @@ use std::{ }; use color_eyre::{eyre::WrapErr, Report, Result}; +pub use iroha_config::logger::{Configuration, Level}; pub use telemetry::{Telemetry, TelemetryFields, TelemetryLayer}; use tokio::sync::mpsc::Receiver; pub use tracing::{ @@ -27,8 +27,6 @@ use tracing_bunyan_formatter::{BunyanFormattingLayer, JsonStorageLayer}; pub use tracing_futures::Instrument as InstrumentFutures; use tracing_subscriber::{layer::SubscriberExt, registry::Registry, reload}; -pub use crate::config::{Configuration, Level}; - /// Substrate telemetry pub type SubstrateTelemetry = Receiver; diff --git a/logger/tests/configuration.rs b/logger/tests/configuration.rs index aacec74df23..634bbbb3341 100644 --- a/logger/tests/configuration.rs +++ b/logger/tests/configuration.rs @@ -2,14 +2,13 @@ use std::time::Duration; -use iroha_config::logger as config; use iroha_logger::{info, init, Configuration, Level, Telemetry, TelemetryFields}; use tokio::time; #[tokio::test] async fn telemetry_separation_custom() { let config = Configuration { - max_log_level: Level(config::Level::TRACE).into(), + max_log_level: Level::TRACE.into(), telemetry_capacity: 100, compact_mode: true, log_file_path: Some("/dev/stdout".into()), diff --git a/p2p/tests/integration/p2p.rs b/p2p/tests/integration/p2p.rs index 957d5584753..30cb2046682 100644 --- a/p2p/tests/integration/p2p.rs +++ b/p2p/tests/integration/p2p.rs @@ -11,7 +11,6 @@ use std::{ use futures::{prelude::*, stream::FuturesUnordered}; use iroha_actor::{broker::*, prelude::*}; -use iroha_config::logger; use iroha_crypto::{KeyPair, PublicKey}; use iroha_logger::{prelude::*, Configuration, Level}; use iroha_p2p::{ @@ -35,7 +34,7 @@ static INIT: Once = Once::new(); fn setup_logger() { INIT.call_once(|| { let log_config = Configuration { - max_log_level: Level(logger::Level::TRACE).into(), + max_log_level: Level::TRACE.into(), compact_mode: false, ..Configuration::default() }; @@ -202,7 +201,7 @@ async fn two_networks() { async fn multiple_networks() { prepare_test_for_nextest!(); let log_config = Configuration { - max_log_level: Level(logger::Level::TRACE).into(), + max_log_level: Level::TRACE.into(), compact_mode: false, ..Configuration::default() }; diff --git a/telemetry/Cargo.toml b/telemetry/Cargo.toml index 981e18c6dfe..21b2b4d1b08 100644 --- a/telemetry/Cargo.toml +++ b/telemetry/Cargo.toml @@ -14,6 +14,7 @@ metric-instrumentation = [] [dependencies] iroha_config = { version = "=2.0.0-pre-rc.5", path = "../config" } +iroha_data_model = { version = "=2.0.0-pre-rc.5", path = "../data_model" } iroha_logger = { version = "=2.0.0-pre-rc.5", path = "../logger" } iroha_futures = { version = "=2.0.0-pre-rc.5", path = "../futures", features = ["telemetry"] } iroha_telemetry_derive = { version = "=2.0.0-pre-rc.5", path = "derive" } diff --git a/telemetry/src/lib.rs b/telemetry/src/lib.rs index a5f3b0ef260..8ba2ec2e2fb 100644 --- a/telemetry/src/lib.rs +++ b/telemetry/src/lib.rs @@ -1,6 +1,5 @@ //! Crate with iroha telemetry processing -mod config; #[cfg(feature = "dev-telemetry")] pub mod dev; pub mod futures; @@ -8,7 +7,7 @@ pub mod metrics; mod retry_period; pub mod ws; -pub use config::Configuration; +pub use iroha_config::telemetry::Configuration; pub use iroha_telemetry_derive::metrics; pub mod msg { diff --git a/telemetry/src/retry_period.rs b/telemetry/src/retry_period.rs index eb3dcbb2235..385df2ec25d 100644 --- a/telemetry/src/retry_period.rs +++ b/telemetry/src/retry_period.rs @@ -1,4 +1,8 @@ /// Encapsulates the retry period that is calculated as `min_period * 2 ^ min(exponent, max_exponent)` +use iroha_config::telemetry::retry_period::{ + DEFAULT_MAX_RETRY_DELAY_EXPONENT, DEFAULT_MIN_RETRY_PERIOD, +}; + pub struct RetryPeriod { /// The minimum period min_period: u64, @@ -9,8 +13,8 @@ pub struct RetryPeriod { } impl RetryPeriod { - pub const DEFAULT_MIN_RETRY_PERIOD: u64 = 1; - pub const DEFAULT_MAX_RETRY_DELAY_EXPONENT: u8 = 4; + pub const DEFAULT_MIN_RETRY_PERIOD: u64 = DEFAULT_MIN_RETRY_PERIOD; + pub const DEFAULT_MAX_RETRY_DELAY_EXPONENT: u8 = DEFAULT_MAX_RETRY_DELAY_EXPONENT; /// Constructs a new object pub const fn new(min_period: u64, max_exponent: u8) -> Self { diff --git a/tools/kagami/Cargo.toml b/tools/kagami/Cargo.toml index 8437e23a797..80223458ef1 100644 --- a/tools/kagami/Cargo.toml +++ b/tools/kagami/Cargo.toml @@ -33,8 +33,6 @@ iroha_schema_gen = { version = "=2.0.0-pre-rc.5", path = "../../schema/gen" } iroha_schema = { version = "=2.0.0-pre-rc.5", path = "../../schema" } iroha_permissions_validators = { version = "=2.0.0-pre-rc.5", path = "../../permissions_validators" } -iroha = { path = "../../cli" } - color-eyre = "0.5.11" clap = { version = "3.1.10", features = ["derive"] } serde_json = "1" diff --git a/tools/kagami/src/main.rs b/tools/kagami/src/main.rs index bfa96b5d5b2..da158075814 100644 --- a/tools/kagami/src/main.rs +++ b/tools/kagami/src/main.rs @@ -6,7 +6,7 @@ use std::io::{stdout, BufWriter, Write}; use clap::{ArgGroup, StructOpt}; use color_eyre::eyre::WrapErr as _; -use iroha::config::Configuration; +use iroha_config::iroha::Configuration; pub type Outcome = color_eyre::Result<()>; @@ -203,7 +203,7 @@ mod docs { use std::{fmt::Debug, io::Write}; use color_eyre::eyre::WrapErr as _; - use iroha_config::Configurable; + use iroha_config::base::Configurable; use serde_json::Value; use super::*;