diff --git a/crates/subspace-malicious-operator/src/bin/subspace-malicious-operator.rs b/crates/subspace-malicious-operator/src/bin/subspace-malicious-operator.rs index 7715f00924..636e90e115 100644 --- a/crates/subspace-malicious-operator/src/bin/subspace-malicious-operator.rs +++ b/crates/subspace-malicious-operator/src/bin/subspace-malicious-operator.rs @@ -23,7 +23,7 @@ use cross_domain_message_gossip::GossipWorkerBuilder; use domain_client_operator::Bootstrapper; use domain_runtime_primitives::opaque::Block as DomainBlock; use log::warn; -use sc_cli::{ChainSpec, CliConfiguration, SubstrateCli}; +use sc_cli::{ChainSpec, SubstrateCli}; use sc_consensus_slots::SlotProportion; use sc_service::Configuration; use sc_storage_monitor::StorageMonitorService; @@ -125,6 +125,7 @@ fn main() -> Result<(), Error> { set_default_ss58_version(&runner.config().chain_spec); runner.run_node_until_exit(|consensus_chain_config| async move { let tokio_handle = consensus_chain_config.tokio_handle.clone(); + let base_path = consensus_chain_config.base_path.path().to_path_buf(); let database_source = consensus_chain_config.database.clone(); let domains_bootstrap_nodes: serde_json::map::Map = @@ -274,12 +275,7 @@ fn main() -> Result<(), Error> { ); let _enter = span.enter(); - let mut domain_cli = DomainCli::new( - cli.run - .base_path()? - .map(|base_path| base_path.path().to_path_buf()), - cli.domain_args.into_iter(), - ); + let mut domain_cli = DomainCli::new(cli.domain_args.into_iter()); let domain_id = domain_cli.domain_id; @@ -360,6 +356,7 @@ fn main() -> Result<(), Error> { let domain_starter = DomainInstanceStarter { domain_cli, + base_path, tokio_handle, consensus_client: consensus_chain_node.client.clone(), consensus_keystore, diff --git a/crates/subspace-malicious-operator/src/malicious_domain_instance_starter.rs b/crates/subspace-malicious-operator/src/malicious_domain_instance_starter.rs index 9fbdf9eefa..1b9e60fbdc 100644 --- a/crates/subspace-malicious-operator/src/malicious_domain_instance_starter.rs +++ b/crates/subspace-malicious-operator/src/malicious_domain_instance_starter.rs @@ -12,12 +12,14 @@ use sc_consensus_subspace::block_import::BlockImportingNotification; use sc_consensus_subspace::notification::SubspaceNotificationStream; use sc_consensus_subspace::slot_worker::NewSlotNotification; use sc_network::NetworkPeers; -use sc_service::BasePath; +use sc_service::config::KeystoreConfig; +use sc_service::{BasePath, DatabaseSource}; use sc_transaction_pool_api::OffchainTransactionPoolFactory; use sc_utils::mpsc::{TracingUnboundedReceiver, TracingUnboundedSender}; use sp_core::traits::SpawnEssentialNamed; use sp_domains::{DomainInstanceData, RuntimeType}; use sp_keystore::KeystorePtr; +use std::path::PathBuf; use std::sync::Arc; use subspace_node::domain::{create_configuration, evm_chain_spec, AccountId20, DomainCli}; use subspace_runtime::{ExecutorDispatch as CExecutorDispatch, RuntimeApi as CRuntimeApi}; @@ -28,6 +30,7 @@ use subspace_service::FullClient as CFullClient; /// bootstrap result pub struct DomainInstanceStarter { pub domain_cli: DomainCli, + pub base_path: PathBuf, pub tokio_handle: tokio::runtime::Handle, pub consensus_client: Arc>, pub consensus_keystore: KeystorePtr, @@ -62,6 +65,7 @@ where let DomainInstanceStarter { domain_cli, + base_path, tokio_handle, consensus_client, consensus_keystore, @@ -75,7 +79,7 @@ where } = self; let domain_id = domain_cli.domain_id; - let domain_config = { + let mut domain_config = { let chain_id = domain_cli.chain_id(domain_cli.is_dev()?)?; let domain_spec = evm_chain_spec::create_domain_spec(chain_id.as_str(), raw_genesis)?; @@ -83,6 +87,27 @@ where create_configuration::<_, DomainCli, DomainCli>(&domain_cli, domain_spec, tokio_handle)? }; + // Change default paths to Subspace structure + // TODO: Similar copy-paste exists in `DomainCli::create_domain_configuration()` as well as + // `subspace-node`'s `DomainInstanceStarter` and should be de-duplicated + { + let domain_base_path = base_path.join("domains").join(domain_id.to_string()); + domain_config.database = DatabaseSource::ParityDb { + path: domain_base_path.join("db"), + }; + domain_config.keystore = KeystoreConfig::Path { + path: domain_base_path.join("keystore"), + password: match domain_config.keystore { + KeystoreConfig::Path { password, .. } => password, + KeystoreConfig::InMemory => None, + }, + }; + // Network directory is shared with consensus chain + if let Some(net_config_path) = &mut domain_config.network.net_config_path { + *net_config_path = base_path.join("network"); + } + } + let block_importing_notification_stream = || { block_importing_notification_stream.subscribe().then( |block_importing_notification| async move { diff --git a/crates/subspace-node/src/bin/subspace-node.rs b/crates/subspace-node/src/bin/subspace-node.rs index f2419d1051..f988e1d780 100644 --- a/crates/subspace-node/src/bin/subspace-node.rs +++ b/crates/subspace-node/src/bin/subspace-node.rs @@ -26,10 +26,12 @@ use evm_domain_runtime::ExecutorDispatch as EVMDomainExecutorDispatch; use frame_benchmarking_cli::BenchmarkCmd; use futures::future::TryFutureExt; use log::warn; -use sc_cli::{ChainSpec, CliConfiguration, SubstrateCli}; +use sc_cli::{ChainSpec, SubstrateCli}; use sc_consensus_slots::SlotProportion; use sc_executor::NativeExecutionDispatch; -use sc_service::{Configuration, PartialComponents}; +use sc_network::config::NodeKeyConfig; +use sc_service::config::KeystoreConfig; +use sc_service::{Configuration, DatabaseSource, PartialComponents}; use sc_storage_monitor::StorageMonitorService; use sc_transaction_pool_api::OffchainTransactionPoolFactory; use sc_utils::mpsc::tracing_unbounded; @@ -225,37 +227,13 @@ fn main() -> Result<(), Error> { base_dir.join("subspace-node").join("chains").join(chain), ); } + let _ = std::fs::remove_dir_all(base_dir.join("subspace-node").join("domain-0")); + let _ = std::fs::remove_dir_all(base_dir.join("subspace-node").join("domain-1")); } let runner = cli.create_runner(&cmd.base)?; - runner.sync_run(|consensus_chain_config| { - let domain_config = if cmd.domain_args.is_empty() { - None - } else { - let domain_cli = DomainCli::new( - cmd.base - .base_path()? - .map(|base_path| base_path.path().to_path_buf()), - cmd.domain_args.clone().into_iter(), - ); - - let domain_config = SubstrateCli::create_configuration( - &domain_cli, - &domain_cli, - consensus_chain_config.tokio_handle.clone(), - ) - .map_err(|error| { - sc_service::Error::Other(format!( - "Failed to create domain configuration: {error:?}" - )) - })?; - - Some(domain_config) - }; - - cmd.run(consensus_chain_config, domain_config) - })?; + runner.sync_run(|consensus_chain_config| cmd.run(consensus_chain_config))?; } Some(Subcommand::Revert(cmd)) => { let runner = cli.create_runner(cmd)?; @@ -365,15 +343,15 @@ fn main() -> Result<(), Error> { let runner = cli.create_runner(cmd)?; runner.sync_run(|consensus_chain_config| { let domain_cli = DomainCli::new( - cli.run - .base_path()? - .map(|base_path| base_path.path().to_path_buf()), // pass the domain-id manually for benchmark since this is // not possible through cli commands at this moment. vec!["--domain-id".to_owned(), "0".to_owned()].into_iter(), ); let domain_config = domain_cli - .create_domain_configuration(consensus_chain_config.tokio_handle) + .create_domain_configuration( + &consensus_chain_config.base_path.path().join("domains"), + consensus_chain_config.tokio_handle, + ) .map_err(|error| { sc_service::Error::Other(format!( "Failed to create domain configuration: {error:?}" @@ -401,14 +379,12 @@ fn main() -> Result<(), Error> { DomainSubcommand::ExportExecutionReceipt(cmd) => { let runner = cli.create_runner(cmd)?; runner.sync_run(|consensus_chain_config| { - let domain_cli = DomainCli::new( - cli.run - .base_path()? - .map(|base_path| base_path.path().to_path_buf()), - cmd.domain_args.clone().into_iter(), - ); + let domain_cli = DomainCli::new(cmd.domain_args.clone().into_iter()); let domain_config = domain_cli - .create_domain_configuration(consensus_chain_config.tokio_handle) + .create_domain_configuration( + &consensus_chain_config.base_path.path().join("domains"), + consensus_chain_config.tokio_handle, + ) .map_err(|error| { sc_service::Error::Other(format!( "Failed to create domain configuration: {error:?}" @@ -430,10 +406,26 @@ fn main() -> Result<(), Error> { _ => unimplemented!("Domain subcommand"), }, None => { - let runner = cli.create_runner(&cli.run)?; + let mut runner = cli.create_runner(&cli.run)?; set_default_ss58_version(&runner.config().chain_spec); + // Change default paths to Subspace structure + { + let config = runner.config_mut(); + config.database = DatabaseSource::ParityDb { + path: config.base_path.path().join("db"), + }; + // Consensus node doesn't use keystore + config.keystore = KeystoreConfig::InMemory; + if let Some(net_config_path) = &mut config.network.net_config_path { + *net_config_path = config.base_path.path().join("network"); + config.network.node_key = NodeKeyConfig::Ed25519( + sc_network::config::Secret::File(net_config_path.join("secret_ed25519")), + ); + } + } runner.run_node_until_exit(|consensus_chain_config| async move { let tokio_handle = consensus_chain_config.tokio_handle.clone(); + let base_path = consensus_chain_config.base_path.path().to_path_buf(); let database_source = consensus_chain_config.database.clone(); let domains_bootstrap_nodes: serde_json::map::Map = @@ -505,7 +497,7 @@ fn main() -> Result<(), Error> { DsnConfig { keypair, - base_path: consensus_chain_config.base_path.path().into(), + base_path: base_path.clone(), listen_on: cli.dsn_listen_on, bootstrap_nodes: dsn_bootstrap_nodes, reserved_peers: cli.dsn_reserved_peers, @@ -577,12 +569,7 @@ fn main() -> Result<(), Error> { ); let _enter = span.enter(); - let mut domain_cli = DomainCli::new( - cli.run - .base_path()? - .map(|base_path| base_path.path().to_path_buf()), - cli.domain_args.into_iter(), - ); + let mut domain_cli = DomainCli::new(cli.domain_args.into_iter()); let domain_id = domain_cli.domain_id; @@ -663,6 +650,7 @@ fn main() -> Result<(), Error> { let domain_starter = DomainInstanceStarter { domain_cli, + base_path, tokio_handle, consensus_client: consensus_chain_node.client.clone(), consensus_offchain_tx_pool_factory: OffchainTransactionPoolFactory::new( diff --git a/crates/subspace-node/src/domain/cli.rs b/crates/subspace-node/src/domain/cli.rs index a9261c9beb..10f60612cd 100644 --- a/crates/subspace-node/src/domain/cli.rs +++ b/crates/subspace-node/src/domain/cli.rs @@ -14,18 +14,18 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use crate::domain::evm_chain_spec::{self, SpecId}; +use crate::domain::evm_chain_spec; +use crate::domain::evm_chain_spec::SpecId; use clap::Parser; use domain_runtime_primitives::opaque::Block as DomainBlock; use parity_scale_codec::Encode; use sc_cli::{ BlockNumberOrHash, ChainSpec, CliConfiguration, DefaultConfigurationValues, ImportParams, - KeystoreParams, NetworkParams, Result, Role, RunCmd as SubstrateRunCmd, SharedParams, - SubstrateCli, + KeystoreParams, NetworkParams, Role, RunCmd as SubstrateRunCmd, SharedParams, SubstrateCli, }; use sc_client_api::backend::AuxStore; -use sc_service::config::PrometheusConfig; -use sc_service::{BasePath, Configuration}; +use sc_service::config::{KeystoreConfig, PrometheusConfig}; +use sc_service::{BasePath, Configuration, DatabaseSource}; use sp_blockchain::HeaderBackend; use sp_domain_digests::AsPredigest; use sp_domains::storage::RawGenesis; @@ -36,7 +36,7 @@ use sp_runtime::{BuildStorage, DigestItem}; use std::io::Write; use std::net::SocketAddr; use std::num::ParseIntError; -use std::path::PathBuf; +use std::path::Path; use subspace_runtime::Block; /// Sub-commands supported by the executor. @@ -60,11 +60,11 @@ pub enum Subcommand { ExportExecutionReceipt(ExportExecutionReceiptCmd), } -fn parse_domain_id(s: &str) -> std::result::Result { +fn parse_domain_id(s: &str) -> Result { s.parse::().map(Into::into) } -fn parse_operator_id(s: &str) -> std::result::Result { +fn parse_operator_id(s: &str) -> Result { s.parse::().map(OperatorId::from) } @@ -88,26 +88,8 @@ pub struct DomainCli { impl DomainCli { /// Constructs a new instance of [`DomainCli`]. - pub fn new( - consensus_base_path: Option, - domain_args: impl Iterator, - ) -> Self { - let mut cli = - DomainCli::parse_from([Self::executable_name()].into_iter().chain(domain_args)); - - // Use `consensus_base_path/domain-{domain_id}` as the domain base path if it's not - // specified explicitly but there is an explicit consensus base path. - match consensus_base_path { - Some(c_path) if cli.run.shared_params.base_path.is_none() => { - cli.run - .shared_params - .base_path - .replace(c_path.join(format!("domain-{}", u32::from(cli.domain_id)))); - } - _ => {} - } - - cli + pub fn new(domain_args: impl Iterator) -> Self { + DomainCli::parse_from([Self::executable_name()].into_iter().chain(domain_args)) } pub fn additional_args(&self) -> impl Iterator { @@ -119,10 +101,30 @@ impl DomainCli { /// Creates domain configuration from domain cli. pub fn create_domain_configuration( &self, + base_path: &Path, tokio_handle: tokio::runtime::Handle, ) -> sc_cli::Result { - let service_config = SubstrateCli::create_configuration(self, self, tokio_handle)?; - Ok(service_config) + let mut domain_config = SubstrateCli::create_configuration(self, self, tokio_handle)?; + + // Change default paths to Subspace structure + { + let domain_base_path = base_path.join(self.domain_id.to_string()); + domain_config.database = DatabaseSource::ParityDb { + path: domain_base_path.join("db"), + }; + domain_config.keystore = KeystoreConfig::Path { + path: domain_base_path.join("keystore"), + password: match domain_config.keystore { + KeystoreConfig::Path { password, .. } => password, + KeystoreConfig::InMemory => None, + }, + }; + // Network directory is shared with consensus chain + if let Some(net_config_path) = &mut domain_config.network.net_config_path { + *net_config_path = base_path.join("network"); + } + } + Ok(domain_config) } } @@ -157,7 +159,7 @@ impl SubstrateCli for DomainCli { 2022 } - fn load_spec(&self, id: &str) -> std::result::Result, String> { + fn load_spec(&self, id: &str) -> Result, String> { // TODO: Fetch the runtime name of `self.domain_id` properly. let runtime_name = "evm"; match runtime_name { @@ -198,11 +200,11 @@ impl CliConfiguration for DomainCli { self.run.keystore_params() } - fn base_path(&self) -> Result> { + fn base_path(&self) -> sc_cli::Result> { self.shared_params().base_path() } - fn rpc_addr(&self, default_listen_port: u16) -> Result> { + fn rpc_addr(&self, default_listen_port: u16) -> sc_cli::Result> { self.run.rpc_addr(default_listen_port) } @@ -210,15 +212,15 @@ impl CliConfiguration for DomainCli { &self, default_listen_port: u16, chain_spec: &Box, - ) -> Result> { + ) -> sc_cli::Result> { self.run.prometheus_config(default_listen_port, chain_spec) } - fn chain_id(&self, is_dev: bool) -> Result { + fn chain_id(&self, is_dev: bool) -> sc_cli::Result { self.run.chain_id(is_dev) } - fn role(&self, _is_dev: bool) -> Result { + fn role(&self, _is_dev: bool) -> sc_cli::Result { if self.run.validator { return Err(sc_cli::Error::Input( "use `--operator-id` argument to run as operator".to_string(), @@ -235,54 +237,57 @@ impl CliConfiguration for DomainCli { }) } - fn transaction_pool(&self, is_dev: bool) -> Result { + fn transaction_pool( + &self, + is_dev: bool, + ) -> sc_cli::Result { self.run.transaction_pool(is_dev) } - fn trie_cache_maximum_size(&self) -> Result> { + fn trie_cache_maximum_size(&self) -> sc_cli::Result> { self.run.trie_cache_maximum_size() } - fn rpc_methods(&self) -> Result { + fn rpc_methods(&self) -> sc_cli::Result { self.run.rpc_methods() } - fn rpc_max_connections(&self) -> Result { + fn rpc_max_connections(&self) -> sc_cli::Result { self.run.rpc_max_connections() } - fn rpc_cors(&self, is_dev: bool) -> Result>> { + fn rpc_cors(&self, is_dev: bool) -> sc_cli::Result>> { self.run.rpc_cors(is_dev) } - fn default_heap_pages(&self) -> Result> { + fn default_heap_pages(&self) -> sc_cli::Result> { self.run.default_heap_pages() } - fn force_authoring(&self) -> Result { + fn force_authoring(&self) -> sc_cli::Result { self.run.force_authoring() } - fn disable_grandpa(&self) -> Result { + fn disable_grandpa(&self) -> sc_cli::Result { self.run.disable_grandpa() } - fn max_runtime_instances(&self) -> Result> { + fn max_runtime_instances(&self) -> sc_cli::Result> { self.run.max_runtime_instances() } - fn announce_block(&self) -> Result { + fn announce_block(&self) -> sc_cli::Result { self.run.announce_block() } - fn dev_key_seed(&self, is_dev: bool) -> Result> { + fn dev_key_seed(&self, is_dev: bool) -> sc_cli::Result> { self.run.dev_key_seed(is_dev) } fn telemetry_endpoints( &self, chain_spec: &Box, - ) -> Result> { + ) -> sc_cli::Result> { self.run.telemetry_endpoints(chain_spec) } } diff --git a/crates/subspace-node/src/domain/domain_instance_starter.rs b/crates/subspace-node/src/domain/domain_instance_starter.rs index 1103b497fe..59d25ca41e 100644 --- a/crates/subspace-node/src/domain/domain_instance_starter.rs +++ b/crates/subspace-node/src/domain/domain_instance_starter.rs @@ -14,10 +14,12 @@ use sc_consensus_subspace::block_import::BlockImportingNotification; use sc_consensus_subspace::notification::SubspaceNotificationStream; use sc_consensus_subspace::slot_worker::NewSlotNotification; use sc_network::NetworkPeers; -use sc_service::{BasePath, Configuration}; +use sc_service::config::KeystoreConfig; +use sc_service::{BasePath, Configuration, DatabaseSource}; use sc_transaction_pool_api::OffchainTransactionPoolFactory; use sc_utils::mpsc::{TracingUnboundedReceiver, TracingUnboundedSender}; use sp_domains::{DomainInstanceData, RuntimeType}; +use std::path::PathBuf; use std::sync::Arc; use subspace_runtime::{ExecutorDispatch as CExecutorDispatch, RuntimeApi as CRuntimeApi}; use subspace_runtime_primitives::opaque::Block as CBlock; @@ -27,6 +29,7 @@ use subspace_service::FullClient as CFullClient; /// bootstrap result pub struct DomainInstanceStarter { pub domain_cli: DomainCli, + pub base_path: PathBuf, pub tokio_handle: tokio::runtime::Handle, pub consensus_client: Arc>, pub consensus_offchain_tx_pool_factory: OffchainTransactionPoolFactory, @@ -46,7 +49,7 @@ where pub async fn start( self, bootstrap_result: BootstrapResult, - ) -> std::result::Result<(), Box> { + ) -> Result<(), Box> { let BootstrapResult { domain_instance_data, domain_created_at, @@ -60,6 +63,7 @@ where let DomainInstanceStarter { domain_cli, + base_path, tokio_handle, consensus_client, consensus_offchain_tx_pool_factory, @@ -72,7 +76,7 @@ where } = self; let domain_id = domain_cli.domain_id; - let domain_config = { + let mut domain_config = { let chain_id = domain_cli.chain_id(domain_cli.is_dev()?)?; let domain_spec = evm_chain_spec::create_domain_spec(chain_id.as_str(), raw_genesis)?; @@ -80,6 +84,27 @@ where create_configuration::<_, DomainCli, DomainCli>(&domain_cli, domain_spec, tokio_handle)? }; + // Change default paths to Subspace structure + // TODO: Similar copy-paste exists in `DomainCli::create_domain_configuration()` and should + // be de-duplicated + { + let domain_base_path = base_path.join("domains").join(domain_id.to_string()); + domain_config.database = DatabaseSource::ParityDb { + path: domain_base_path.join("db"), + }; + domain_config.keystore = KeystoreConfig::Path { + path: domain_base_path.join("keystore"), + password: match domain_config.keystore { + KeystoreConfig::Path { password, .. } => password, + KeystoreConfig::InMemory => None, + }, + }; + // Network directory is shared with consensus chain + if let Some(net_config_path) = &mut domain_config.network.net_config_path { + *net_config_path = base_path.join("network"); + } + } + let block_importing_notification_stream = || { block_importing_notification_stream.subscribe().then( |block_importing_notification| async move { diff --git a/crates/subspace-node/src/lib.rs b/crates/subspace-node/src/lib.rs index e79f634b29..45fb58b4ee 100644 --- a/crates/subspace-node/src/lib.rs +++ b/crates/subspace-node/src/lib.rs @@ -39,44 +39,25 @@ pub struct PurgeChainCmd { /// The base struct of the purge-chain command. #[clap(flatten)] pub base: sc_cli::PurgeChainCmd, - - /// Domain arguments - /// - /// The command-line arguments provided first will be passed to the embedded consensus node, - /// while the arguments provided after `--` will be passed to the domain node. - /// - /// subspace-node purge-chain [consensus-chain-args] -- [domain-args] - #[arg(raw = true)] - pub domain_args: Vec, } impl PurgeChainCmd { /// Run the purge command - pub fn run( - &self, - consensus_chain_config: sc_service::Configuration, - domain_config: Option, - ) -> sc_cli::Result<()> { - let mut db_paths = domain_config.map_or(vec![], |dc| { - vec![dc - .database - .path() - .expect("No custom database used here; qed") - .to_path_buf() - .clone()] - }); - - db_paths.push( - consensus_chain_config - .database - .path() - .expect("No custom database used here; qed") - .to_path_buf(), - ); + pub fn run(&self, consensus_chain_config: sc_service::Configuration) -> sc_cli::Result<()> { + let paths = vec![ + consensus_chain_config.base_path.path().join("db"), + consensus_chain_config.base_path.path().join("domains"), + consensus_chain_config.base_path.path().join("network"), + // TODO: Following three are temporary workaround for wiping old chains, remove once enough time has passed + consensus_chain_config.base_path.path().join("chains"), + consensus_chain_config.base_path.path().join("domain-0"), + consensus_chain_config.base_path.path().join("domain-1"), + ]; if !self.base.yes { - for db_path in &db_paths { - println!("{}", db_path.display()); + println!("Following paths (if exist) are about to be removed:"); + for path in &paths { + println!(" {}", path.display()); } print!("Are you sure to remove? [y/N]: "); io::stdout().flush().expect("failed to flush stdout"); @@ -94,13 +75,13 @@ impl PurgeChainCmd { } } - for db_path in &db_paths { + for db_path in &paths { match fs::remove_dir_all(db_path) { Ok(_) => { println!("{:?} removed.", &db_path); } Err(ref err) if err.kind() == io::ErrorKind::NotFound => { - eprintln!("{:?} did not exist.", &db_path); + eprintln!("{:?} did not exist already, skipping.", &db_path); } Err(err) => return Err(err.into()), }