Skip to content

Allow to override chainstate options for regtest #301

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 14 commits into from
Jul 26, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 1 addition & 24 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion common/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"

Expand Down
27 changes: 1 addition & 26 deletions common/src/chain/config/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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();
Expand Down
2 changes: 1 addition & 1 deletion node/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
1 change: 1 addition & 0 deletions node/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

mod config;
mod options;
mod regtest_options;
mod runner;

pub type Error = anyhow::Error;
Expand Down
15 changes: 7 additions & 8 deletions node/src/options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down Expand Up @@ -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<usize>,
Expand Down
68 changes: 68 additions & 0 deletions node/src/regtest_options.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
// Copyright (c) 2022 RBB S.r.l
// [email protected]
// 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<String>,

/// Block reward maturity.
#[clap(long)]
pub chain_blockreward_maturity: Option<i64>,

/// The maximum future block offset in seconds.
#[clap(long)]
pub chain_max_future_block_time_offset: Option<u64>,

/// The chain version (major.minor.path).
#[clap(long)]
pub chain_version: Option<String>,

/// Target block spacing in seconds.
#[clap(long)]
pub chain_target_block_spacing: Option<u64>,

/// Coin decimals.
#[clap(long)]
pub chain_coin_decimals: Option<u8>,

/// Emission schedule (`<initial_supply>+<initial_subsidy>[, <height>+<subsidy>]`).
pub chain_emission_schedule: Option<String>,

/// The maximum block header size in bytes.
#[clap(long)]
pub chain_max_block_header_size: Option<usize>,

/// The maximum transactions size in block in bytes.
#[clap(long)]
pub chain_max_block_size_with_standard_txs: Option<usize>,

/// The maximum smart contracts size ib block in bytes.
#[clap(long)]
pub chain_max_block_size_with_smart_contracts: Option<usize>,
}
121 changes: 96 additions & 25 deletions node/src/runner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<subsystem::Manager> {
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");
Expand Down Expand Up @@ -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(&regtest_options.chain_config)?;
start(
&options.config_path(),
&regtest_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<ChainConfig> {
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) = [<chain_ $field>] {
builder = builder.$field($converter(val.to_owned()));
}
}
};
($field: ident, $converter: stmt, map_err) => {
paste! {
if let Some(val) = [<chain_ $field>] {
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
Expand Down
Loading