diff --git a/Cargo.lock b/Cargo.lock index 31753784d7..6b2f65d391 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -685,7 +685,6 @@ dependencies = [ "serialization", "sscanf", "static_assertions", - "strum", "thiserror", ] @@ -2439,9 +2438,9 @@ dependencies = [ "jsonrpsee", "logging", "p2p", + "paste", "rpc", "serde", - "strum", "subsystem", "tempdir", "thiserror", @@ -3863,28 +3862,6 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" -[[package]] -name = "strum" -version = "0.24.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "063e6045c0e62079840579a7e47a355ae92f60eb74daaf156fb1e84ba164e63f" -dependencies = [ - "strum_macros", -] - -[[package]] -name = "strum_macros" -version = "0.24.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6878079b17446e4d3eba6192bb0a2950d5b14f0ed8424b852310e5a94345d0ef" -dependencies = [ - "heck 0.4.0", - "proc-macro2", - "quote", - "rustversion", - "syn", -] - [[package]] name = "subsystem" version = "0.1.0" diff --git a/common/Cargo.toml b/common/Cargo.toml index d2db55b40f..4786214592 100644 --- a/common/Cargo.toml +++ b/common/Cargo.toml @@ -21,7 +21,6 @@ parity-scale-codec = "3.1" serde = "1.0" sscanf = "0.2" static_assertions = "1.1" -strum = { version = "0.24", features = ["derive"] } thiserror = "1.0" hex = "0.4" diff --git a/common/src/chain/config/mod.rs b/common/src/chain/config/mod.rs index 86ec3605d7..becfd533cb 100644 --- a/common/src/chain/config/mod.rs +++ b/common/src/chain/config/mod.rs @@ -40,19 +40,7 @@ use std::time::Duration; const DEFAULT_MAX_FUTURE_BLOCK_TIME_OFFSET: Duration = Duration::from_secs(60 * 60); pub const DEFAULT_TARGET_BLOCK_SPACING: Duration = Duration::from_secs(120); -#[derive( - Debug, - Copy, - Clone, - PartialEq, - Eq, - PartialOrd, - Ord, - strum::Display, - strum::EnumVariantNames, - strum::EnumString, -)] -#[strum(serialize_all = "kebab-case")] +#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] pub enum ChainType { Mainnet, Testnet, @@ -279,19 +267,6 @@ mod tests { assert_eq!(config.chain_type(), &ChainType::Mainnet); } - #[test] - fn chain_type_names() { - use strum::VariantNames; - - assert_eq!(&ChainType::Mainnet.to_string(), "mainnet"); - assert_eq!(&ChainType::Testnet.to_string(), "testnet"); - - for chain_type_str in ChainType::VARIANTS { - let chain_type: ChainType = chain_type_str.parse().expect("cannot parse chain type"); - assert_eq!(&chain_type.to_string(), chain_type_str); - } - } - #[test] fn different_magic_bytes() { let config1 = Builder::new(ChainType::Regtest).build(); diff --git a/node/Cargo.toml b/node/Cargo.toml index 4ffa3e0841..15aac80dd0 100644 --- a/node/Cargo.toml +++ b/node/Cargo.toml @@ -20,12 +20,12 @@ subsystem = { path = "../subsystem/" } anyhow = "1.0" clap = { version = "3.1", features = ["derive"] } jsonrpsee = { version = "0.14", features = ["macros"] } -strum = "0.24" tokio = { version = "1.19", default-features = false } thiserror = "1.0" serde = { version = "1", features = ["derive"] } toml = "0.5" directories = "4.0" +paste = "1.0" [dev-dependencies] assert_cmd = "2" diff --git a/node/src/lib.rs b/node/src/lib.rs index b64d55c710..69433d500a 100644 --- a/node/src/lib.rs +++ b/node/src/lib.rs @@ -17,6 +17,7 @@ mod config; mod options; +mod regtest_options; mod runner; pub type Error = anyhow::Error; diff --git a/node/src/options.rs b/node/src/options.rs index 34057f0cb2..7a0941b353 100644 --- a/node/src/options.rs +++ b/node/src/options.rs @@ -20,9 +20,8 @@ use std::{ffi::OsString, fs, net::SocketAddr, path::PathBuf}; use anyhow::{Context, Result}; use clap::{Args, Parser, Subcommand}; use directories::UserDirs; -use strum::VariantNames; -use common::chain::config::ChainType; +use crate::regtest_options::RegtestOptions; const DATA_DIR_NAME: &str = ".mintlayer"; const CONFIG_NAME: &str = "config.toml"; @@ -51,16 +50,16 @@ pub struct Options { pub enum Command { /// Create a configuration file. CreateConfig, - Run(RunOptions), + /// Run the mainnet node. + Mainnet(RunOptions), + /// Run the testnet node. + Testnet(RunOptions), + /// Run the regtest node. + Regtest(RegtestOptions), } -/// Run the node. #[derive(Args, Debug)] pub struct RunOptions { - /// Blockchain type. - #[clap(long, possible_values = ChainType::VARIANTS, default_value = "mainnet")] - pub net: ChainType, - /// The number of maximum attempts to process a block. #[clap(long)] pub max_db_commit_attempts: Option, diff --git a/node/src/regtest_options.rs b/node/src/regtest_options.rs new file mode 100644 index 0000000000..1959654f59 --- /dev/null +++ b/node/src/regtest_options.rs @@ -0,0 +1,68 @@ +// Copyright (c) 2022 RBB S.r.l +// opensource@mintlayer.org +// SPDX-License-Identifier: MIT +// Licensed under the MIT License; +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://spdx.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use clap::Args; + +use crate::RunOptions; + +#[derive(Args, Debug)] +pub struct RegtestOptions { + #[clap(flatten)] + pub run_options: RunOptions, + #[clap(flatten)] + pub chain_config: ChainConfigOptions, +} + +#[derive(Args, Debug)] +pub struct ChainConfigOptions { + /// Address prefix. + #[clap(long)] + pub chain_address_prefix: Option, + + /// Block reward maturity. + #[clap(long)] + pub chain_blockreward_maturity: Option, + + /// The maximum future block offset in seconds. + #[clap(long)] + pub chain_max_future_block_time_offset: Option, + + /// The chain version (major.minor.path). + #[clap(long)] + pub chain_version: Option, + + /// Target block spacing in seconds. + #[clap(long)] + pub chain_target_block_spacing: Option, + + /// Coin decimals. + #[clap(long)] + pub chain_coin_decimals: Option, + + /// Emission schedule (`+[, +]`). + pub chain_emission_schedule: Option, + + /// The maximum block header size in bytes. + #[clap(long)] + pub chain_max_block_header_size: Option, + + /// The maximum transactions size in block in bytes. + #[clap(long)] + pub chain_max_block_size_with_standard_txs: Option, + + /// The maximum smart contracts size ib block in bytes. + #[clap(long)] + pub chain_max_block_size_with_smart_contracts: Option, +} diff --git a/node/src/runner.rs b/node/src/runner.rs index e0f9deab76..d9c816d0d6 100644 --- a/node/src/runner.rs +++ b/node/src/runner.rs @@ -15,41 +15,37 @@ //! Node initialisation routine. -use std::{fs, sync::Arc}; +use std::{fs, path::Path, str::FromStr, sync::Arc, time::Duration}; -use anyhow::{Context, Result}; +use anyhow::{anyhow, Context, Result}; +use paste::paste; use chainstate::rpc::ChainstateRpcServer; -use common::chain::config::ChainType; +use common::{ + chain::config::{ + Builder as ChainConfigBuilder, ChainConfig, ChainType, EmissionScheduleTabular, + }, + primitives::{semver::SemVer, BlockDistance}, +}; use logging::log; use p2p::rpc::P2pRpcServer; use crate::{ config::NodeConfig, - options::{Command, Options}, + options::{Command, Options, RunOptions}, + regtest_options::ChainConfigOptions, }; -#[derive(Debug, Ord, PartialOrd, PartialEq, Eq, Clone, Copy, thiserror::Error)] -enum Error { - #[error("Chain type '{0}' not yet supported")] - UnsupportedChain(ChainType), -} - /// Initialize the node, giving caller the opportunity to add more subsystems before start. pub async fn initialize( - chain_type: ChainType, + chain_config: ChainConfig, node_config: NodeConfig, ) -> Result { + let chain_config = Arc::new(chain_config); + // Initialize storage. let storage = chainstate_storage::Store::new_empty()?; - // Initialize chain configuration. - let chain_config = Arc::new(match chain_type { - ChainType::Mainnet => common::chain::config::create_mainnet(), - ChainType::Regtest => common::chain::config::create_regtest(), - chain_ty => return Err(Error::UnsupportedChain(chain_ty).into()), - }); - // INITIALIZE SUBSYSTEMS let mut manager = subsystem::Manager::new("mintlayer"); @@ -105,17 +101,92 @@ pub async fn run(options: Options) -> Result<()> { .with_context(|| format!("Failed to write config to the '{path:?}' file"))?; Ok(()) } - Command::Run(ref run_options) => { - let node_config = NodeConfig::read(&options.config_path(), run_options) - .context("Failed to initialize config")?; - log::trace!("Starting with the following config\n: {node_config:#?}"); - let manager = initialize(run_options.net, node_config).await?; - #[allow(clippy::unit_arg)] - Ok(manager.main().await) + Command::Mainnet(ref run_options) => { + let chain_config = common::chain::config::create_mainnet(); + start(&options.config_path(), run_options, chain_config).await + } + Command::Testnet(ref run_options) => { + let chain_config = ChainConfigBuilder::new(ChainType::Testnet).build(); + start(&options.config_path(), run_options, chain_config).await + } + Command::Regtest(ref regtest_options) => { + let chain_config = regtest_chain_config(®test_options.chain_config)?; + start( + &options.config_path(), + ®test_options.run_options, + chain_config, + ) + .await } } } +async fn start( + config_path: &Path, + run_options: &RunOptions, + chain_config: ChainConfig, +) -> Result<()> { + let node_config = + NodeConfig::read(config_path, run_options).context("Failed to initialize config")?; + log::info!("Starting with the following config:\n {node_config:#?}"); + let manager = initialize(chain_config, node_config).await?; + manager.main().await; + Ok(()) +} + +fn regtest_chain_config(options: &ChainConfigOptions) -> Result { + let ChainConfigOptions { + chain_address_prefix, + chain_blockreward_maturity, + chain_max_future_block_time_offset, + chain_version, + chain_target_block_spacing, + chain_coin_decimals, + chain_emission_schedule, + chain_max_block_header_size, + chain_max_block_size_with_standard_txs, + chain_max_block_size_with_smart_contracts, + } = options; + + let mut builder = ChainConfigBuilder::new(ChainType::Regtest); + + macro_rules! update_builder { + ($field: ident) => { + update_builder!($field, std::convert::identity) + }; + ($field: ident, $converter: stmt) => { + paste! { + if let Some(val) = [] { + builder = builder.$field($converter(val.to_owned())); + } + } + }; + ($field: ident, $converter: stmt, map_err) => { + paste! { + if let Some(val) = [] { + builder = builder.$field($converter(val.to_owned()).map_err(|e| anyhow!(e))?); + } + } + }; + } + + update_builder!(address_prefix); + update_builder!(blockreward_maturity, BlockDistance::new); + update_builder!(max_future_block_time_offset, Duration::from_secs); + update_builder!(version, SemVer::try_from, map_err); + update_builder!(target_block_spacing, Duration::from_secs); + update_builder!(coin_decimals); + if let Some(val) = chain_emission_schedule { + builder = + builder.emission_schedule_tabular(EmissionScheduleTabular::from_str(val.as_str())?); + } + update_builder!(max_block_header_size); + update_builder!(max_block_size_with_standard_txs); + update_builder!(max_block_size_with_smart_contracts); + + Ok(builder.build()) +} + #[rpc::rpc(server, namespace = "node")] trait NodeRpc { /// Order the node to shutdown diff --git a/node/tests/cli.rs b/node/tests/cli.rs index eb24ce0228..683a839c1e 100644 --- a/node/tests/cli.rs +++ b/node/tests/cli.rs @@ -19,7 +19,6 @@ use assert_cmd::Command; use directories::UserDirs; use tempdir::TempDir; -use common::chain::config::ChainType; use node::{NodeConfig, RunOptions}; const BIN_NAME: &str = env!("CARGO_BIN_EXE_node"); @@ -90,7 +89,6 @@ fn read_config_override_values() { let rpc_addr = SocketAddr::from_str("127.0.0.1:5432").unwrap(); let options = RunOptions { - net: ChainType::Mainnet, max_db_commit_attempts: Some(max_db_commit_attempts), max_orphan_blocks: Some(max_orphan_blocks), p2p_addr: Some(p2p_addr.into()), @@ -162,7 +160,6 @@ fn custom_config_path_and_data_dir() { fn default_run_options() -> RunOptions { RunOptions { - net: ChainType::Mainnet, max_db_commit_attempts: None, max_orphan_blocks: None, p2p_addr: None, diff --git a/test/functional/test_framework/test_node.py b/test/functional/test_framework/test_node.py index 1011757c64..d87716ea53 100755 --- a/test/functional/test_framework/test_node.py +++ b/test/functional/test_framework/test_node.py @@ -107,8 +107,7 @@ def __init__(self, i, datadir, *, chain, rpchost, timewait, timeout_factor, bitc self.args = [ self.binary, "--datadir={}".format(datadir_path), - "run", - "--net=regtest", + "regtest", "--rpc-addr={}".format(rpc_addr), "--p2p-addr={}".format(p2p_addr), #"-X",