From bdcbbd6f55b360edf6c863e975d48b6cd8fda187 Mon Sep 17 00:00:00 2001 From: vasylenko-yevhen Date: Wed, 14 Sep 2022 01:24:27 +0300 Subject: [PATCH] Adds clean parachain runtime --- bin/zero-parachain-live/node/Cargo.toml | 101 ++ bin/zero-parachain-live/node/build.rs | 7 + .../node/src/chain_spec.rs | 229 +++++ bin/zero-parachain-live/node/src/cli.rs | 93 ++ bin/zero-parachain-live/node/src/command.rs | 441 ++++++++ bin/zero-parachain-live/node/src/main.rs | 14 + bin/zero-parachain-live/node/src/rpc.rs | 58 ++ bin/zero-parachain-live/node/src/service.rs | 535 ++++++++++ bin/zero-parachain-live/runtime/Cargo.toml | 175 ++++ bin/zero-parachain-live/runtime/build.rs | 9 + bin/zero-parachain-live/runtime/src/lib.rs | 939 ++++++++++++++++++ .../runtime/src/weights/block_weights.rs | 46 + .../runtime/src/weights/extrinsic_weights.rs | 46 + .../runtime/src/weights/mod.rs | 28 + .../runtime/src/weights/paritydb_weights.rs | 63 ++ .../runtime/src/weights/rocksdb_weights.rs | 63 ++ .../runtime/src/xcm_config.rs | 221 +++++ 17 files changed, 3068 insertions(+) create mode 100644 bin/zero-parachain-live/node/Cargo.toml create mode 100644 bin/zero-parachain-live/node/build.rs create mode 100644 bin/zero-parachain-live/node/src/chain_spec.rs create mode 100644 bin/zero-parachain-live/node/src/cli.rs create mode 100644 bin/zero-parachain-live/node/src/command.rs create mode 100644 bin/zero-parachain-live/node/src/main.rs create mode 100644 bin/zero-parachain-live/node/src/rpc.rs create mode 100644 bin/zero-parachain-live/node/src/service.rs create mode 100644 bin/zero-parachain-live/runtime/Cargo.toml create mode 100644 bin/zero-parachain-live/runtime/build.rs create mode 100644 bin/zero-parachain-live/runtime/src/lib.rs create mode 100644 bin/zero-parachain-live/runtime/src/weights/block_weights.rs create mode 100644 bin/zero-parachain-live/runtime/src/weights/extrinsic_weights.rs create mode 100644 bin/zero-parachain-live/runtime/src/weights/mod.rs create mode 100644 bin/zero-parachain-live/runtime/src/weights/paritydb_weights.rs create mode 100644 bin/zero-parachain-live/runtime/src/weights/rocksdb_weights.rs create mode 100644 bin/zero-parachain-live/runtime/src/xcm_config.rs diff --git a/bin/zero-parachain-live/node/Cargo.toml b/bin/zero-parachain-live/node/Cargo.toml new file mode 100644 index 0000000000..480347a522 --- /dev/null +++ b/bin/zero-parachain-live/node/Cargo.toml @@ -0,0 +1,101 @@ +[package] +name = "parachain-subzero-node-live" +version = "0.1.0" +authors = ["ZERO "] +description = "A substrate node for video games and beyond." +license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +homepage = "https://zero.io" +repository = "https://github.com/playzero/zero-network/" +edition = "2021" +build = "build.rs" + +[[bin]] +name = "subzero-collator-live" +path = "src/main.rs" + +[dependencies] +clap = { version = "3.2.5", features = ["derive"] } +derive_more = "0.99.2" +log = "0.4.17" +codec = { package = "parity-scale-codec", version = "3.0.0" } +serde = { version = "1.0.137", features = ["derive"] } +hex-literal = "0.3.4" +jsonrpsee = { version = "0.14.0", features = ["server"] } + +# Local +parachain-subzero-runtime-live = { path = "../runtime" } + +# Substrate +frame-benchmarking = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.25" } +frame-benchmarking-cli = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.25" } +pallet-transaction-payment-rpc = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.25" } +sc-basic-authorship = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.25" } +sc-chain-spec = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.25" } +sc-cli = { git = "https://github.com/paritytech/substrate", features = ["wasmtime"] , branch = "polkadot-v0.9.25" } +sc-client-api = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.25" } +sc-consensus = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.25" } +sc-executor = { git = "https://github.com/paritytech/substrate", features = ["wasmtime"] , branch = "polkadot-v0.9.25" } +sc-keystore = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.25" } +sc-network = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.25" } +sc-rpc = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.25" } +sc-rpc-api = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.25" } +sc-service = { git = "https://github.com/paritytech/substrate", features = ["wasmtime"] , branch = "polkadot-v0.9.25" } +sc-sysinfo = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.25" } +sc-telemetry = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.25" } +sc-tracing = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.25" } +sc-transaction-pool = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.25" } +sc-transaction-pool-api = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.25" } +sp-api = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.25" } +sp-block-builder = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.25" } +sp-blockchain = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.25" } +sp-consensus = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.25" } +sp-consensus-aura = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.25" } +sp-core = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.25" } +sp-inherents = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.25" } +sp-keystore = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.25" } +sp-offchain = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.25" } +sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.25" } +sp-session = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.25" } +sp-timestamp = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.25" } +sp-transaction-pool = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.25" } +substrate-frame-rpc-system = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.25" } +substrate-prometheus-endpoint = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.25" } +try-runtime-cli = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.25" } + +# Polkadot +polkadot-cli = { git = "https://github.com/paritytech/polkadot", branch = "release-v0.9.25", features = [ + # Set of features fixes next error: + # Invalid input: `rococo-local` only supported with `rococo-native` feature enabled. + # Includes default features + rococo. + "wasmtime", "db", "cli", "full-node", "trie-memory-tracker", "polkadot-native", "rococo-native" +] } +polkadot-parachain = { git = "https://github.com/paritytech/polkadot", branch = "release-v0.9.25" } +polkadot-primitives = { git = "https://github.com/paritytech/polkadot", branch = "release-v0.9.25" } +polkadot-service = { git = "https://github.com/paritytech/polkadot", branch = "release-v0.9.25" } +xcm = { git = "https://github.com/paritytech/polkadot", default-features = false, branch = "release-v0.9.25" } + +# Cumulus +cumulus-client-cli = { git = "https://github.com/paritytech/cumulus", branch = "polkadot-v0.9.25" } +cumulus-client-collator = { git = "https://github.com/paritytech/cumulus", branch = "polkadot-v0.9.25" } +cumulus-client-consensus-aura = { git = "https://github.com/paritytech/cumulus", branch = "polkadot-v0.9.25" } +cumulus-client-consensus-common = { git = "https://github.com/paritytech/cumulus", branch = "polkadot-v0.9.25" } +cumulus-client-network = { git = "https://github.com/paritytech/cumulus", branch = "polkadot-v0.9.25" } +cumulus-client-service = { git = "https://github.com/paritytech/cumulus", branch = "polkadot-v0.9.25" } +cumulus-primitives-core = { git = "https://github.com/paritytech/cumulus", branch = "polkadot-v0.9.25" } +cumulus-primitives-parachain-inherent = { git = "https://github.com/paritytech/cumulus", branch = "polkadot-v0.9.25" } +cumulus-relay-chain-inprocess-interface = { git = "https://github.com/paritytech/cumulus", branch = "polkadot-v0.9.25" } +cumulus-relay-chain-interface = { git = "https://github.com/paritytech/cumulus", branch = "polkadot-v0.9.25" } +cumulus-relay-chain-rpc-interface = { git = "https://github.com/paritytech/cumulus", branch = "polkadot-v0.9.25" } + +primitives = { version = "2.0.0", package = "zero-primitives", default-features = false, path = "../../../primitives" } + +[build-dependencies] +substrate-build-script-utils = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.25" } + +[features] +default = [] +runtime-benchmarks = [ + "parachain-subzero-runtime-live/runtime-benchmarks", + "polkadot-cli/runtime-benchmarks", +] +try-runtime = ["parachain-subzero-runtime-live/try-runtime"] diff --git a/bin/zero-parachain-live/node/build.rs b/bin/zero-parachain-live/node/build.rs new file mode 100644 index 0000000000..e3bfe3116b --- /dev/null +++ b/bin/zero-parachain-live/node/build.rs @@ -0,0 +1,7 @@ +use substrate_build_script_utils::{generate_cargo_keys, rerun_if_git_head_changed}; + +fn main() { + generate_cargo_keys(); + + rerun_if_git_head_changed(); +} diff --git a/bin/zero-parachain-live/node/src/chain_spec.rs b/bin/zero-parachain-live/node/src/chain_spec.rs new file mode 100644 index 0000000000..ae2853d116 --- /dev/null +++ b/bin/zero-parachain-live/node/src/chain_spec.rs @@ -0,0 +1,229 @@ +use cumulus_primitives_core::ParaId; +use parachain_subzero_runtime_live::{AccountId, AuraId, Signature, SudoConfig}; +use sc_chain_spec::{ChainSpecExtension, ChainSpecGroup}; +use sc_service::ChainType; +use serde::{Deserialize, Serialize}; +use sp_core::{sr25519, Pair, Public}; +use sp_runtime::traits::{IdentifyAccount, Verify}; + +use primitives::{ + currency::ZERO, + cent +}; + +/// Specialized `ChainSpec` for the normal parachain runtime. +pub type ChainSpec = + sc_service::GenericChainSpec; + +/// The default XCM version to set in genesis config. +const SAFE_XCM_VERSION: u32 = xcm::prelude::XCM_VERSION; +const DEFAULT_PARA_ID: u32 = 4040; + +/// Helper function to generate a crypto pair from seed +pub fn get_public_from_seed(seed: &str) -> ::Public { + TPublic::Pair::from_string(&format!("//{}", seed), None) + .expect("static values are valid; qed") + .public() +} + +/// The extensions for the [`ChainSpec`]. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, ChainSpecGroup, ChainSpecExtension)] +#[serde(deny_unknown_fields)] +pub struct Extensions { + /// The relay chain of the Parachain. + pub relay_chain: String, + /// The id of the Parachain. + pub para_id: u32, +} + +impl Extensions { + /// Try to get the extension from the given `ChainSpec`. + pub fn try_get(chain_spec: &dyn sc_service::ChainSpec) -> Option<&Self> { + sc_chain_spec::get_extension(chain_spec.extensions()) + } +} + +type AccountPublic = ::Signer; + +/// Generate collator keys from seed. +/// +/// This function's return type must always match the session keys of the chain in tuple format. +pub fn get_collator_keys_from_seed(seed: &str) -> AuraId { + get_public_from_seed::(seed) +} + +/// Helper function to generate an account ID from seed +pub fn get_account_id_from_seed(seed: &str) -> AccountId +where + AccountPublic: From<::Public>, +{ + AccountPublic::from(get_public_from_seed::(seed)).into_account() +} + +/// Generate the session keys from individual elements. +/// +/// The input must be a tuple of individual keys (a single arg for now since we have just one key). +pub fn subzero_session_keys(keys: AuraId) -> parachain_subzero_runtime_live::SessionKeys { + parachain_subzero_runtime_live::SessionKeys { aura: keys } +} + +pub fn development_config() -> ChainSpec { + + ChainSpec::from_genesis( + // Name + "Development", + // ID + "dev", + ChainType::Development, + move || { + testnet_genesis( + // initial collators. + vec![ + ( + get_account_id_from_seed::("Alice"), + get_collator_keys_from_seed("Alice"), + ), + ( + get_account_id_from_seed::("Bob"), + get_collator_keys_from_seed("Bob"), + ), + ], + vec![ + get_account_id_from_seed::("Alice"), + get_account_id_from_seed::("Bob"), + get_account_id_from_seed::("Charlie"), + get_account_id_from_seed::("Dave"), + get_account_id_from_seed::("Eve"), + get_account_id_from_seed::("Ferdie"), + get_account_id_from_seed::("Alice//stash"), + get_account_id_from_seed::("Bob//stash"), + get_account_id_from_seed::("Charlie//stash"), + get_account_id_from_seed::("Dave//stash"), + get_account_id_from_seed::("Eve//stash"), + get_account_id_from_seed::("Ferdie//stash"), + ], + get_account_id_from_seed::("Alice"), + DEFAULT_PARA_ID.into(), + ) + }, + Vec::new(), + None, + None, + None, + None, + Extensions { + relay_chain: "rococo-local".into(), // You MUST set this to the correct network! + para_id: DEFAULT_PARA_ID, + }, + ) +} + +pub fn local_testnet_config() -> ChainSpec { + // Give your base currency a unit name and decimal places + let mut properties = sc_chain_spec::Properties::new(); + properties.insert("tokenSymbol".into(), "ZERO".into()); + properties.insert("tokenDecimals".into(), 18.into()); + properties.insert("ss58Format".into(), 25.into()); + + ChainSpec::from_genesis( + // Name + "Local Testnet", + // ID + "local_testnet", + ChainType::Local, + move || { + testnet_genesis( + // initial collators. + vec![ + ( + get_account_id_from_seed::("Alice"), + get_collator_keys_from_seed("Alice"), + ), + ( + get_account_id_from_seed::("Bob"), + get_collator_keys_from_seed("Bob"), + ), + ], + vec![ + get_account_id_from_seed::("Alice"), + get_account_id_from_seed::("Bob"), + get_account_id_from_seed::("Charlie"), + get_account_id_from_seed::("Dave"), + get_account_id_from_seed::("Eve"), + get_account_id_from_seed::("Ferdie"), + get_account_id_from_seed::("Alice//stash"), + get_account_id_from_seed::("Bob//stash"), + get_account_id_from_seed::("Charlie//stash"), + get_account_id_from_seed::("Dave//stash"), + get_account_id_from_seed::("Eve//stash"), + get_account_id_from_seed::("Ferdie//stash"), + ], + get_account_id_from_seed::("Alice"), + DEFAULT_PARA_ID.into(), + ) + }, + // Bootnodes + Vec::new(), + // Telemetry + None, + // Protocol ID + Some("subzero-local"), + // Fork ID + None, + // Properties + Some(properties), + // Extensions + Extensions { + relay_chain: "rococo-local".into(), // You MUST set this to the correct network! + para_id: DEFAULT_PARA_ID, + }, + ) +} + +fn testnet_genesis( + invulnerables: Vec<(AccountId, AuraId)>, + endowed_accounts: Vec, + root_key: AccountId, + id: ParaId, +) -> parachain_subzero_runtime_live::GenesisConfig { + parachain_subzero_runtime_live::GenesisConfig { + system: parachain_subzero_runtime_live::SystemConfig { + code: parachain_subzero_runtime_live::WASM_BINARY + .expect("WASM binary was not build, please build it!") + .to_vec(), + }, + sudo: SudoConfig { key: Some(root_key) }, + balances: parachain_subzero_runtime_live::BalancesConfig { + balances: endowed_accounts.iter().cloned().map(|k| (k, 1 << 60)).collect(), + }, + parachain_info: parachain_subzero_runtime_live::ParachainInfoConfig { parachain_id: id }, + collator_selection: parachain_subzero_runtime_live::CollatorSelectionConfig { + invulnerables: invulnerables.iter().cloned().map(|(acc, _)| acc).collect(), + candidacy_bond: cent(ZERO) * 16, + ..Default::default() + }, + session: parachain_subzero_runtime_live::SessionConfig { + keys: invulnerables + .into_iter() + .map(|(acc, aura)| { + ( + acc.clone(), // account id + acc, // validator id + subzero_session_keys(aura), // session keys + ) + }) + .collect(), + }, + // no need to pass anything to aura, in fact it will panic if we do. Session will take care + // of this. + aura: Default::default(), + aura_ext: Default::default(), + parachain_system: Default::default(), + polkadot_xcm: parachain_subzero_runtime_live::PolkadotXcmConfig { + safe_xcm_version: Some(SAFE_XCM_VERSION), + }, + council: Default::default(), + treasury: Default::default(), + tokens: Default::default(), + } +} diff --git a/bin/zero-parachain-live/node/src/cli.rs b/bin/zero-parachain-live/node/src/cli.rs new file mode 100644 index 0000000000..949ce489d6 --- /dev/null +++ b/bin/zero-parachain-live/node/src/cli.rs @@ -0,0 +1,93 @@ +use std::path::PathBuf; + +/// Sub-commands supported by the collator. +#[derive(Debug, clap::Subcommand)] +pub enum Subcommand { + /// Build a chain specification. + BuildSpec(sc_cli::BuildSpecCmd), + + /// Validate blocks. + CheckBlock(sc_cli::CheckBlockCmd), + + /// Export blocks. + ExportBlocks(sc_cli::ExportBlocksCmd), + + /// Export the state of a given block into a chain spec. + ExportState(sc_cli::ExportStateCmd), + + /// Import blocks. + ImportBlocks(sc_cli::ImportBlocksCmd), + + /// Revert the chain to a previous state. + Revert(sc_cli::RevertCmd), + + /// Remove the whole chain. + PurgeChain(cumulus_client_cli::PurgeChainCmd), + + /// Export the genesis state of the parachain. + ExportGenesisState(cumulus_client_cli::ExportGenesisStateCommand), + + /// Export the genesis wasm of the parachain. + ExportGenesisWasm(cumulus_client_cli::ExportGenesisWasmCommand), + + /// Sub-commands concerned with benchmarking. + /// The pallet benchmarking moved to the `pallet` sub-command. + #[clap(subcommand)] + Benchmark(frame_benchmarking_cli::BenchmarkCmd), + + /// Try some testing command against a specified runtime state. + TryRuntime(try_runtime_cli::TryRuntimeCmd), +} + +#[derive(Debug, clap::Parser)] +#[clap( + propagate_version = true, + args_conflicts_with_subcommands = true, + subcommand_negates_reqs = true +)] +pub struct Cli { + #[clap(subcommand)] + pub subcommand: Option, + + #[clap(flatten)] + pub run: cumulus_client_cli::RunCmd, + + /// Disable automatic hardware benchmarks. + /// + /// By default these benchmarks are automatically ran at startup and measure + /// the CPU speed, the memory bandwidth and the disk speed. + /// + /// The results are then printed out in the logs, and also sent as part of + /// telemetry, if telemetry is enabled. + #[clap(long)] + pub no_hardware_benchmarks: bool, + + /// Relay chain arguments + #[clap(raw = true)] + pub relay_chain_args: Vec, +} + +#[derive(Debug)] +pub struct RelayChainCli { + /// The actual relay chain cli object. + pub base: polkadot_cli::RunCmd, + + /// Optional chain id that should be passed to the relay chain. + pub chain_id: Option, + + /// The base path that should be used by the relay chain. + pub base_path: Option, +} + +impl RelayChainCli { + /// Parse the relay chain CLI parameters using the para chain `Configuration`. + pub fn new<'a>( + para_config: &sc_service::Configuration, + relay_chain_args: impl Iterator, + ) -> Self { + let extension = crate::chain_spec::Extensions::try_get(&*para_config.chain_spec); + let chain_id = extension.map(|e| e.relay_chain.clone()); + let base_path = para_config.base_path.as_ref().map(|x| x.path().join("polkadot")); + Self { base_path, chain_id, base: clap::Parser::parse_from(relay_chain_args) } + } +} diff --git a/bin/zero-parachain-live/node/src/command.rs b/bin/zero-parachain-live/node/src/command.rs new file mode 100644 index 0000000000..62b982e404 --- /dev/null +++ b/bin/zero-parachain-live/node/src/command.rs @@ -0,0 +1,441 @@ +use std::net::SocketAddr; + +use codec::Encode; +use cumulus_client_cli::generate_genesis_block; +use cumulus_primitives_core::ParaId; +use frame_benchmarking_cli::{BenchmarkCmd, SUBSTRATE_REFERENCE_HARDWARE}; +use log::info; +use parachain_subzero_runtime_live::{Block, RuntimeApi}; +use sc_cli::{ + ChainSpec, CliConfiguration, DefaultConfigurationValues, ImportParams, KeystoreParams, + NetworkParams, Result, RuntimeVersion, SharedParams, SubstrateCli, +}; +use sc_service::{ + config::{BasePath, PrometheusConfig}, + TaskManager, +}; +use sp_core::hexdisplay::HexDisplay; +use sp_runtime::traits::{AccountIdConversion, Block as BlockT}; + +use crate::{ + chain_spec, + cli::{Cli, RelayChainCli, Subcommand}, + service::{new_partial, SubzeroRuntimeExecutor}, +}; + +fn load_spec(id: &str) -> std::result::Result, String> { + Ok(match id { + "dev" => Box::new(chain_spec::development_config()), + "template-rococo" => Box::new(chain_spec::local_testnet_config()), + "" | "local" => Box::new(chain_spec::local_testnet_config()), + path => Box::new(chain_spec::ChainSpec::from_json_file(std::path::PathBuf::from(path))?), + }) +} + +impl SubstrateCli for Cli { + fn impl_name() -> String { + "Subzero Collator".into() + } + + fn impl_version() -> String { + env!("SUBSTRATE_CLI_IMPL_VERSION").into() + } + + fn description() -> String { + "Subzero Collator\n\nThe command-line arguments provided first will be \ + passed to the parachain node, while the arguments provided after -- will be passed \ + to the relay chain node.\n\n\ + parachain-collator -- " + .into() + } + + fn author() -> String { + env!("CARGO_PKG_AUTHORS").into() + } + + fn support_url() -> String { + "https://github.com/playzero/zero-network/issues/new".into() + } + + fn copyright_start_year() -> i32 { + 2022 + } + + fn load_spec(&self, id: &str) -> std::result::Result, String> { + load_spec(id) + } + + fn native_runtime_version(_: &Box) -> &'static RuntimeVersion { + ¶chain_subzero_runtime_live::VERSION + } +} + +impl SubstrateCli for RelayChainCli { + fn impl_name() -> String { + "Subzero Collator".into() + } + + fn impl_version() -> String { + env!("SUBSTRATE_CLI_IMPL_VERSION").into() + } + + fn description() -> String { + "Subzero Collator\n\nThe command-line arguments provided first will be \ + passed to the parachain node, while the arguments provided after -- will be passed \ + to the relay chain node.\n\n\ + parachain-collator -- " + .into() + } + + fn author() -> String { + env!("CARGO_PKG_AUTHORS").into() + } + + fn support_url() -> String { + "https://github.com/playzero/zero-network/issues/new".into() + } + + fn copyright_start_year() -> i32 { + 2022 + } + + fn load_spec(&self, id: &str) -> std::result::Result, String> { + polkadot_cli::Cli::from_iter([RelayChainCli::executable_name()].iter()).load_spec(id) + } + + fn native_runtime_version(chain_spec: &Box) -> &'static RuntimeVersion { + polkadot_cli::Cli::native_runtime_version(chain_spec) + } +} + +macro_rules! construct_async_run { + (|$components:ident, $cli:ident, $cmd:ident, $config:ident| $( $code:tt )* ) => {{ + let runner = $cli.create_runner($cmd)?; + runner.async_run(|$config| { + let $components = new_partial::< + RuntimeApi, + SubzeroRuntimeExecutor, + _ + >( + &$config, + crate::service::parachain_build_import_queue, + )?; + let task_manager = $components.task_manager; + { $( $code )* }.map(|v| (v, task_manager)) + }) + }} +} + +/// Parse command line arguments into service configuration. +pub fn run() -> Result<()> { + let cli = Cli::from_args(); + + match &cli.subcommand { + Some(Subcommand::BuildSpec(cmd)) => { + let runner = cli.create_runner(cmd)?; + runner.sync_run(|config| cmd.run(config.chain_spec, config.network)) + }, + Some(Subcommand::CheckBlock(cmd)) => { + construct_async_run!(|components, cli, cmd, config| { + Ok(cmd.run(components.client, components.import_queue)) + }) + }, + Some(Subcommand::ExportBlocks(cmd)) => { + construct_async_run!(|components, cli, cmd, config| { + Ok(cmd.run(components.client, config.database)) + }) + }, + Some(Subcommand::ExportState(cmd)) => { + construct_async_run!(|components, cli, cmd, config| { + Ok(cmd.run(components.client, config.chain_spec)) + }) + }, + Some(Subcommand::ImportBlocks(cmd)) => { + construct_async_run!(|components, cli, cmd, config| { + Ok(cmd.run(components.client, components.import_queue)) + }) + }, + Some(Subcommand::Revert(cmd)) => { + construct_async_run!(|components, cli, cmd, config| { + Ok(cmd.run(components.client, components.backend, None)) + }) + }, + Some(Subcommand::PurgeChain(cmd)) => { + let runner = cli.create_runner(cmd)?; + + runner.sync_run(|config| { + let polkadot_cli = RelayChainCli::new( + &config, + [RelayChainCli::executable_name()].iter().chain(cli.relay_chain_args.iter()), + ); + + let polkadot_config = SubstrateCli::create_configuration( + &polkadot_cli, + &polkadot_cli, + config.tokio_handle.clone(), + ) + .map_err(|err| format!("Relay chain argument error: {}", err))?; + + cmd.run(config, polkadot_config) + }) + }, + Some(Subcommand::ExportGenesisState(cmd)) => { + let runner = cli.create_runner(cmd)?; + runner.sync_run(|_config| { + let spec = cli.load_spec(&cmd.shared_params.chain.clone().unwrap_or_default())?; + let state_version = Cli::native_runtime_version(&spec).state_version(); + cmd.run::(&*spec, state_version) + }) + }, + Some(Subcommand::ExportGenesisWasm(cmd)) => { + let runner = cli.create_runner(cmd)?; + runner.sync_run(|_config| { + let spec = cli.load_spec(&cmd.shared_params.chain.clone().unwrap_or_default())?; + cmd.run(&*spec) + }) + }, + Some(Subcommand::Benchmark(cmd)) => { + let runner = cli.create_runner(cmd)?; + // Switch on the concrete benchmark sub-command- + match cmd { + BenchmarkCmd::Pallet(cmd) => + if cfg!(feature = "runtime-benchmarks") { + runner.sync_run(|config| cmd.run::(config)) + } else { + Err("Benchmarking wasn't enabled when building the node. \ + You can enable it with `--features runtime-benchmarks`." + .into()) + }, + BenchmarkCmd::Block(cmd) => runner.sync_run(|config| { + let partials = new_partial::( + &config, + crate::service::parachain_build_import_queue, + )?; + cmd.run(partials.client) + }), + BenchmarkCmd::Storage(cmd) => runner.sync_run(|config| { + let partials = new_partial::( + &config, + crate::service::parachain_build_import_queue, + )?; + let db = partials.backend.expose_db(); + let storage = partials.backend.expose_storage(); + + cmd.run(config, partials.client.clone(), db, storage) + }), + BenchmarkCmd::Overhead(_) => Err("Unsupported benchmarking command".into()), + BenchmarkCmd::Machine(cmd) => + runner.sync_run(|config| cmd.run(&config, SUBSTRATE_REFERENCE_HARDWARE.clone())), + } + }, + Some(Subcommand::TryRuntime(cmd)) => { + if cfg!(feature = "try-runtime") { + let runner = cli.create_runner(cmd)?; + + // grab the task manager. + let registry = &runner.config().prometheus_config.as_ref().map(|cfg| &cfg.registry); + let task_manager = + TaskManager::new(runner.config().tokio_handle.clone(), *registry) + .map_err(|e| format!("Error: {:?}", e))?; + + runner.async_run(|config| { + Ok((cmd.run::(config), task_manager)) + }) + } else { + Err("Try-runtime must be enabled by `--features try-runtime`.".into()) + } + }, + None => { + let runner = cli.create_runner(&cli.run.normalize())?; + let collator_options = cli.run.collator_options(); + + runner.run_node_until_exit(|config| async move { + let hwbench = if !cli.no_hardware_benchmarks { + config.database.path().map(|database_path| { + let _ = std::fs::create_dir_all(&database_path); + sc_sysinfo::gather_hwbench(Some(database_path)) + }) + } else { + None + }; + + let para_id = chain_spec::Extensions::try_get(&*config.chain_spec) + .map(|e| e.para_id) + .ok_or_else(|| "Could not find parachain ID in chain-spec.")?; + + let polkadot_cli = RelayChainCli::new( + &config, + [RelayChainCli::executable_name()].iter().chain(cli.relay_chain_args.iter()), + ); + + let id = ParaId::from(para_id); + + let parachain_account = + AccountIdConversion::::into_account_truncating(&id); + + let state_version = Cli::native_runtime_version(&config.chain_spec).state_version(); + let block: Block = generate_genesis_block(&*config.chain_spec, state_version) + .map_err(|e| format!("{:?}", e))?; + let genesis_state = format!("0x{:?}", HexDisplay::from(&block.header().encode())); + + let tokio_handle = config.tokio_handle.clone(); + let polkadot_config = + SubstrateCli::create_configuration(&polkadot_cli, &polkadot_cli, tokio_handle) + .map_err(|err| format!("Relay chain argument error: {}", err))?; + + info!("Parachain id: {:?}", id); + info!("Parachain Account: {}", parachain_account); + info!("Parachain genesis state: {}", genesis_state); + info!("Is collating: {}", if config.role.is_authority() { "yes" } else { "no" }); + + crate::service::start_parachain_node( + config, + polkadot_config, + collator_options, + id, + hwbench, + ) + .await + .map(|r| r.0) + .map_err(Into::into) + }) + }, + } +} + +impl DefaultConfigurationValues for RelayChainCli { + fn p2p_listen_port() -> u16 { + 30334 + } + + fn rpc_ws_listen_port() -> u16 { + 9945 + } + + fn rpc_http_listen_port() -> u16 { + 9934 + } + + fn prometheus_listen_port() -> u16 { + 9616 + } +} + +impl CliConfiguration for RelayChainCli { + fn shared_params(&self) -> &SharedParams { + self.base.base.shared_params() + } + + fn import_params(&self) -> Option<&ImportParams> { + self.base.base.import_params() + } + + fn network_params(&self) -> Option<&NetworkParams> { + self.base.base.network_params() + } + + fn keystore_params(&self) -> Option<&KeystoreParams> { + self.base.base.keystore_params() + } + + fn base_path(&self) -> Result> { + Ok(self + .shared_params() + .base_path() + .or_else(|| self.base_path.clone().map(Into::into))) + } + + fn rpc_http(&self, default_listen_port: u16) -> Result> { + self.base.base.rpc_http(default_listen_port) + } + + fn rpc_ipc(&self) -> Result> { + self.base.base.rpc_ipc() + } + + fn rpc_ws(&self, default_listen_port: u16) -> Result> { + self.base.base.rpc_ws(default_listen_port) + } + + fn prometheus_config( + &self, + default_listen_port: u16, + chain_spec: &Box, + ) -> Result> { + self.base.base.prometheus_config(default_listen_port, chain_spec) + } + + fn init( + &self, + _support_url: &String, + _impl_version: &String, + _logger_hook: F, + _config: &sc_service::Configuration, + ) -> Result<()> + where + F: FnOnce(&mut sc_cli::LoggerBuilder, &sc_service::Configuration), + { + unreachable!("PolkadotCli is never initialized; qed"); + } + + fn chain_id(&self, is_dev: bool) -> Result { + let chain_id = self.base.base.chain_id(is_dev)?; + + Ok(if chain_id.is_empty() { self.chain_id.clone().unwrap_or_default() } else { chain_id }) + } + + fn role(&self, is_dev: bool) -> Result { + self.base.base.role(is_dev) + } + + fn transaction_pool(&self) -> Result { + self.base.base.transaction_pool() + } + + fn state_cache_child_ratio(&self) -> Result> { + self.base.base.state_cache_child_ratio() + } + + fn rpc_methods(&self) -> Result { + self.base.base.rpc_methods() + } + + fn rpc_ws_max_connections(&self) -> Result> { + self.base.base.rpc_ws_max_connections() + } + + fn rpc_cors(&self, is_dev: bool) -> Result>> { + self.base.base.rpc_cors(is_dev) + } + + fn default_heap_pages(&self) -> Result> { + self.base.base.default_heap_pages() + } + + fn force_authoring(&self) -> Result { + self.base.base.force_authoring() + } + + fn disable_grandpa(&self) -> Result { + self.base.base.disable_grandpa() + } + + fn max_runtime_instances(&self) -> Result> { + self.base.base.max_runtime_instances() + } + + fn announce_block(&self) -> Result { + self.base.base.announce_block() + } + + fn telemetry_endpoints( + &self, + chain_spec: &Box, + ) -> Result> { + self.base.base.telemetry_endpoints(chain_spec) + } + + fn node_name(&self) -> Result { + self.base.base.node_name() + } +} diff --git a/bin/zero-parachain-live/node/src/main.rs b/bin/zero-parachain-live/node/src/main.rs new file mode 100644 index 0000000000..ab6d14e34f --- /dev/null +++ b/bin/zero-parachain-live/node/src/main.rs @@ -0,0 +1,14 @@ +//! Subzero Parachain Node CLI + +#![warn(missing_docs)] + +mod chain_spec; +#[macro_use] +mod service; +mod cli; +mod command; +mod rpc; + +fn main() -> sc_cli::Result<()> { + command::run() +} diff --git a/bin/zero-parachain-live/node/src/rpc.rs b/bin/zero-parachain-live/node/src/rpc.rs new file mode 100644 index 0000000000..2891ac84c7 --- /dev/null +++ b/bin/zero-parachain-live/node/src/rpc.rs @@ -0,0 +1,58 @@ +//! A collection of node-specific RPC methods. +//! Substrate provides the `sc-rpc` crate, which defines the core RPC layer +//! used by Substrate nodes. This file extends those RPC definitions with +//! capabilities that are specific to this project's runtime configuration. + +#![warn(missing_docs)] + +use std::sync::Arc; + +use parachain_subzero_runtime_live::{opaque::Block, AccountId, Balance, Index as Nonce}; + +use sc_client_api::AuxStore; +pub use sc_rpc::{DenyUnsafe, SubscriptionTaskExecutor}; +use sc_transaction_pool_api::TransactionPool; +use sp_api::ProvideRuntimeApi; +use sp_block_builder::BlockBuilder; +use sp_blockchain::{Error as BlockChainError, HeaderBackend, HeaderMetadata}; + +/// A type representing all RPC extensions. +pub type RpcExtension = jsonrpsee::RpcModule<()>; + +/// Full client dependencies +pub struct FullDeps { + /// The client instance to use. + pub client: Arc, + /// Transaction pool instance. + pub pool: Arc

