1234567891011121314151617181920212223242526272829303132333435use crate::{36 chain_spec,37 cli::{Cli, RelayChainCli, Subcommand},38 service::{new_partial, ParachainRuntimeExecutor},39};40use codec::Encode;41use cumulus_primitives_core::ParaId;42use cumulus_client_service::genesis::generate_genesis_block;43use log::info;44use unique_runtime::Block;45use polkadot_parachain::primitives::AccountIdConversion;46use sc_cli::{47 ChainSpec, CliConfiguration, DefaultConfigurationValues, ImportParams, KeystoreParams,48 NetworkParams, Result, RuntimeVersion, SharedParams, SubstrateCli,49};50use sc_service::{51 config::{BasePath, PrometheusConfig},52};53use sp_core::hexdisplay::HexDisplay;54use sp_runtime::traits::Block as BlockT;55use std::{io::Write, net::SocketAddr};5657fn load_spec(id: &str) -> std::result::Result<Box<dyn sc_service::ChainSpec>, String> {58 Ok(match id {59 "westend-local" => Box::new(chain_spec::local_testnet_westend_config()),60 "rococo-local" => Box::new(chain_spec::local_testnet_rococo_config()),61 "dev" => Box::new(chain_spec::development_config()),62 "" | "local" => Box::new(chain_spec::local_testnet_rococo_config()),63 path => Box::new(chain_spec::ChainSpec::from_json_file(64 std::path::PathBuf::from(path),65 )?),66 })67}6869impl SubstrateCli for Cli {70 71 fn impl_name() -> String {72 "Opal Node".into()73 }7475 fn impl_version() -> String {76 env!("SUBSTRATE_CLI_IMPL_VERSION").into()77 }78 79 fn description() -> String {80 format!(81 "Opal Node\n\nThe command-line arguments provided first will be \82 passed to the parachain node, while the arguments provided after -- will be passed \83 to the relaychain node.\n\n\84 {} [parachain-args] -- [relaychain-args]",85 Self::executable_name()86 )87 }8889 fn author() -> String {90 env!("CARGO_PKG_AUTHORS").into()91 }9293 94 fn support_url() -> String {95 "support@unique.network".into()96 }9798 fn copyright_start_year() -> i32 {99 2019100 }101102 fn load_spec(&self, id: &str) -> std::result::Result<Box<dyn sc_service::ChainSpec>, String> {103 load_spec(id)104 }105106 fn native_runtime_version(_: &Box<dyn ChainSpec>) -> &'static RuntimeVersion {107 &unique_runtime::VERSION108 }109}110111impl SubstrateCli for RelayChainCli {112 113 fn impl_name() -> String {114 "Opal Node".into()115 }116117 fn impl_version() -> String {118 env!("SUBSTRATE_CLI_IMPL_VERSION").into()119 }120 121 fn description() -> String {122 "Opal Node\n\nThe command-line arguments provided first will be \123 passed to the parachain node, while the arguments provided after -- will be passed \124 to the relaychain node.\n\n\125 parachain-collator [parachain-args] -- [relaychain-args]"126 .into()127 }128129 fn author() -> String {130 env!("CARGO_PKG_AUTHORS").into()131 }132 133 fn support_url() -> String {134 "support@unique.network".into()135 }136137 fn copyright_start_year() -> i32 {138 2019139 }140141 fn load_spec(&self, id: &str) -> std::result::Result<Box<dyn sc_service::ChainSpec>, String> {142 polkadot_cli::Cli::from_iter([RelayChainCli::executable_name()].iter()).load_spec(id)143 }144145 fn native_runtime_version(chain_spec: &Box<dyn ChainSpec>) -> &'static RuntimeVersion {146 polkadot_cli::Cli::native_runtime_version(chain_spec)147 }148}149150#[allow(clippy::borrowed_box)]151fn extract_genesis_wasm(chain_spec: &Box<dyn sc_service::ChainSpec>) -> Result<Vec<u8>> {152 let mut storage = chain_spec.build_storage()?;153154 storage155 .top156 .remove(sp_core::storage::well_known_keys::CODE)157 .ok_or_else(|| "Could not find wasm file in genesis state!".into())158}159160macro_rules! construct_async_run {161 (|$components:ident, $cli:ident, $cmd:ident, $config:ident| $( $code:tt )* ) => {{162 let runner = $cli.create_runner($cmd)?;163 runner.async_run(|$config| {164 let $components = new_partial::<165 _166 >(167 &$config,168 crate::service::parachain_build_import_queue,169 )?;170 let task_manager = $components.task_manager;171 { $( $code )* }.map(|v| (v, task_manager))172 })173 }}174}175176177pub fn run() -> Result<()> {178 let cli = Cli::from_args();179180 match &cli.subcommand {181 Some(Subcommand::BuildSpec(cmd)) => {182 let runner = cli.create_runner(cmd)?;183 runner.sync_run(|config| cmd.run(config.chain_spec, config.network))184 }185 Some(Subcommand::CheckBlock(cmd)) => {186 construct_async_run!(|components, cli, cmd, config| {187 Ok(cmd.run(components.client, components.import_queue))188 })189 }190 Some(Subcommand::ExportBlocks(cmd)) => {191 construct_async_run!(|components, cli, cmd, config| {192 Ok(cmd.run(components.client, config.database))193 })194 }195 Some(Subcommand::ExportState(cmd)) => {196 construct_async_run!(|components, cli, cmd, config| {197 Ok(cmd.run(components.client, config.chain_spec))198 })199 }200 Some(Subcommand::ImportBlocks(cmd)) => {201 construct_async_run!(|components, cli, cmd, config| {202 Ok(cmd.run(components.client, components.import_queue))203 })204 }205 Some(Subcommand::PurgeChain(cmd)) => {206 let runner = cli.create_runner(cmd)?;207208 runner.sync_run(|config| {209 let polkadot_cli = RelayChainCli::new(210 &config,211 [RelayChainCli::executable_name()]212 .iter()213 .chain(cli.relaychain_args.iter()),214 );215216 let polkadot_config = SubstrateCli::create_configuration(217 &polkadot_cli,218 &polkadot_cli,219 config.tokio_handle.clone(),220 )221 .map_err(|err| format!("Relay chain argument error: {}", err))?;222223 cmd.run(config, polkadot_config)224 })225 }226 Some(Subcommand::Revert(cmd)) => construct_async_run!(|components, cli, cmd, config| {227 Ok(cmd.run(components.client, components.backend))228 }),229 Some(Subcommand::ExportGenesisState(params)) => {230 let mut builder = sc_cli::LoggerBuilder::new("");231 builder.with_profiling(sc_tracing::TracingReceiver::Log, "");232 let _ = builder.init();233234 let spec = load_spec(¶ms.chain.clone().unwrap_or_default())?;235 let state_version = Cli::native_runtime_version(&spec).state_version();236 let block: Block = generate_genesis_block(&spec, state_version)?;237 let raw_header = block.header().encode();238 let output_buf = if params.raw {239 raw_header240 } else {241 format!("0x{:?}", HexDisplay::from(&block.header().encode())).into_bytes()242 };243244 if let Some(output) = ¶ms.output {245 std::fs::write(output, output_buf)?;246 } else {247 std::io::stdout().write_all(&output_buf)?;248 }249250 Ok(())251 }252 Some(Subcommand::ExportGenesisWasm(params)) => {253 let mut builder = sc_cli::LoggerBuilder::new("");254 builder.with_profiling(sc_tracing::TracingReceiver::Log, "");255 let _ = builder.init();256257 let raw_wasm_blob =258 extract_genesis_wasm(&cli.load_spec(¶ms.chain.clone().unwrap_or_default())?)?;259 let output_buf = if params.raw {260 raw_wasm_blob261 } else {262 format!("0x{:?}", HexDisplay::from(&raw_wasm_blob)).into_bytes()263 };264265 if let Some(output) = ¶ms.output {266 std::fs::write(output, output_buf)?;267 } else {268 std::io::stdout().write_all(&output_buf)?;269 }270271 Ok(())272 }273 Some(Subcommand::Benchmark(cmd)) => {274 if cfg!(feature = "runtime-benchmarks") {275 let runner = cli.create_runner(cmd)?;276277 runner.sync_run(|config| cmd.run::<Block, ParachainRuntimeExecutor>(config))278 } else {279 Err("Benchmarking wasn't enabled when building the node. \280 You can enable it with `--features runtime-benchmarks`."281 .into())282 }283 }284 None => {285 let runner = cli.create_runner(&cli.run.normalize())?;286287 runner.run_node_until_exit(|config| async move {288 let para_id = chain_spec::Extensions::try_get(&*config.chain_spec)289 .map(|e| e.para_id)290 .ok_or("Could not find parachain ID in chain-spec.")?;291292 let polkadot_cli = RelayChainCli::new(293 &config,294 [RelayChainCli::executable_name()]295 .iter()296 .chain(cli.relaychain_args.iter()),297 );298299 let id = ParaId::from(para_id);300301 let parachain_account =302 AccountIdConversion::<polkadot_primitives::v0::AccountId>::into_account(&id);303304 let state_version =305 RelayChainCli::native_runtime_version(&config.chain_spec).state_version();306 let block: Block = generate_genesis_block(&config.chain_spec, state_version)307 .map_err(|e| format!("{:?}", e))?;308 let genesis_state = format!("0x{:?}", HexDisplay::from(&block.header().encode()));309 let genesis_hash = format!("0x{:?}", HexDisplay::from(&block.header().hash().0));310311 let polkadot_config = SubstrateCli::create_configuration(312 &polkadot_cli,313 &polkadot_cli,314 config.tokio_handle.clone(),315 )316 .map_err(|err| format!("Relay chain argument error: {}", err))?;317318 info!("Parachain id: {:?}", id);319 info!("Parachain Account: {}", parachain_account);320 info!("Parachain genesis state: {}", genesis_state);321 info!("Parachain genesis hash: {}", genesis_hash);322 info!(323 "Is collating: {}",324 if config.role.is_authority() {325 "yes"326 } else {327 "no"328 }329 );330331 crate::service::start_node(config, polkadot_config, id)332 .await333 .map(|r| r.0)334 .map_err(Into::into)335 })336 }337 }338}339340impl DefaultConfigurationValues for RelayChainCli {341 fn p2p_listen_port() -> u16 {342 30334343 }344345 fn rpc_ws_listen_port() -> u16 {346 9945347 }348349 fn rpc_http_listen_port() -> u16 {350 9934351 }352353 fn prometheus_listen_port() -> u16 {354 9616355 }356}357358impl CliConfiguration<Self> for RelayChainCli {359 fn shared_params(&self) -> &SharedParams {360 self.base.base.shared_params()361 }362363 fn import_params(&self) -> Option<&ImportParams> {364 self.base.base.import_params()365 }366367 fn network_params(&self) -> Option<&NetworkParams> {368 self.base.base.network_params()369 }370371 fn keystore_params(&self) -> Option<&KeystoreParams> {372 self.base.base.keystore_params()373 }374375 fn base_path(&self) -> Result<Option<BasePath>> {376 Ok(self377 .shared_params()378 .base_path()379 .or_else(|| self.base_path.clone().map(Into::into)))380 }381382 fn rpc_http(&self, default_listen_port: u16) -> Result<Option<SocketAddr>> {383 self.base.base.rpc_http(default_listen_port)384 }385386 fn rpc_ipc(&self) -> Result<Option<String>> {387 self.base.base.rpc_ipc()388 }389390 fn rpc_ws(&self, default_listen_port: u16) -> Result<Option<SocketAddr>> {391 self.base.base.rpc_ws(default_listen_port)392 }393394 fn prometheus_config(395 &self,396 default_listen_port: u16,397 chain_spec: &Box<dyn ChainSpec>,398 ) -> Result<Option<PrometheusConfig>> {399 self.base400 .base401 .prometheus_config(default_listen_port, chain_spec)402 }403404 fn init<F>(405 &self,406 _support_url: &String,407 _impl_version: &String,408 _logger_hook: F,409 _config: &sc_service::Configuration,410 ) -> Result<()> {411 unreachable!("PolkadotCli is never initialized; qed");412 }413414 fn chain_id(&self, is_dev: bool) -> Result<String> {415 let chain_id = self.base.base.chain_id(is_dev)?;416417 Ok(if chain_id.is_empty() {418 self.chain_id.clone().unwrap_or_default()419 } else {420 chain_id421 })422 }423424 fn role(&self, is_dev: bool) -> Result<sc_service::Role> {425 self.base.base.role(is_dev)426 }427428 fn transaction_pool(&self) -> Result<sc_service::config::TransactionPoolOptions> {429 self.base.base.transaction_pool()430 }431432 fn state_cache_child_ratio(&self) -> Result<Option<usize>> {433 self.base.base.state_cache_child_ratio()434 }435436 fn rpc_methods(&self) -> Result<sc_service::config::RpcMethods> {437 self.base.base.rpc_methods()438 }439440 fn rpc_ws_max_connections(&self) -> Result<Option<usize>> {441 self.base.base.rpc_ws_max_connections()442 }443444 fn rpc_cors(&self, is_dev: bool) -> Result<Option<Vec<String>>> {445 self.base.base.rpc_cors(is_dev)446 }447448 fn default_heap_pages(&self) -> Result<Option<u64>> {449 self.base.base.default_heap_pages()450 }451452 fn force_authoring(&self) -> Result<bool> {453 self.base.base.force_authoring()454 }455456 fn disable_grandpa(&self) -> Result<bool> {457 self.base.base.disable_grandpa()458 }459460 fn max_runtime_instances(&self) -> Result<Option<usize>> {461 self.base.base.max_runtime_instances()462 }463464 fn announce_block(&self) -> Result<bool> {465 self.base.base.announce_block()466 }467468 fn telemetry_endpoints(469 &self,470 chain_spec: &Box<dyn ChainSpec>,471 ) -> Result<Option<sc_telemetry::TelemetryEndpoints>> {472 self.base.base.telemetry_endpoints(chain_spec)473 }474}