, + /// Whether to deny unsafe calls + pub deny_unsafe: DenyUnsafe, +} + +/// Instantiate all RPC extensions. +pub fn create_full( + deps: FullDeps, +) -> Result> +where + C: ProvideRuntimeApi + + HeaderBackend + + AuxStore + + HeaderMetadata + + Send + + Sync + + 'static, + C::Api: pallet_transaction_payment_rpc::TransactionPaymentRuntimeApi, + C::Api: substrate_frame_rpc_system::AccountNonceApi, + C::Api: BlockBuilder, + P: TransactionPool + Sync + Send + 'static, +{ + use pallet_transaction_payment_rpc::{TransactionPayment, TransactionPaymentApiServer}; + use substrate_frame_rpc_system::{System, SystemApiServer}; + + let mut module = RpcExtension::new(()); + let FullDeps { client, pool, deny_unsafe } = deps; + + module.merge(System::new(client.clone(), pool.clone(), deny_unsafe).into_rpc())?; + module.merge(TransactionPayment::new(client.clone()).into_rpc())?; + Ok(module) +} diff --git a/bin/zero-parachain-live/node/src/service.rs b/bin/zero-parachain-live/node/src/service.rs new file mode 100644 index 0000000000..7e641d619e --- /dev/null +++ b/bin/zero-parachain-live/node/src/service.rs @@ -0,0 +1,535 @@ +//! Service and ServiceFactory implementation. Specialized wrapper over substrate service. + +// std +use std::{sync::Arc, time::Duration}; + +// rpc +use jsonrpsee::RpcModule; + +use cumulus_client_cli::CollatorOptions; +// Local Runtime Types +use parachain_subzero_runtime_live::{ + opaque::Block, AccountId, Balance, Hash, Index as Nonce, RuntimeApi, +}; + +// Cumulus Imports +use cumulus_client_consensus_aura::{AuraConsensus, BuildAuraConsensusParams, SlotProportion}; +use cumulus_client_consensus_common::ParachainConsensus; +use cumulus_client_network::BlockAnnounceValidator; +use cumulus_client_service::{ + prepare_node_config, start_collator, start_full_node, StartCollatorParams, StartFullNodeParams, +}; +use cumulus_primitives_core::ParaId; +use cumulus_relay_chain_inprocess_interface::build_inprocess_relay_chain; +use cumulus_relay_chain_interface::{RelayChainError, RelayChainInterface, RelayChainResult}; +use cumulus_relay_chain_rpc_interface::RelayChainRPCInterface; + +// Substrate Imports +use sc_client_api::ExecutorProvider; +use sc_executor::NativeElseWasmExecutor; +use sc_network::NetworkService; +use sc_service::{Configuration, PartialComponents, Role, TFullBackend, TFullClient, TaskManager}; +use sc_telemetry::{Telemetry, TelemetryHandle, TelemetryWorker, TelemetryWorkerHandle}; +use sp_api::ConstructRuntimeApi; +use sp_keystore::SyncCryptoStorePtr; +use sp_runtime::traits::BlakeTwo256; +use substrate_prometheus_endpoint::Registry; + +use polkadot_service::CollatorPair; + +/// Native executor instance. +pub struct SubzeroRuntimeExecutor; + +impl sc_executor::NativeExecutionDispatch for SubzeroRuntimeExecutor { + type ExtendHostFunctions = frame_benchmarking::benchmarking::HostFunctions; + + fn dispatch(method: &str, data: &[u8]) -> Option> { + parachain_subzero_runtime_live::api::dispatch(method, data) + } + + fn native_version() -> sc_executor::NativeVersion { + parachain_subzero_runtime_live::native_version() + } +} + +/// Starts a `ServiceBuilder` for a full service. +/// +/// Use this macro if you don't actually need the full service, but just the builder in order to +/// be able to perform chain operations. +#[allow(clippy::type_complexity)] +pub fn new_partial( + config: &Configuration, + build_import_queue: BIQ, +) -> Result< + PartialComponents< + TFullClient>, + TFullBackend, + (), + sc_consensus::DefaultImportQueue< + Block, + TFullClient>, + >, + sc_transaction_pool::FullPool< + Block, + TFullClient>, + >, + (Option, Option), + >, + sc_service::Error, +> +where + RuntimeApi: ConstructRuntimeApi>> + + Send + + Sync + + 'static, + RuntimeApi::RuntimeApi: sp_transaction_pool::runtime_api::TaggedTransactionQueue + + sp_api::Metadata + + sp_session::SessionKeys + + sp_api::ApiExt< + Block, + StateBackend = sc_client_api::StateBackendFor, Block>, + > + sp_offchain::OffchainWorkerApi + + sp_block_builder::BlockBuilder, + sc_client_api::StateBackendFor, Block>: sp_api::StateBackend, + Executor: sc_executor::NativeExecutionDispatch + 'static, + BIQ: FnOnce( + Arc>>, + &Configuration, + Option, + &TaskManager, + ) -> Result< + sc_consensus::DefaultImportQueue< + Block, + TFullClient>, + >, + sc_service::Error, + >, +{ + let telemetry = config + .telemetry_endpoints + .clone() + .filter(|x| !x.is_empty()) + .map(|endpoints| -> Result<_, sc_telemetry::Error> { + let worker = TelemetryWorker::new(16)?; + let telemetry = worker.handle().new_telemetry(endpoints); + Ok((worker, telemetry)) + }) + .transpose()?; + + let executor = sc_executor::NativeElseWasmExecutor::::new( + config.wasm_method, + config.default_heap_pages, + config.max_runtime_instances, + config.runtime_cache_size, + ); + + let (client, backend, keystore_container, task_manager) = + sc_service::new_full_parts::( + config, + telemetry.as_ref().map(|(_, telemetry)| telemetry.handle()), + executor, + )?; + let client = Arc::new(client); + + let telemetry_worker_handle = telemetry.as_ref().map(|(worker, _)| worker.handle()); + + let telemetry = telemetry.map(|(worker, telemetry)| { + task_manager.spawn_handle().spawn("telemetry", None, worker.run()); + telemetry + }); + + let transaction_pool = sc_transaction_pool::BasicPool::new_full( + config.transaction_pool.clone(), + config.role.is_authority().into(), + config.prometheus_registry(), + task_manager.spawn_essential_handle(), + client.clone(), + ); + + let import_queue = build_import_queue( + client.clone(), + config, + telemetry.as_ref().map(|telemetry| telemetry.handle()), + &task_manager, + )?; + + let params = PartialComponents { + backend, + client, + import_queue, + keystore_container, + task_manager, + transaction_pool, + select_chain: (), + other: (telemetry, telemetry_worker_handle), + }; + + Ok(params) +} + +async fn build_relay_chain_interface( + polkadot_config: Configuration, + parachain_config: &Configuration, + telemetry_worker_handle: Option, + task_manager: &mut TaskManager, + collator_options: CollatorOptions, + hwbench: Option, +) -> RelayChainResult<(Arc<(dyn RelayChainInterface + 'static)>, Option)> { + match collator_options.relay_chain_rpc_url { + Some(relay_chain_url) => + Ok((Arc::new(RelayChainRPCInterface::new(relay_chain_url).await?) as Arc<_>, None)), + None => build_inprocess_relay_chain( + polkadot_config, + parachain_config, + telemetry_worker_handle, + task_manager, + hwbench, + ), + } +} + +/// Start a node with the given parachain `Configuration` and relay chain `Configuration`. +/// +/// This is the actual implementation that is abstract over the executor and the runtime api. +#[sc_tracing::logging::prefix_logs_with("Parachain")] +async fn start_node_impl( + parachain_config: Configuration, + polkadot_config: Configuration, + collator_options: CollatorOptions, + id: ParaId, + _rpc_ext_builder: RB, + build_import_queue: BIQ, + build_consensus: BIC, + hwbench: Option, +) -> sc_service::error::Result<( + TaskManager, + Arc>>, +)> +where + RuntimeApi: ConstructRuntimeApi>> + + Send + + Sync + + 'static, + RuntimeApi::RuntimeApi: sp_transaction_pool::runtime_api::TaggedTransactionQueue + + sp_api::Metadata + + sp_session::SessionKeys + + sp_api::ApiExt< + Block, + StateBackend = sc_client_api::StateBackendFor, Block>, + > + sp_offchain::OffchainWorkerApi + + sp_block_builder::BlockBuilder + + cumulus_primitives_core::CollectCollationInfo + + pallet_transaction_payment_rpc::TransactionPaymentRuntimeApi + + substrate_frame_rpc_system::AccountNonceApi, + sc_client_api::StateBackendFor, Block>: sp_api::StateBackend, + Executor: sc_executor::NativeExecutionDispatch + 'static, + RB: Fn( + Arc>, + ) -> Result, sc_service::Error> + + Send + + 'static, + BIQ: FnOnce( + Arc>>, + &Configuration, + Option, + &TaskManager, + ) -> Result< + sc_consensus::DefaultImportQueue< + Block, + TFullClient>, + >, + sc_service::Error, + > + 'static, + BIC: FnOnce( + Arc>>, + Option<&Registry>, + Option, + &TaskManager, + Arc, + Arc< + sc_transaction_pool::FullPool< + Block, + TFullClient>, + >, + >, + Arc>, + SyncCryptoStorePtr, + bool, + ) -> Result>, sc_service::Error>, +{ + if matches!(parachain_config.role, Role::Light) { + return Err("Light client not supported!".into()) + } + + let parachain_config = prepare_node_config(parachain_config); + + let params = new_partial::(¶chain_config, build_import_queue)?; + let (mut telemetry, telemetry_worker_handle) = params.other; + + let client = params.client.clone(); + let backend = params.backend.clone(); + let mut task_manager = params.task_manager; + + let (relay_chain_interface, collator_key) = build_relay_chain_interface( + polkadot_config, + ¶chain_config, + telemetry_worker_handle, + &mut task_manager, + collator_options.clone(), + hwbench.clone(), + ) + .await + .map_err(|e| match e { + RelayChainError::ServiceError(polkadot_service::Error::Sub(x)) => x, + s => s.to_string().into(), + })?; + + let block_announce_validator = BlockAnnounceValidator::new(relay_chain_interface.clone(), id); + + let force_authoring = parachain_config.force_authoring; + let validator = parachain_config.role.is_authority(); + let prometheus_registry = parachain_config.prometheus_registry().cloned(); + let transaction_pool = params.transaction_pool.clone(); + let import_queue = cumulus_client_service::SharedImportQueue::new(params.import_queue); + let (network, system_rpc_tx, start_network) = + sc_service::build_network(sc_service::BuildNetworkParams { + config: ¶chain_config, + client: client.clone(), + transaction_pool: transaction_pool.clone(), + spawn_handle: task_manager.spawn_handle(), + import_queue: import_queue.clone(), + block_announce_validator_builder: Some(Box::new(|_| { + Box::new(block_announce_validator) + })), + warp_sync: None, + })?; + + let rpc_builder = { + let client = client.clone(); + let transaction_pool = transaction_pool.clone(); + + Box::new(move |deny_unsafe, _| { + let deps = crate::rpc::FullDeps { + client: client.clone(), + pool: transaction_pool.clone(), + deny_unsafe, + }; + + crate::rpc::create_full(deps).map_err(Into::into) + }) + }; + + sc_service::spawn_tasks(sc_service::SpawnTasksParams { + rpc_builder, + client: client.clone(), + transaction_pool: transaction_pool.clone(), + task_manager: &mut task_manager, + config: parachain_config, + keystore: params.keystore_container.sync_keystore(), + backend: backend.clone(), + network: network.clone(), + system_rpc_tx, + telemetry: telemetry.as_mut(), + })?; + + if let Some(hwbench) = hwbench { + sc_sysinfo::print_hwbench(&hwbench); + + if let Some(ref mut telemetry) = telemetry { + let telemetry_handle = telemetry.handle(); + task_manager.spawn_handle().spawn( + "telemetry_hwbench", + None, + sc_sysinfo::initialize_hwbench_telemetry(telemetry_handle, hwbench), + ); + } + } + + let announce_block = { + let network = network.clone(); + Arc::new(move |hash, data| network.announce_block(hash, data)) + }; + + let relay_chain_slot_duration = Duration::from_secs(6); + + if validator { + let parachain_consensus = build_consensus( + client.clone(), + prometheus_registry.as_ref(), + telemetry.as_ref().map(|t| t.handle()), + &task_manager, + relay_chain_interface.clone(), + transaction_pool, + network, + params.keystore_container.sync_keystore(), + force_authoring, + )?; + + let spawner = task_manager.spawn_handle(); + + let params = StartCollatorParams { + para_id: id, + block_status: client.clone(), + announce_block, + client: client.clone(), + task_manager: &mut task_manager, + relay_chain_interface, + spawner, + parachain_consensus, + import_queue, + collator_key: collator_key.expect("Command line arguments do not allow this. qed"), + relay_chain_slot_duration, + }; + + start_collator(params).await?; + } else { + let params = StartFullNodeParams { + client: client.clone(), + announce_block, + task_manager: &mut task_manager, + para_id: id, + relay_chain_interface, + relay_chain_slot_duration, + import_queue, + collator_options, + }; + + start_full_node(params)?; + } + + start_network.start_network(); + + Ok((task_manager, client)) +} + +/// Build the import queue for the parachain runtime. +#[allow(clippy::type_complexity)] +pub fn parachain_build_import_queue( + client: Arc>>, + config: &Configuration, + telemetry: Option, + task_manager: &TaskManager, +) -> Result< + sc_consensus::DefaultImportQueue< + Block, + TFullClient>, + >, + sc_service::Error, +> { + let slot_duration = cumulus_client_consensus_aura::slot_duration(&*client)?; + + cumulus_client_consensus_aura::import_queue::< + sp_consensus_aura::sr25519::AuthorityPair, + _, + _, + _, + _, + _, + _, + >(cumulus_client_consensus_aura::ImportQueueParams { + block_import: client.clone(), + client: client.clone(), + create_inherent_data_providers: move |_, _| async move { + let time = sp_timestamp::InherentDataProvider::from_system_time(); + + let slot = + sp_consensus_aura::inherents::InherentDataProvider::from_timestamp_and_slot_duration( + *time, + slot_duration, + ); + + Ok((time, slot)) + }, + registry: config.prometheus_registry(), + can_author_with: sp_consensus::CanAuthorWithNativeVersion::new(client.executor().clone()), + spawner: &task_manager.spawn_essential_handle(), + telemetry, + }) + .map_err(Into::into) +} + +/// Start a parachain node. +pub async fn start_parachain_node( + parachain_config: Configuration, + polkadot_config: Configuration, + collator_options: CollatorOptions, + id: ParaId, + hwbench: Option, +) -> sc_service::error::Result<( + TaskManager, + Arc>>, +)> { + start_node_impl::( + parachain_config, + polkadot_config, + collator_options, + id, + |_| Ok(RpcModule::new(())), + parachain_build_import_queue, + |client, + prometheus_registry, + telemetry, + task_manager, + relay_chain_interface, + transaction_pool, + sync_oracle, + keystore, + force_authoring| { + let slot_duration = cumulus_client_consensus_aura::slot_duration(&*client)?; + + let proposer_factory = sc_basic_authorship::ProposerFactory::with_proof_recording( + task_manager.spawn_handle(), + client.clone(), + transaction_pool, + prometheus_registry, + telemetry.clone(), + ); + + Ok(AuraConsensus::build::( + BuildAuraConsensusParams { + proposer_factory, + create_inherent_data_providers: move |_, (relay_parent, validation_data)| { + let relay_chain_interface = relay_chain_interface.clone(); + async move { + let parachain_inherent = + cumulus_primitives_parachain_inherent::ParachainInherentData::create_at( + relay_parent, + &relay_chain_interface, + &validation_data, + id, + ).await; + let time = sp_timestamp::InherentDataProvider::from_system_time(); + + let slot = + sp_consensus_aura::inherents::InherentDataProvider::from_timestamp_and_slot_duration( + *time, + slot_duration, + ); + + let parachain_inherent = parachain_inherent.ok_or_else(|| { + Box::::from( + "Failed to create parachain inherent", + ) + })?; + Ok((time, slot, parachain_inherent)) + } + }, + block_import: client.clone(), + para_client: client, + backoff_authoring_blocks: Option::<()>::None, + sync_oracle, + keystore, + force_authoring, + slot_duration, + // We got around 500ms for proposing + block_proposal_slot_portion: SlotProportion::new(1f32 / 24f32), + // And a maximum of 750ms if slots are skipped + max_block_proposal_slot_portion: Some(SlotProportion::new(1f32 / 16f32)), + telemetry, + }, + )) + }, + hwbench, + ) + .await +} diff --git a/bin/zero-parachain-live/runtime/Cargo.toml b/bin/zero-parachain-live/runtime/Cargo.toml new file mode 100644 index 0000000000..c8da4d73c4 --- /dev/null +++ b/bin/zero-parachain-live/runtime/Cargo.toml @@ -0,0 +1,175 @@ +[package] +name = "parachain-subzero-runtime-live" +version = "0.1.0" +authors = ["ZERO "] +license = "Apache-2.0" +homepage = "https://zero.io" +repository = "https://github.com/playzero/zero-network/" +edition = "2021" + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[build-dependencies] +substrate-wasm-builder = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.25" } + +[dependencies] +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +hex-literal = { version = "0.3.4", optional = true } +log = { version = "0.4.17", default-features = false } +scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } +serde = { version = "1.0.137", optional = true, features = ["derive"] } +smallvec = "1.6.1" + +# Substrate +frame-benchmarking = { git = "https://github.com/paritytech/substrate", default-features = false, optional = true, branch = "polkadot-v0.9.25" } +frame-executive = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.25" } +frame-support = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.25" } +frame-system = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.25" } +frame-system-benchmarking = { git = "https://github.com/paritytech/substrate", default-features = false, optional = true, branch = "polkadot-v0.9.25" } +frame-system-rpc-runtime-api = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.25" } +frame-try-runtime = { git = "https://github.com/paritytech/substrate", default-features = false, optional = true, branch = "polkadot-v0.9.25" } +pallet-aura = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.25" } +pallet-authorship = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.25" } +pallet-balances = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.25" } +pallet-bounties = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.25" } +pallet-child-bounties = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.25" } +pallet-collective = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.25" } +pallet-identity = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.25" } +pallet-session = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.25" } +pallet-sudo = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.25" } +pallet-timestamp = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.25" } +pallet-transaction-payment = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.25" } +pallet-transaction-payment-rpc-runtime-api = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.25" } +pallet-treasury = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.25" } +sp-api = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.25" } +sp-block-builder = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.25" } +sp-consensus-aura = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.25" } +sp-core = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.25" } +sp-inherents = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.25" } +sp-io = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.25" } +sp-offchain = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.25" } +sp-runtime = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.25" } +sp-session = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.25" } +sp-std = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.25" } +sp-transaction-pool = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.25" } +sp-version = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.25" } + +# Polkadot +pallet-xcm = { git = "https://github.com/paritytech/polkadot", default-features = false, branch = "release-v0.9.25" } +polkadot-parachain = { git = "https://github.com/paritytech/polkadot", default-features = false, branch = "release-v0.9.25" } +polkadot-runtime-common = { git = "https://github.com/paritytech/polkadot", default-features = false, branch = "release-v0.9.25" } +xcm = { git = "https://github.com/paritytech/polkadot", default-features = false, branch = "release-v0.9.25" } +xcm-builder = { git = "https://github.com/paritytech/polkadot", default-features = false, branch = "release-v0.9.25" } +xcm-executor = { git = "https://github.com/paritytech/polkadot", default-features = false, branch = "release-v0.9.25" } + +# Cumulus +cumulus-pallet-aura-ext = { git = "https://github.com/paritytech/cumulus", default-features = false, branch = "polkadot-v0.9.25" } +cumulus-pallet-dmp-queue = { git = "https://github.com/paritytech/cumulus", default-features = false, branch = "polkadot-v0.9.25" } +cumulus-pallet-parachain-system = { git = "https://github.com/paritytech/cumulus", default-features = false, branch = "polkadot-v0.9.25" } +cumulus-pallet-session-benchmarking = { git = "https://github.com/paritytech/cumulus", default-features = false, branch = "polkadot-v0.9.25", version = "3.0.0"} +cumulus-pallet-xcm = { git = "https://github.com/paritytech/cumulus", default-features = false, branch = "polkadot-v0.9.25" } +cumulus-pallet-xcmp-queue = { git = "https://github.com/paritytech/cumulus", default-features = false, branch = "polkadot-v0.9.25" } +cumulus-primitives-core = { git = "https://github.com/paritytech/cumulus", default-features = false, branch = "polkadot-v0.9.25" } +cumulus-primitives-timestamp = { git = "https://github.com/paritytech/cumulus", default-features = false, branch = "polkadot-v0.9.25" } +cumulus-primitives-utility = { git = "https://github.com/paritytech/cumulus", default-features = false, branch = "polkadot-v0.9.25" } +pallet-collator-selection = { git = "https://github.com/paritytech/cumulus", default-features = false, branch = "polkadot-v0.9.25" } +parachain-info = { git = "https://github.com/paritytech/cumulus", default-features = false, branch = "polkadot-v0.9.25" } + +primitives = { version = "2.0.0", package = "zero-primitives", default-features = false, path = "../../../primitives" } + +# ORML +orml-currencies = { path = "../../../orml/currencies", default-features = false } +orml-tokens = { path = "../../../orml/tokens", default-features = false } +orml-traits = { path = "../../../orml/traits", default-features = false } +orml-unknown-tokens = { path = "../../../orml/unknown-tokens", default-features = false } +orml-xcm = { path = "../../../orml/xcm", default-features = false } +orml-xcm-support = { path = "../../../orml/xcm-support", default-features = false } +orml-xtokens = { path = "../../../orml/xtokens", default-features = false } + +[features] +default = [ + "std", +] +std = [ + "codec/std", + "log/std", + "scale-info/std", + "serde", + "cumulus-pallet-aura-ext/std", + "cumulus-pallet-dmp-queue/std", + "cumulus-pallet-parachain-system/std", + "cumulus-pallet-xcm/std", + "cumulus-pallet-xcmp-queue/std", + "cumulus-primitives-core/std", + "cumulus-primitives-timestamp/std", + "cumulus-primitives-utility/std", + "frame-executive/std", + "frame-support/std", + "frame-system-rpc-runtime-api/std", + "frame-system/std", + "pallet-aura/std", + "pallet-authorship/std", + "pallet-balances/std", + "pallet-collator-selection/std", + "pallet-session/std", + "pallet-bounties/std", + "pallet-child-bounties/std", + "pallet-collective/std", + "pallet-identity/std", + "pallet-treasury/std", + "pallet-sudo/std", + "pallet-timestamp/std", + "pallet-transaction-payment-rpc-runtime-api/std", + "pallet-transaction-payment/std", + "pallet-xcm/std", + "parachain-info/std", + "polkadot-parachain/std", + "polkadot-runtime-common/std", + "sp-api/std", + "sp-block-builder/std", + "sp-consensus-aura/std", + "sp-core/std", + "sp-inherents/std", + "sp-io/std", + "sp-offchain/std", + "sp-runtime/std", + "sp-session/std", + "sp-std/std", + "sp-transaction-pool/std", + "sp-version/std", + "xcm-builder/std", + "xcm-executor/std", + "xcm/std", + + "primitives/std", + + "orml-currencies/std", + "orml-tokens/std", + "orml-traits/std", + "orml-unknown-tokens/std", + "orml-xcm-support/std", + "orml-xcm/std", + "orml-xtokens/std", +] + +runtime-benchmarks = [ + "hex-literal", + "frame-benchmarking/runtime-benchmarks", + "frame-support/runtime-benchmarks", + "frame-system-benchmarking", + "frame-system/runtime-benchmarks", + "pallet-balances/runtime-benchmarks", + "pallet-collator-selection/runtime-benchmarks", + "pallet-timestamp/runtime-benchmarks", + "pallet-xcm/runtime-benchmarks", + "sp-runtime/runtime-benchmarks", + "xcm-builder/runtime-benchmarks", + "cumulus-pallet-session-benchmarking/runtime-benchmarks", + "cumulus-pallet-xcmp-queue/runtime-benchmarks", +] + +try-runtime = [ + "frame-executive/try-runtime", + "frame-try-runtime", +] diff --git a/bin/zero-parachain-live/runtime/build.rs b/bin/zero-parachain-live/runtime/build.rs new file mode 100644 index 0000000000..9b53d2457d --- /dev/null +++ b/bin/zero-parachain-live/runtime/build.rs @@ -0,0 +1,9 @@ +use substrate_wasm_builder::WasmBuilder; + +fn main() { + WasmBuilder::new() + .with_current_project() + .export_heap_base() + .import_memory() + .build() +} diff --git a/bin/zero-parachain-live/runtime/src/lib.rs b/bin/zero-parachain-live/runtime/src/lib.rs new file mode 100644 index 0000000000..070f40d04f --- /dev/null +++ b/bin/zero-parachain-live/runtime/src/lib.rs @@ -0,0 +1,939 @@ +#![cfg_attr(not(feature = "std"), no_std)] +// `construct_runtime!` does a lot of recursion and requires us to increase the limit to 256. +#![recursion_limit = "256"] + +// Make the WASM binary available. +#[cfg(feature = "std")] +include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); + +mod weights; +pub mod xcm_config; + +use cumulus_pallet_parachain_system::RelayNumberStrictlyIncreases; +use smallvec::smallvec; +use sp_api::impl_runtime_apis; +use sp_core::{crypto::KeyTypeId, OpaqueMetadata}; +use sp_runtime::{ + create_runtime_str, generic, impl_opaque_keys, + traits::{AccountIdConversion, AccountIdLookup, BlakeTwo256, Block as BlockT, IdentifyAccount, Verify}, + transaction_validity::{TransactionSource, TransactionValidity}, + ApplyExtrinsicResult, MultiSignature, +}; + +use sp_std::prelude::*; +#[cfg(feature = "std")] +use sp_version::NativeVersion; +use sp_version::RuntimeVersion; + +use frame_support::{ + construct_runtime, parameter_types, + traits::{ConstU32, Contains, EitherOfDiverse, Everything}, + weights::{ + constants::WEIGHT_PER_SECOND, ConstantMultiplier, DispatchClass, Weight, + WeightToFeeCoefficient, WeightToFeeCoefficients, WeightToFeePolynomial, + }, + PalletId, +}; +use frame_system::{ + limits::{BlockLength, BlockWeights}, + EnsureRoot, +}; +pub use sp_consensus_aura::sr25519::AuthorityId as AuraId; +pub use sp_runtime::{MultiAddress, Perbill, Permill}; +use xcm_config::{XcmConfig, XcmOriginToTransactDispatchOrigin}; + +#[cfg(any(feature = "std", test))] +pub use sp_runtime::BuildStorage; + +// Polkadot imports +use polkadot_runtime_common::{BlockHashCount, SlowAdjustingFeeUpdate}; + +use weights::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight}; + +// XCM Imports +use xcm::latest::prelude::BodyId; +use xcm_executor::XcmExecutor; + +pub use primitives::{ + currency::{ZERO, PLAY, GAME, AssetIds, CurrencyId, TokenSymbol}, + dollar, cent, millicent, + Amount, ReserveIdentifier +}; + +use orml_traits::{parameter_type_with_key, GetByKey}; +use orml_currencies::BasicCurrencyAdapter; + +/// Alias to 512-bit hash when used in the context of a transaction signature on the chain. +pub type Signature = MultiSignature; + +/// Some way of identifying an account on the chain. We intentionally make it equivalent +/// to the public key of our transaction signing scheme. +pub type AccountId = <::Signer as IdentifyAccount>::AccountId; + +/// Balance of an account. +pub type Balance = u128; + +/// Index of a transaction in the chain. +pub type Index = u32; + +/// A hash of some data used by the chain. +pub type Hash = sp_core::H256; + +/// An index to a block. +pub type BlockNumber = u32; + +/// The address format for describing accounts. +pub type Address = MultiAddress; + +/// Block header type as expected by this runtime. +pub type Header = generic::Header; + +/// Block type as expected by this runtime. +pub type Block = generic::Block; + +/// A Block signed with a Justification +pub type SignedBlock = generic::SignedBlock; + +/// BlockId type as expected by this runtime. +pub type BlockId = generic::BlockId; + +/// The SignedExtension to the basic transaction logic. +pub type SignedExtra = ( + frame_system::CheckNonZeroSender, + frame_system::CheckSpecVersion, + frame_system::CheckTxVersion, + frame_system::CheckGenesis, + frame_system::CheckEra, + frame_system::CheckNonce, + frame_system::CheckWeight, + pallet_transaction_payment::ChargeTransactionPayment, +); + +/// Unchecked extrinsic type as expected by this runtime. +pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; + +/// Extrinsic type that has already been checked. +pub type CheckedExtrinsic = generic::CheckedExtrinsic; + +/// Executive: handles dispatch to the various modules. +pub type Executive = frame_executive::Executive< + Runtime, + Block, + frame_system::ChainContext, + Runtime, + AllPalletsWithSystem, +>; + +/// Handles converting a weight scalar to a fee value, based on the scale and granularity of the +/// node's balance type. +/// +/// This should typically create a mapping between the following ranges: +/// - `[0, MAXIMUM_BLOCK_WEIGHT]` +/// - `[Balance::min, Balance::max]` +/// +/// Yet, it can be used for any other sort of change to weight-fee. Some examples being: +/// - Setting it to `0` will essentially disable the weight fee. +/// - Setting it to `1` will cause the literal `#[weight = x]` values to be charged. +pub struct WeightToFee; +impl WeightToFeePolynomial for WeightToFee { + type Balance = Balance; + fn polynomial() -> WeightToFeeCoefficients { + // in Rococo, extrinsic base weight (smallest non-zero weight) is mapped to 1 MILLIUNIT: + // in our template, we map to 1/10 of that, or 1/10 MILLIUNIT + let p = MILLIUNIT / 10; + let q = 100 * Balance::from(ExtrinsicBaseWeight::get()); + smallvec![WeightToFeeCoefficient { + degree: 1, + negative: false, + coeff_frac: Perbill::from_rational(p % q, q), + coeff_integer: p / q, + }] + } +} + +/// Opaque types. These are used by the CLI to instantiate machinery that don't need to know +/// the specifics of the runtime. They can then be made to be agnostic over specific formats +/// of data like extrinsics, allowing for them to continue syncing the network through upgrades +/// to even the core data structures. +pub mod opaque { + use super::*; + use sp_runtime::{generic, traits::BlakeTwo256}; + + pub use sp_runtime::OpaqueExtrinsic as UncheckedExtrinsic; + /// Opaque block header type. + pub type Header = generic::Header; + /// Opaque block type. + pub type Block = generic::Block; + /// Opaque block identifier type. + pub type BlockId = generic::BlockId; +} + +impl_opaque_keys! { + pub struct SessionKeys { + pub aura: Aura, + } +} + +#[sp_version::runtime_version] +pub const VERSION: RuntimeVersion = RuntimeVersion { + spec_name: create_runtime_str!("subzero"), + impl_name: create_runtime_str!("alphaville"), + authoring_version: 1, + spec_version: 1, + impl_version: 0, + apis: RUNTIME_API_VERSIONS, + transaction_version: 1, + state_version: 1, +}; + +/// This determines the average expected block time that we are targeting. +/// Blocks will be produced at a minimum duration defined by `SLOT_DURATION`. +/// `SLOT_DURATION` is picked up by `pallet_timestamp` which is in turn picked +/// up by `pallet_aura` to implement `fn slot_duration()`. +/// +/// Change this to adjust the block time. +pub const MILLISECS_PER_BLOCK: u64 = 12000; + +// NOTE: Currently it is not possible to change the slot duration after the chain has started. +// Attempting to do so will brick block production. +pub const SLOT_DURATION: u64 = MILLISECS_PER_BLOCK; + +// Time is measured by number of blocks. +pub const MINUTES: BlockNumber = 60_000 / (MILLISECS_PER_BLOCK as BlockNumber); +pub const HOURS: BlockNumber = MINUTES * 60; +pub const DAYS: BlockNumber = HOURS * 24; + +// Unit = the base number of indivisible units for balances +pub const UNIT: Balance = 1_000_000_000_000; +pub const MILLIUNIT: Balance = 1_000_000_000; +pub const MICROUNIT: Balance = 1_000_000; + +/// The existential deposit. Set to 1/10 of the Connected Relay Chain. +pub const EXISTENTIAL_DEPOSIT: Balance = MILLIUNIT; + +/// We assume that ~5% of the block weight is consumed by `on_initialize` handlers. This is +/// used to limit the maximal weight of a single extrinsic. +const AVERAGE_ON_INITIALIZE_RATIO: Perbill = Perbill::from_percent(5); + +/// We allow `Normal` extrinsics to fill up the block up to 75%, the rest can be used by +/// `Operational` extrinsics. +const NORMAL_DISPATCH_RATIO: Perbill = Perbill::from_percent(75); + +/// We allow for 0.5 of a second of compute with a 12 second average block time. +const MAXIMUM_BLOCK_WEIGHT: Weight = WEIGHT_PER_SECOND / 2; + +/// The version information used to identify this runtime when compiled natively. +#[cfg(feature = "std")] +pub fn native_version() -> NativeVersion { + NativeVersion { runtime_version: VERSION, can_author_with: Default::default() } +} + +parameter_types! { + pub const Version: RuntimeVersion = VERSION; + + // This part is copied from Substrate's `bin/node/runtime/src/lib.rs`. + // The `RuntimeBlockLength` and `RuntimeBlockWeights` exist here because the + // `DeletionWeightLimit` and `DeletionQueueDepth` depend on those to parameterize + // the lazy contract deletion. + pub RuntimeBlockLength: BlockLength = + BlockLength::max_with_normal_ratio(5 * 1024 * 1024, NORMAL_DISPATCH_RATIO); + pub RuntimeBlockWeights: BlockWeights = BlockWeights::builder() + .base_block(BlockExecutionWeight::get()) + .for_class(DispatchClass::all(), |weights| { + weights.base_extrinsic = ExtrinsicBaseWeight::get(); + }) + .for_class(DispatchClass::Normal, |weights| { + weights.max_total = Some(NORMAL_DISPATCH_RATIO * MAXIMUM_BLOCK_WEIGHT); + }) + .for_class(DispatchClass::Operational, |weights| { + weights.max_total = Some(MAXIMUM_BLOCK_WEIGHT); + // Operational transactions have some extra reserved space, so that they + // are included even if block reached `MAXIMUM_BLOCK_WEIGHT`. + weights.reserved = Some( + MAXIMUM_BLOCK_WEIGHT - NORMAL_DISPATCH_RATIO * MAXIMUM_BLOCK_WEIGHT + ); + }) + .avg_block_initialization(AVERAGE_ON_INITIALIZE_RATIO) + .build_or_panic(); + pub const SS58Prefix: u16 = 25; +} + +// Configure FRAME pallets to include in runtime. + +impl frame_system::Config for Runtime { + /// The identifier used to distinguish between accounts. + type AccountId = AccountId; + /// The aggregated dispatch type that is available for extrinsics. + type Call = Call; + /// The lookup mechanism to get account ID from whatever is passed in dispatchers. + type Lookup = AccountIdLookup; + /// The index type for storing how many extrinsics an account has signed. + type Index = Index; + /// The index type for blocks. + type BlockNumber = BlockNumber; + /// The type for hashing blocks and tries. + type Hash = Hash; + /// The hashing algorithm used. + type Hashing = BlakeTwo256; + /// The header type. + type Header = generic::Header; + /// The ubiquitous event type. + type Event = Event; + /// The ubiquitous origin type. + type Origin = Origin; + /// Maximum number of block number to block hash mappings to keep (oldest pruned first). + type BlockHashCount = BlockHashCount; + /// Runtime version. + type Version = Version; + /// Converts a module to an index of this module in the runtime. + type PalletInfo = PalletInfo; + /// The data to be stored in an account. + type AccountData = pallet_balances::AccountData; + /// What to do if a new account is created. + type OnNewAccount = (); + /// What to do if an account is fully reaped from the system. + type OnKilledAccount = (); + /// The weight of database operations that the runtime can invoke. + type DbWeight = RocksDbWeight; + /// The basic call filter to use in dispatchable. + type BaseCallFilter = Everything; + /// Weight information for the extrinsics of this pallet. + type SystemWeightInfo = (); + /// Block & extrinsics weights: base values and limits. + type BlockWeights = RuntimeBlockWeights; + /// The maximum length of a block (in bytes). + type BlockLength = RuntimeBlockLength; + /// This is used as an identifier of the chain. 42 is the generic substrate prefix. + type SS58Prefix = SS58Prefix; + /// The action to take on a Runtime Upgrade + type OnSetCode = cumulus_pallet_parachain_system::ParachainSetCode; + type MaxConsumers = ConstU32<16>; +} + +parameter_types! { + pub const MinimumPeriod: u64 = SLOT_DURATION / 2; +} + +impl pallet_timestamp::Config for Runtime { + /// A timestamp: milliseconds since the unix epoch. + type Moment = u64; + type OnTimestampSet = (); + type MinimumPeriod = MinimumPeriod; + type WeightInfo = (); +} + +parameter_types! { + pub const UncleGenerations: u32 = 0; +} + +impl pallet_authorship::Config for Runtime { + type FindAuthor = pallet_session::FindAccountFromAuthorIndex; + type UncleGenerations = UncleGenerations; + type FilterUncle = (); + type EventHandler = (CollatorSelection,); +} + +parameter_types! { + pub ExistentialDeposit: Balance = ExistentialDeposits::get(&ZERO); + pub const MaxLocks: u32 = 50; + pub const MaxReserves: u32 = ReserveIdentifier::Count as u32; +} + +impl pallet_balances::Config for Runtime { + type MaxLocks = MaxLocks; + /// The type for recording an account's balance. + type Balance = Balance; + /// The ubiquitous event type. + type Event = Event; + type DustRemoval = (); + type ExistentialDeposit = ExistentialDeposit; + type AccountStore = System; + type WeightInfo = pallet_balances::weights::SubstrateWeight; + type MaxReserves = MaxReserves; + type ReserveIdentifier = ReserveIdentifier; +} + +parameter_types! { + /// Relay Chain `TransactionByteFee` / 10 + pub const TransactionByteFee: Balance = 10 * MICROUNIT; + pub const OperationalFeeMultiplier: u8 = 5; +} + +impl pallet_transaction_payment::Config for Runtime { + type OnChargeTransaction = pallet_transaction_payment::CurrencyAdapter; + type WeightToFee = WeightToFee; + type LengthToFee = ConstantMultiplier; + type FeeMultiplierUpdate = SlowAdjustingFeeUpdate; + type OperationalFeeMultiplier = OperationalFeeMultiplier; +} + +impl pallet_sudo::Config for Runtime { + type Event = Event; + type Call = Call; +} + +parameter_types! { + pub BountyValueMinimum: Balance = 5 * dollar(ZERO); + pub BountyDepositBase: Balance = 1 * dollar(ZERO); + pub const CuratorDepositMultiplier: Permill = Permill::from_percent(50); + pub CuratorDepositMin: Balance = 1 * dollar(ZERO); + pub CuratorDepositMax: Balance = 100 * dollar(ZERO); + pub const BountyDepositPayoutDelay: BlockNumber = 1 * DAYS; + pub const BountyUpdatePeriod: BlockNumber = 14 * DAYS; +} + +impl pallet_bounties::Config for Runtime { + type Event = Event; + type BountyDepositBase = BountyDepositBase; + type BountyDepositPayoutDelay = BountyDepositPayoutDelay; + type BountyUpdatePeriod = BountyUpdatePeriod; + type CuratorDepositMultiplier = CuratorDepositMultiplier; + type CuratorDepositMin = CuratorDepositMin; + type CuratorDepositMax = CuratorDepositMax; + type BountyValueMinimum = BountyValueMinimum; + type DataDepositPerByte = DataDepositPerByte; + type MaximumReasonLength = MaximumReasonLength; + type WeightInfo = pallet_bounties::weights::SubstrateWeight; + type ChildBountyManager = ChildBounties; +} + +parameter_types! { + pub ChildBountyValueMinimum: Balance = 1 * dollar(ZERO); +} + +impl pallet_child_bounties::Config for Runtime { + type Event = Event; + type MaxActiveChildBountyCount = ConstU32<5>; + type ChildBountyValueMinimum = ChildBountyValueMinimum; + type WeightInfo = pallet_child_bounties::weights::SubstrateWeight; +} + +parameter_types! { + pub const CouncilMotionDuration: BlockNumber = 5 * DAYS; + pub const CouncilMaxMembers: u32 = 100; +} + +type EnsureRootOrHalfCouncil = EitherOfDiverse< + EnsureRoot, + pallet_collective::EnsureProportionMoreThan, +>; + +type EnsureRootOrThreeFourthsCouncil = EitherOfDiverse< + EnsureRoot, + pallet_collective::EnsureProportionMoreThan, +>; + +type CouncilCollective = pallet_collective::Instance1; +impl pallet_collective::Config for Runtime { + type Origin = Origin; + type Proposal = Call; + type Event = Event; + type MotionDuration = CouncilMotionDuration; + type MaxProposals = ConstU32<100>; + type MaxMembers = CouncilMaxMembers; + type DefaultVote = pallet_collective::PrimeDefaultVote; + type WeightInfo = pallet_collective::weights::SubstrateWeight; +} + +parameter_types! { + pub const ProposalBond: Permill = Permill::from_percent(5); + pub ProposalBondMinimum: Balance = 1 * dollar(ZERO); + pub const SpendPeriod: BlockNumber = 1 * DAYS; + pub const Burn: Permill = Permill::from_percent(50); + pub DataDepositPerByte: Balance = 1 * cent(ZERO); + pub const MaximumReasonLength: u32 = 300; +} + +impl pallet_treasury::Config for Runtime { + type PalletId = TreasuryPalletId; + type Currency = Balances; + type ApproveOrigin = EitherOfDiverse< + EnsureRoot, + pallet_collective::EnsureProportionAtLeast, + >; + type RejectOrigin = EitherOfDiverse< + EnsureRoot, + pallet_collective::EnsureProportionMoreThan, + >; + type Event = Event; + type OnSlash = (); + type ProposalBond = ProposalBond; + type ProposalBondMinimum = ProposalBondMinimum; + type ProposalBondMaximum = (); + type SpendPeriod = SpendPeriod; + type Burn = Burn; + type BurnDestination = (); + type SpendFunds = Bounties; + type WeightInfo = pallet_treasury::weights::SubstrateWeight; + type MaxApprovals = ConstU32<100>; + type SpendOrigin = frame_support::traits::NeverEnsureOrigin; +} + +parameter_types! { + pub BasicDeposit: Balance = 10 * dollar(ZERO); // 258 bytes on-chain + pub FieldDeposit: Balance = 250 * cent(ZERO); // 66 bytes on-chain + pub SubAccountDeposit: Balance = 2 * dollar(ZERO); // 53 bytes on-chain +} + +impl pallet_identity::Config for Runtime { + type Event = Event; + type Currency = Balances; + type BasicDeposit = BasicDeposit; + type FieldDeposit = FieldDeposit; + type SubAccountDeposit = SubAccountDeposit; + type MaxSubAccounts = ConstU32<100>; + type MaxAdditionalFields = ConstU32<100>; + type MaxRegistrars = ConstU32<20>; + type Slashed = Treasury; + type ForceOrigin = EnsureRootOrHalfCouncil; + type RegistrarOrigin = EnsureRootOrHalfCouncil; + type WeightInfo = pallet_identity::weights::SubstrateWeight; +} + +parameter_types! { + pub const ReservedXcmpWeight: Weight = MAXIMUM_BLOCK_WEIGHT / 4; + pub const ReservedDmpWeight: Weight = MAXIMUM_BLOCK_WEIGHT / 4; +} + +impl cumulus_pallet_parachain_system::Config for Runtime { + type Event = Event; + type OnSystemEvent = (); + type SelfParaId = parachain_info::Pallet; + type OutboundXcmpMessageSource = XcmpQueue; + type DmpMessageHandler = DmpQueue; + type ReservedDmpWeight = ReservedDmpWeight; + type XcmpMessageHandler = XcmpQueue; + type ReservedXcmpWeight = ReservedXcmpWeight; + type CheckAssociatedRelayNumber = RelayNumberStrictlyIncreases; +} + +impl parachain_info::Config for Runtime {} + +impl cumulus_pallet_aura_ext::Config for Runtime {} + +impl cumulus_pallet_xcmp_queue::Config for Runtime { + type Event = Event; + type XcmExecutor = XcmExecutor; + type ChannelInfo = ParachainSystem; + type VersionWrapper = (); + type ExecuteOverweightOrigin = EnsureRoot; + type ControllerOrigin = EnsureRoot; + type ControllerOriginConverter = XcmOriginToTransactDispatchOrigin; + type WeightInfo = (); +} + +impl cumulus_pallet_dmp_queue::Config for Runtime { + type Event = Event; + type XcmExecutor = XcmExecutor; + type ExecuteOverweightOrigin = EnsureRoot; +} + +parameter_types! { + pub const Period: u32 = 6 * HOURS; + pub const Offset: u32 = 0; + pub const MaxAuthorities: u32 = 100_000; +} + +impl pallet_session::Config for Runtime { + type Event = Event; + type ValidatorId = ::AccountId; + // we don't have stash and controller, thus we don't need the convert as well. + type ValidatorIdOf = pallet_collator_selection::IdentityCollator; + type ShouldEndSession = pallet_session::PeriodicSessions; + type NextSessionRotation = pallet_session::PeriodicSessions; + type SessionManager = CollatorSelection; + // Essentially just Aura, but lets be pedantic. + type SessionHandler = ::KeyTypeIdProviders; + type Keys = SessionKeys; + type WeightInfo = (); +} + +impl pallet_aura::Config for Runtime { + type AuthorityId = AuraId; + type DisabledValidators = (); + type MaxAuthorities = MaxAuthorities; +} + +parameter_types! { + pub const PotId: PalletId = PalletId(*b"PotStake"); + pub const MaxCandidates: u32 = 1000; + pub const MinCandidates: u32 = 5; + pub const SessionLength: BlockNumber = 6 * HOURS; + pub const MaxInvulnerables: u32 = 100; + pub const ExecutiveBody: BodyId = BodyId::Executive; +} + +// We allow root only to execute privileged collator selection operations. +pub type CollatorSelectionUpdateOrigin = EnsureRoot; + +impl pallet_collator_selection::Config for Runtime { + type Event = Event; + type Currency = Balances; + type UpdateOrigin = CollatorSelectionUpdateOrigin; + type PotId = PotId; + type MaxCandidates = MaxCandidates; + type MinCandidates = MinCandidates; + type MaxInvulnerables = MaxInvulnerables; + // should be a multiple of session or things will get inconsistent + type KickThreshold = Period; + type ValidatorId = ::AccountId; + type ValidatorIdOf = pallet_collator_selection::IdentityCollator; + type ValidatorRegistration = Session; + type WeightInfo = (); +} + +// Pallet accounts of runtime +parameter_types! { + pub const TreasuryPalletId: PalletId = PalletId(*b"zr/zrtrs"); + pub const ControlPalletId: PalletId = PalletId(*b"gd/cntrl"); + pub TreasuryAccountId: AccountId = TreasuryPalletId::get().into_account_truncating(); + pub Game3FoundationTreasuryAccountId: AccountId = PalletId(*b"gd/g3trs").into_account_truncating(); + pub GameDAOTreasuryAccountId: AccountId = PalletId(*b"gd/gdtrs").into_account_truncating(); +} + +pub fn get_all_module_accounts() -> Vec { + vec![ + TreasuryAccountId::get(), + ControlPalletId::get().into_account_truncating(), + Game3FoundationTreasuryAccountId::get(), + GameDAOTreasuryAccountId::get(), + ] +} + +parameter_type_with_key! { + pub ExistentialDeposits: |currency_id: CurrencyId| -> Balance { + match currency_id { + CurrencyId::Token(symbol) => match symbol { + TokenSymbol::ZERO => cent(*currency_id), + TokenSymbol::PLAY => 10 * cent(*currency_id), + TokenSymbol::GAME => 10 * cent(*currency_id), + + TokenSymbol::AUSD => 10 * cent(*currency_id), + TokenSymbol::DOT => cent(*currency_id), + TokenSymbol::LDOT => 5 * cent(*currency_id), + + TokenSymbol::KAR | + TokenSymbol::KUSD | + TokenSymbol::KSM | + TokenSymbol::LKSM | + TokenSymbol::BNC | + TokenSymbol::PHA | + TokenSymbol::VSKSM | + TokenSymbol::ACA | + TokenSymbol::KBTC | + TokenSymbol::KINT | + TokenSymbol::TAI => Balance::max_value() // unsupported + }, + _ => Balance::max_value() + } + }; +} + +pub struct DustRemovalWhitelist; +impl Contains for DustRemovalWhitelist { + fn contains(a: &AccountId) -> bool { + get_all_module_accounts().contains(a) + } +} + +parameter_types! { + pub const GetNativeCurrencyId: CurrencyId = ZERO; + pub const GetStableCurrencyId: CurrencyId = PLAY; + pub const GetProtocolCurrencyId: CurrencyId = GAME; + pub const StringLimit: u32 = 64; +} + +impl orml_tokens::Config for Runtime { + type Event = Event; + type Balance = Balance; + type Amount = Amount; + type CurrencyId = CurrencyId; + type WeightInfo = (); + type ExistentialDeposits = ExistentialDeposits; + type OnDust = orml_tokens::TransferDust; + type MaxLocks = MaxLocks; + type MaxReserves = MaxReserves; + type ReserveIdentifier = ReserveIdentifier; + type DustRemovalWhitelist = DustRemovalWhitelist; + type OnNewTokenAccount = (); + type OnKilledTokenAccount = (); +} + +impl orml_currencies::Config for Runtime { + type MultiCurrency = Tokens; + type NativeCurrency = BasicCurrencyAdapter; + type GetNativeCurrencyId = GetNativeCurrencyId; + type WeightInfo = (); +} + +impl orml_unknown_tokens::Config for Runtime { + type Event = Event; +} + +impl orml_xcm::Config for Runtime { + type Event = Event; + type SovereignOrigin = EnsureRootOrThreeFourthsCouncil; +} + +// Create the runtime by composing the FRAME pallets that were previously configured. +construct_runtime!( + pub enum Runtime where + Block = Block, + NodeBlock = opaque::Block, + UncheckedExtrinsic = UncheckedExtrinsic, + { + // System support stuff. + System: frame_system::{Pallet, Call, Config, Storage, Event} = 0, + ParachainSystem: cumulus_pallet_parachain_system::{ + Pallet, Call, Config, Storage, Inherent, Event, ValidateUnsigned, + } = 1, + Timestamp: pallet_timestamp::{Pallet, Call, Storage, Inherent} = 2, + ParachainInfo: parachain_info::{Pallet, Storage, Config} = 3, + Council: pallet_collective:: = 4, + Identity: pallet_identity = 5, + Bounties: pallet_bounties = 6, + ChildBounties: pallet_child_bounties = 7, + Sudo: pallet_sudo = 8, + Treasury: pallet_treasury = 9, + + // Monetary stuff. + Balances: pallet_balances::{Pallet, Call, Storage, Config, Event} = 10, + TransactionPayment: pallet_transaction_payment::{Pallet, Storage} = 11, + + // Collator support. The order of these 4 are important and shall not change. + Authorship: pallet_authorship::{Pallet, Call, Storage} = 20, + CollatorSelection: pallet_collator_selection::{Pallet, Call, Storage, Event, Config} = 21, + Session: pallet_session::{Pallet, Call, Storage, Event, Config} = 22, + Aura: pallet_aura::{Pallet, Storage, Config} = 23, + AuraExt: cumulus_pallet_aura_ext::{Pallet, Storage, Config} = 24, + + // XCM helpers. + XcmpQueue: cumulus_pallet_xcmp_queue::{Pallet, Call, Storage, Event} = 30, + PolkadotXcm: pallet_xcm::{Pallet, Call, Event, Origin, Config} = 31, + CumulusXcm: cumulus_pallet_xcm::{Pallet, Event, Origin} = 32, + DmpQueue: cumulus_pallet_dmp_queue::{Pallet, Call, Storage, Event} = 33, + + // ORML + Tokens: orml_tokens::{Pallet, Storage, Event, Config} = 40, + Currencies: orml_currencies::{Pallet, Call} = 41, + UnknownTokens: orml_unknown_tokens::{Pallet, Storage, Event} = 43, + OrmlXcm: orml_xcm::{Pallet, Call, Event} = 44, + } +); + +#[cfg(feature = "runtime-benchmarks")] +#[macro_use] +extern crate frame_benchmarking; + +#[cfg(feature = "runtime-benchmarks")] +mod benches { + define_benchmarks!( + [frame_system, SystemBench::] + [pallet_balances, Balances] + [pallet_session, SessionBench::] + [pallet_timestamp, Timestamp] + [pallet_collator_selection, CollatorSelection] + [cumulus_pallet_xcmp_queue, XcmpQueue] + ); +} + +impl_runtime_apis! { + impl sp_consensus_aura::AuraApi for Runtime { + fn slot_duration() -> sp_consensus_aura::SlotDuration { + sp_consensus_aura::SlotDuration::from_millis(Aura::slot_duration()) + } + + fn authorities() -> Vec { + Aura::authorities().into_inner() + } + } + + impl sp_api::Core for Runtime { + fn version() -> RuntimeVersion { + VERSION + } + + fn execute_block(block: Block) { + Executive::execute_block(block) + } + + fn initialize_block(header: &::Header) { + Executive::initialize_block(header) + } + } + + impl sp_api::Metadata for Runtime { + fn metadata() -> OpaqueMetadata { + OpaqueMetadata::new(Runtime::metadata().into()) + } + } + + impl sp_block_builder::BlockBuilder for Runtime { + fn apply_extrinsic(extrinsic: ::Extrinsic) -> ApplyExtrinsicResult { + Executive::apply_extrinsic(extrinsic) + } + + fn finalize_block() -> ::Header { + Executive::finalize_block() + } + + fn inherent_extrinsics(data: sp_inherents::InherentData) -> Vec<::Extrinsic> { + data.create_extrinsics() + } + + fn check_inherents( + block: Block, + data: sp_inherents::InherentData, + ) -> sp_inherents::CheckInherentsResult { + data.check_extrinsics(&block) + } + } + + impl sp_transaction_pool::runtime_api::TaggedTransactionQueue for Runtime { + fn validate_transaction( + source: TransactionSource, + tx: ::Extrinsic, + block_hash: ::Hash, + ) -> TransactionValidity { + Executive::validate_transaction(source, tx, block_hash) + } + } + + impl sp_offchain::OffchainWorkerApi for Runtime { + fn offchain_worker(header: &::Header) { + Executive::offchain_worker(header) + } + } + + impl sp_session::SessionKeys for Runtime { + fn generate_session_keys(seed: Option>) -> Vec { + SessionKeys::generate(seed) + } + + fn decode_session_keys( + encoded: Vec, + ) -> Option, KeyTypeId)>> { + SessionKeys::decode_into_raw_public_keys(&encoded) + } + } + + impl frame_system_rpc_runtime_api::AccountNonceApi for Runtime { + fn account_nonce(account: AccountId) -> Index { + System::account_nonce(account) + } + } + + impl pallet_transaction_payment_rpc_runtime_api::TransactionPaymentApi for Runtime { + fn query_info( + uxt: ::Extrinsic, + len: u32, + ) -> pallet_transaction_payment_rpc_runtime_api::RuntimeDispatchInfo { + TransactionPayment::query_info(uxt, len) + } + fn query_fee_details( + uxt: ::Extrinsic, + len: u32, + ) -> pallet_transaction_payment::FeeDetails { + TransactionPayment::query_fee_details(uxt, len) + } + } + + impl cumulus_primitives_core::CollectCollationInfo for Runtime { + fn collect_collation_info(header: &::Header) -> cumulus_primitives_core::CollationInfo { + ParachainSystem::collect_collation_info(header) + } + } + + #[cfg(feature = "try-runtime")] + impl frame_try_runtime::TryRuntime for Runtime { + fn on_runtime_upgrade() -> (Weight, Weight) { + log::info!("try-runtime::on_runtime_upgrade parachain-subzero."); + let weight = Executive::try_runtime_upgrade().unwrap(); + (weight, RuntimeBlockWeights::get().max_block) + } + + fn execute_block_no_check(block: Block) -> Weight { + Executive::execute_block_no_check(block) + } + } + + #[cfg(feature = "runtime-benchmarks")] + impl frame_benchmarking::Benchmark for Runtime { + fn benchmark_metadata(extra: bool) -> ( + Vec, + Vec, + ) { + use frame_benchmarking::{Benchmarking, BenchmarkList}; + use frame_support::traits::StorageInfoTrait; + use frame_system_benchmarking::Pallet as SystemBench; + use cumulus_pallet_session_benchmarking::Pallet as SessionBench; + + let mut list = Vec::::new(); + list_benchmarks!(list, extra); + + let storage_info = AllPalletsWithSystem::storage_info(); + return (list, storage_info) + } + + fn dispatch_benchmark( + config: frame_benchmarking::BenchmarkConfig + ) -> Result, sp_runtime::RuntimeString> { + use frame_benchmarking::{Benchmarking, BenchmarkBatch, TrackedStorageKey}; + + use frame_system_benchmarking::Pallet as SystemBench; + impl frame_system_benchmarking::Config for Runtime {} + + use cumulus_pallet_session_benchmarking::Pallet as SessionBench; + impl cumulus_pallet_session_benchmarking::Config for Runtime {} + + let whitelist: Vec = vec![ + // Block Number + hex_literal::hex!("26aa394eea5630e07c48ae0c9558cef702a5c1b19ab7a04f536c519aca4983ac").to_vec().into(), + // Total Issuance + hex_literal::hex!("c2261276cc9d1f8598ea4b6a74b15c2f57c875e4cff74148e4628f264b974c80").to_vec().into(), + // Execution Phase + hex_literal::hex!("26aa394eea5630e07c48ae0c9558cef7ff553b5a9862a516939d82b3d3d8661a").to_vec().into(), + // Event Count + hex_literal::hex!("26aa394eea5630e07c48ae0c9558cef70a98fdbe9ce6c55837576c60c7af3850").to_vec().into(), + // System Events + hex_literal::hex!("26aa394eea5630e07c48ae0c9558cef780d41e5e16056765bc8461851072c9d7").to_vec().into(), + ]; + + let mut batches = Vec::::new(); + let params = (&config, &whitelist); + add_benchmarks!(params, batches); + + if batches.is_empty() { return Err("Benchmark not found for this pallet.".into()) } + Ok(batches) + } + } +} + +struct CheckInherents; + +impl cumulus_pallet_parachain_system::CheckInherents for CheckInherents { + fn check_inherents( + block: &Block, + relay_state_proof: &cumulus_pallet_parachain_system::RelayChainStateProof, + ) -> sp_inherents::CheckInherentsResult { + let relay_chain_slot = relay_state_proof + .read_slot() + .expect("Could not read the relay chain slot from the proof"); + + let inherent_data = + cumulus_primitives_timestamp::InherentDataProvider::from_relay_chain_slot_and_duration( + relay_chain_slot, + sp_std::time::Duration::from_secs(6), + ) + .create_inherent_data() + .expect("Could not create the timestamp inherent data"); + + inherent_data.check_extrinsics(block) + } +} + +cumulus_pallet_parachain_system::register_validate_block! { + Runtime = Runtime, + BlockExecutor = cumulus_pallet_aura_ext::BlockExecutor::, + CheckInherents = CheckInherents, +} diff --git a/bin/zero-parachain-live/runtime/src/weights/block_weights.rs b/bin/zero-parachain-live/runtime/src/weights/block_weights.rs new file mode 100644 index 0000000000..4db90f0c02 --- /dev/null +++ b/bin/zero-parachain-live/runtime/src/weights/block_weights.rs @@ -0,0 +1,46 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// 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. + +pub mod constants { + use frame_support::{ + parameter_types, + weights::{constants, Weight}, + }; + + parameter_types! { + /// Importing a block with 0 Extrinsics. + pub const BlockExecutionWeight: Weight = 5_000_000 * constants::WEIGHT_PER_NANOS; + } + + #[cfg(test)] + mod test_weights { + use frame_support::weights::constants; + + /// Checks that the weight exists and is sane. + // NOTE: If this test fails but you are sure that the generated values are fine, + // you can delete it. + #[test] + fn sane() { + let w = super::constants::BlockExecutionWeight::get(); + + // At least 100 µs. + assert!(w >= 100 * constants::WEIGHT_PER_MICROS, "Weight should be at least 100 µs."); + // At most 50 ms. + assert!(w <= 50 * constants::WEIGHT_PER_MILLIS, "Weight should be at most 50 ms."); + } + } +} diff --git a/bin/zero-parachain-live/runtime/src/weights/extrinsic_weights.rs b/bin/zero-parachain-live/runtime/src/weights/extrinsic_weights.rs new file mode 100644 index 0000000000..158ba99c6a --- /dev/null +++ b/bin/zero-parachain-live/runtime/src/weights/extrinsic_weights.rs @@ -0,0 +1,46 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// 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. + +pub mod constants { + use frame_support::{ + parameter_types, + weights::{constants, Weight}, + }; + + parameter_types! { + /// Executing a NO-OP `System::remarks` Extrinsic. + pub const ExtrinsicBaseWeight: Weight = 125_000 * constants::WEIGHT_PER_NANOS; + } + + #[cfg(test)] + mod test_weights { + use frame_support::weights::constants; + + /// Checks that the weight exists and is sane. + // NOTE: If this test fails but you are sure that the generated values are fine, + // you can delete it. + #[test] + fn sane() { + let w = super::constants::ExtrinsicBaseWeight::get(); + + // At least 10 µs. + assert!(w >= 10 * constants::WEIGHT_PER_MICROS, "Weight should be at least 10 µs."); + // At most 1 ms. + assert!(w <= constants::WEIGHT_PER_MILLIS, "Weight should be at most 1 ms."); + } + } +} diff --git a/bin/zero-parachain-live/runtime/src/weights/mod.rs b/bin/zero-parachain-live/runtime/src/weights/mod.rs new file mode 100644 index 0000000000..ed0b4dbcd4 --- /dev/null +++ b/bin/zero-parachain-live/runtime/src/weights/mod.rs @@ -0,0 +1,28 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// 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. + +//! Expose the auto generated weight files. + +pub mod block_weights; +pub mod extrinsic_weights; +pub mod paritydb_weights; +pub mod rocksdb_weights; + +pub use block_weights::constants::BlockExecutionWeight; +pub use extrinsic_weights::constants::ExtrinsicBaseWeight; +pub use paritydb_weights::constants::ParityDbWeight; +pub use rocksdb_weights::constants::RocksDbWeight; diff --git a/bin/zero-parachain-live/runtime/src/weights/paritydb_weights.rs b/bin/zero-parachain-live/runtime/src/weights/paritydb_weights.rs new file mode 100644 index 0000000000..843823c1bf --- /dev/null +++ b/bin/zero-parachain-live/runtime/src/weights/paritydb_weights.rs @@ -0,0 +1,63 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// 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. + +pub mod constants { + use frame_support::{ + parameter_types, + weights::{constants, RuntimeDbWeight}, + }; + + parameter_types! { + /// `ParityDB` can be enabled with a feature flag, but is still experimental. These weights + /// are available for brave runtime engineers who may want to try this out as default. + pub const ParityDbWeight: RuntimeDbWeight = RuntimeDbWeight { + read: 8_000 * constants::WEIGHT_PER_NANOS, + write: 50_000 * constants::WEIGHT_PER_NANOS, + }; + } + + #[cfg(test)] + mod test_db_weights { + use super::constants::ParityDbWeight as W; + use frame_support::weights::constants; + + /// Checks that all weights exist and have sane values. + // NOTE: If this test fails but you are sure that the generated values are fine, + // you can delete it. + #[test] + fn sane() { + // At least 1 µs. + assert!( + W::get().reads(1) >= constants::WEIGHT_PER_MICROS, + "Read weight should be at least 1 µs." + ); + assert!( + W::get().writes(1) >= constants::WEIGHT_PER_MICROS, + "Write weight should be at least 1 µs." + ); + // At most 1 ms. + assert!( + W::get().reads(1) <= constants::WEIGHT_PER_MILLIS, + "Read weight should be at most 1 ms." + ); + assert!( + W::get().writes(1) <= constants::WEIGHT_PER_MILLIS, + "Write weight should be at most 1 ms." + ); + } + } +} diff --git a/bin/zero-parachain-live/runtime/src/weights/rocksdb_weights.rs b/bin/zero-parachain-live/runtime/src/weights/rocksdb_weights.rs new file mode 100644 index 0000000000..05e06b0eab --- /dev/null +++ b/bin/zero-parachain-live/runtime/src/weights/rocksdb_weights.rs @@ -0,0 +1,63 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// 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. + +pub mod constants { + use frame_support::{ + parameter_types, + weights::{constants, RuntimeDbWeight}, + }; + + parameter_types! { + /// By default, Substrate uses `RocksDB`, so this will be the weight used throughout + /// the runtime. + pub const RocksDbWeight: RuntimeDbWeight = RuntimeDbWeight { + read: 25_000 * constants::WEIGHT_PER_NANOS, + write: 100_000 * constants::WEIGHT_PER_NANOS, + }; + } + + #[cfg(test)] + mod test_db_weights { + use super::constants::RocksDbWeight as W; + use frame_support::weights::constants; + + /// Checks that all weights exist and have sane values. + // NOTE: If this test fails but you are sure that the generated values are fine, + // you can delete it. + #[test] + fn sane() { + // At least 1 µs. + assert!( + W::get().reads(1) >= constants::WEIGHT_PER_MICROS, + "Read weight should be at least 1 µs." + ); + assert!( + W::get().writes(1) >= constants::WEIGHT_PER_MICROS, + "Write weight should be at least 1 µs." + ); + // At most 1 ms. + assert!( + W::get().reads(1) <= constants::WEIGHT_PER_MILLIS, + "Read weight should be at most 1 ms." + ); + assert!( + W::get().writes(1) <= constants::WEIGHT_PER_MILLIS, + "Write weight should be at most 1 ms." + ); + } + } +} diff --git a/bin/zero-parachain-live/runtime/src/xcm_config.rs b/bin/zero-parachain-live/runtime/src/xcm_config.rs new file mode 100644 index 0000000000..2ec84d1887 --- /dev/null +++ b/bin/zero-parachain-live/runtime/src/xcm_config.rs @@ -0,0 +1,221 @@ +use super::{ + AccountId, Balances, Call, Event, Origin, ParachainInfo, ParachainSystem, PolkadotXcm, Runtime, + WeightToFee, XcmpQueue, +}; +use core::marker::PhantomData; +use frame_support::{ + log, match_types, parameter_types, + traits::{Everything, Nothing}, + weights::Weight, +}; +use pallet_xcm::XcmPassthrough; +use polkadot_parachain::primitives::Sibling; +use polkadot_runtime_common::impls::ToAuthor; +use xcm::latest::prelude::*; +use xcm_builder::{ + AccountId32Aliases, AllowTopLevelPaidExecutionFrom, AllowUnpaidExecutionFrom, CurrencyAdapter, + EnsureXcmOrigin, FixedWeightBounds, IsConcrete, LocationInverter, NativeAsset, ParentIsPreset, + RelayChainAsNative, SiblingParachainAsNative, SiblingParachainConvertsVia, + SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, + UsingComponents, +}; +use xcm_executor::{traits::ShouldExecute, XcmExecutor}; + +parameter_types! { + pub const RelayLocation: MultiLocation = MultiLocation::parent(); + pub const RelayNetwork: NetworkId = NetworkId::Any; + pub RelayChainOrigin: Origin = cumulus_pallet_xcm::Origin::Relay.into(); + pub Ancestry: MultiLocation = Parachain(ParachainInfo::parachain_id().into()).into(); +} + +/// Type for specifying how a `MultiLocation` can be converted into an `AccountId`. This is used +/// when determining ownership of accounts for asset transacting and when attempting to use XCM +/// `Transact` in order to determine the dispatch Origin. +pub type LocationToAccountId = ( + // The parent (Relay-chain) origin converts to the parent `AccountId`. + ParentIsPreset, + // Sibling parachain origins convert to AccountId via the `ParaId::into`. + SiblingParachainConvertsVia, + // Straight up local `AccountId32` origins just alias directly to `AccountId`. + AccountId32Aliases, +); + +/// Means for transacting assets on this chain. +pub type LocalAssetTransactor = CurrencyAdapter< + // Use this currency: + Balances, + // Use this currency when it is a fungible asset matching the given location or name: + IsConcrete, + // Do a simple punn to convert an AccountId32 MultiLocation into a native chain account ID: + LocationToAccountId, + // Our chain's account ID type (we can't get away without mentioning it explicitly): + AccountId, + // We don't track any teleports. + (), +>; + +/// This is the type we use to convert an (incoming) XCM origin into a local `Origin` instance, +/// ready for dispatching a transaction with Xcm's `Transact`. There is an `OriginKind` which can +/// biases the kind of local `Origin` it will become. +pub type XcmOriginToTransactDispatchOrigin = ( + // Sovereign account converter; this attempts to derive an `AccountId` from the origin location + // using `LocationToAccountId` and then turn that into the usual `Signed` origin. Useful for + // foreign chains who want to have a local sovereign account on this chain which they control. + SovereignSignedViaLocation, + // Native converter for Relay-chain (Parent) location; will converts to a `Relay` origin when + // recognized. + RelayChainAsNative, + // Native converter for sibling Parachains; will convert to a `SiblingPara` origin when + // recognized. + SiblingParachainAsNative, + // Native signed account converter; this just converts an `AccountId32` origin into a normal + // `Origin::Signed` origin of the same 32-byte value. + SignedAccountId32AsNative, + // Xcm origins can be represented natively under the Xcm pallet's Xcm origin. + XcmPassthrough, +); + +parameter_types! { + // One XCM operation is 1_000_000_000 weight - almost certainly a conservative estimate. + pub UnitWeightCost: Weight = 1_000_000_000; + pub const MaxInstructions: u32 = 100; +} + +match_types! { + pub type ParentOrParentsExecutivePlurality: impl Contains = { + MultiLocation { parents: 1, interior: Here } | + MultiLocation { parents: 1, interior: X1(Plurality { id: BodyId::Executive, .. }) } + }; +} + +//TODO: move DenyThenTry to polkadot's xcm module. +/// Deny executing the xcm message if it matches any of the Deny filter regardless of anything else. +/// If it passes the Deny, and matches one of the Allow cases then it is let through. +pub struct DenyThenTry(PhantomData, PhantomData) +where + Deny: ShouldExecute, + Allow: ShouldExecute; + +impl ShouldExecute for DenyThenTry +where + Deny: ShouldExecute, + Allow: ShouldExecute, +{ + fn should_execute( + origin: &MultiLocation, + message: &mut Xcm, + max_weight: Weight, + weight_credit: &mut Weight, + ) -> Result<(), ()> { + Deny::should_execute(origin, message, max_weight, weight_credit)?; + Allow::should_execute(origin, message, max_weight, weight_credit) + } +} + +// See issue #5233 +pub struct DenyReserveTransferToRelayChain; +impl ShouldExecute for DenyReserveTransferToRelayChain { + fn should_execute( + origin: &MultiLocation, + message: &mut Xcm, + _max_weight: Weight, + _weight_credit: &mut Weight, + ) -> Result<(), ()> { + if message.0.iter().any(|inst| { + matches!( + inst, + InitiateReserveWithdraw { + reserve: MultiLocation { parents: 1, interior: Here }, + .. + } | DepositReserveAsset { dest: MultiLocation { parents: 1, interior: Here }, .. } | + TransferReserveAsset { + dest: MultiLocation { parents: 1, interior: Here }, + .. + } + ) + }) { + return Err(()) // Deny + } + + // An unexpected reserve transfer has arrived from the Relay Chain. Generally, `IsReserve` + // should not allow this, but we just log it here. + if matches!(origin, MultiLocation { parents: 1, interior: Here }) && + message.0.iter().any(|inst| matches!(inst, ReserveAssetDeposited { .. })) + { + log::warn!( + target: "xcm::barriers", + "Unexpected ReserveAssetDeposited from the Relay Chain", + ); + } + // Permit everything else + Ok(()) + } +} + +pub type Barrier = DenyThenTry< + DenyReserveTransferToRelayChain, + ( + TakeWeightCredit, + AllowTopLevelPaidExecutionFrom, + AllowUnpaidExecutionFrom, + // ^^^ Parent and its exec plurality get free execution + ), +>; + +pub struct XcmConfig; +impl xcm_executor::Config for XcmConfig { + type Call = Call; + type XcmSender = XcmRouter; + // How to withdraw and deposit an asset. + type AssetTransactor = LocalAssetTransactor; + type OriginConverter = XcmOriginToTransactDispatchOrigin; + type IsReserve = NativeAsset; + type IsTeleporter = (); // Teleporting is disabled. + type LocationInverter = LocationInverter; + type Barrier = Barrier; + type Weigher = FixedWeightBounds; + type Trader = + UsingComponents>; + type ResponseHandler = PolkadotXcm; + type AssetTrap = PolkadotXcm; + type AssetClaims = PolkadotXcm; + type SubscriptionService = PolkadotXcm; +} + +/// No local origins on this chain are allowed to dispatch XCM sends/executions. +pub type LocalOriginToLocation = SignedToAccountId32; + +/// The means for routing XCM messages which are not for local execution into the right message +/// queues. +pub type XcmRouter = ( + // Two routers - use UMP to communicate with the relay chain: + cumulus_primitives_utility::ParentAsUmp, + // ..and XCMP to communicate with the sibling chains. + XcmpQueue, +); + +impl pallet_xcm::Config for Runtime { + type Event = Event; + type SendXcmOrigin = EnsureXcmOrigin; + type XcmRouter = XcmRouter; + type ExecuteXcmOrigin = EnsureXcmOrigin; + type XcmExecuteFilter = Nothing; + // ^ Disable dispatchable execute on the XCM pallet. + // Needs to be `Everything` for local testing. + type XcmExecutor = XcmExecutor; + type XcmTeleportFilter = Everything; + type XcmReserveTransferFilter = Nothing; + type Weigher = FixedWeightBounds; + type LocationInverter = LocationInverter; + type Origin = Origin; + type Call = Call; + + const VERSION_DISCOVERY_QUEUE_SIZE: u32 = 100; + // ^ Override for AdvertisedXcmVersion default + type AdvertisedXcmVersion = pallet_xcm::CurrentXcmVersion; +} + +impl cumulus_pallet_xcm::Config for Runtime { + type Event = Event; + type XcmExecutor = XcmExecutor; +}