From 2101d6ac647794b525f9af13876b0bb04c8f3b0d Mon Sep 17 00:00:00 2001 From: Hernando Castano <HCastano@users.noreply.github.com> Date: Thu, 23 Sep 2021 13:47:47 -0400 Subject: [PATCH] Add Parachain Template (#620) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add Canvas node as Parachain template * Remove `pallet-contracts` * Point to local Cumulus dependency * Use double quotes instead of single quotes * Get rid of GPL licensing * Remove references to Canvas * Get rid of warnings * Remove GLP-3 License copy-pasta file * Copy in README from `substrate-parachain-template` * Add mention of `polkadot-launch` tool * Add missing screenshot asset * Remove Canvas hidden files and scripts * Rename `template` to `parachain-template` * Remove a few more Canvas references * Add `pallet-template` * Get `pallet-template` compiling * Remove TODOs about Weights * Sort some dependencies * Remove contracts specific const * Change binary name back to `parachain-collator` * RustFmt * Fix mock tests * Purge sneaky whitespace * Add template pallet index to runtime Co-authored-by: Ricardo Rius <9488369+riusricardo@users.noreply.github.com> * Add force authoring to collator `polkadot-launch` config Co-authored-by: Ricardo Rius <9488369+riusricardo@users.noreply.github.com> * Refer README readers to `substrate-parachain-template` * Remove license header in `build.rs` Co-authored-by: Michael Müller <michi@parity.io> * Fix punctuation nitpick Co-authored-by: Michael Müller <michi@parity.io> * Remove unused `lib.rs` file * Add note about Rococo network Co-authored-by: Ricardo Rius <9488369+riusricardo@users.noreply.github.com> Co-authored-by: Michael Müller <michi@parity.io> --- cumulus/Cargo.lock | 132 +++ cumulus/Cargo.toml | 8 +- cumulus/parachain-template/LICENSE | 24 + cumulus/parachain-template/README.md | 14 + cumulus/parachain-template/node/Cargo.toml | 95 ++ cumulus/parachain-template/node/build.rs | 7 + .../parachain-template/node/src/chain_spec.rs | 214 +++++ cumulus/parachain-template/node/src/cli.rs | 121 +++ .../parachain-template/node/src/command.rs | 405 +++++++++ cumulus/parachain-template/node/src/main.rs | 14 + cumulus/parachain-template/node/src/rpc.rs | 57 ++ .../parachain-template/node/src/service.rs | 492 ++++++++++ .../pallets/template/Cargo.toml | 37 + .../pallets/template/README.md | 1 + .../pallets/template/src/benchmarking.rs | 20 + .../pallets/template/src/lib.rs | 105 +++ .../pallets/template/src/mock.rs | 63 ++ .../pallets/template/src/tests.rs | 20 + .../polkadot-launch/config.json | 39 + cumulus/parachain-template/runtime/Cargo.toml | 144 +++ cumulus/parachain-template/runtime/build.rs | 9 + cumulus/parachain-template/runtime/src/lib.rs | 845 ++++++++++++++++++ 22 files changed, 2863 insertions(+), 3 deletions(-) create mode 100644 cumulus/parachain-template/LICENSE create mode 100644 cumulus/parachain-template/README.md create mode 100644 cumulus/parachain-template/node/Cargo.toml create mode 100644 cumulus/parachain-template/node/build.rs create mode 100644 cumulus/parachain-template/node/src/chain_spec.rs create mode 100644 cumulus/parachain-template/node/src/cli.rs create mode 100644 cumulus/parachain-template/node/src/command.rs create mode 100644 cumulus/parachain-template/node/src/main.rs create mode 100644 cumulus/parachain-template/node/src/rpc.rs create mode 100644 cumulus/parachain-template/node/src/service.rs create mode 100644 cumulus/parachain-template/pallets/template/Cargo.toml create mode 100644 cumulus/parachain-template/pallets/template/README.md create mode 100644 cumulus/parachain-template/pallets/template/src/benchmarking.rs create mode 100644 cumulus/parachain-template/pallets/template/src/lib.rs create mode 100644 cumulus/parachain-template/pallets/template/src/mock.rs create mode 100644 cumulus/parachain-template/pallets/template/src/tests.rs create mode 100644 cumulus/parachain-template/polkadot-launch/config.json create mode 100644 cumulus/parachain-template/runtime/Cargo.toml create mode 100644 cumulus/parachain-template/runtime/build.rs create mode 100644 cumulus/parachain-template/runtime/src/lib.rs diff --git a/cumulus/Cargo.lock b/cumulus/Cargo.lock index b19bf5f6288..3a756c245c5 100644 --- a/cumulus/Cargo.lock +++ b/cumulus/Cargo.lock @@ -5740,6 +5740,21 @@ dependencies = [ "sp-std", ] +[[package]] +name = "pallet-template" +version = "0.1.0" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "parity-scale-codec", + "scale-info", + "serde", + "sp-core", + "sp-io", + "sp-runtime", +] + [[package]] name = "pallet-timestamp" version = "4.0.0-dev" @@ -5914,6 +5929,123 @@ dependencies = [ "serde", ] +[[package]] +name = "parachain-template-node" +version = "0.1.0" +dependencies = [ + "cumulus-client-cli", + "cumulus-client-collator", + "cumulus-client-consensus-aura", + "cumulus-client-consensus-common", + "cumulus-client-network", + "cumulus-client-service", + "cumulus-primitives-core", + "cumulus-primitives-parachain-inherent", + "derive_more", + "frame-benchmarking", + "frame-benchmarking-cli", + "hex-literal 0.3.3", + "jsonrpc-core", + "log", + "pallet-transaction-payment-rpc", + "parachain-template-runtime", + "parity-scale-codec", + "polkadot-cli", + "polkadot-parachain", + "polkadot-primitives", + "polkadot-service", + "polkadot-test-service", + "sc-basic-authorship", + "sc-chain-spec", + "sc-cli", + "sc-client-api", + "sc-consensus", + "sc-executor", + "sc-keystore", + "sc-network", + "sc-rpc", + "sc-rpc-api", + "sc-service", + "sc-telemetry", + "sc-tracing", + "sc-transaction-pool", + "sc-transaction-pool-api", + "serde", + "sp-api", + "sp-block-builder", + "sp-blockchain", + "sp-consensus", + "sp-consensus-aura", + "sp-core", + "sp-inherents", + "sp-keystore", + "sp-offchain", + "sp-runtime", + "sp-session", + "sp-timestamp", + "sp-transaction-pool", + "structopt", + "substrate-build-script-utils", + "substrate-frame-rpc-system", + "substrate-prometheus-endpoint", +] + +[[package]] +name = "parachain-template-runtime" +version = "0.1.0" +dependencies = [ + "cumulus-pallet-aura-ext", + "cumulus-pallet-dmp-queue", + "cumulus-pallet-parachain-system", + "cumulus-pallet-xcm", + "cumulus-pallet-xcmp-queue", + "cumulus-primitives-core", + "cumulus-primitives-timestamp", + "cumulus-primitives-utility", + "frame-benchmarking", + "frame-executive", + "frame-support", + "frame-system", + "frame-system-benchmarking", + "frame-system-rpc-runtime-api", + "log", + "pallet-aura", + "pallet-authorship", + "pallet-balances", + "pallet-collator-selection", + "pallet-randomness-collective-flip", + "pallet-session", + "pallet-sudo", + "pallet-template", + "pallet-timestamp", + "pallet-transaction-payment", + "pallet-transaction-payment-rpc-runtime-api", + "pallet-xcm", + "parachain-info", + "parity-scale-codec", + "polkadot-parachain", + "polkadot-runtime-common", + "scale-info", + "serde", + "smallvec", + "sp-api", + "sp-block-builder", + "sp-consensus-aura", + "sp-core", + "sp-inherents", + "sp-io", + "sp-offchain", + "sp-runtime", + "sp-session", + "sp-std", + "sp-transaction-pool", + "sp-version", + "substrate-wasm-builder", + "xcm", + "xcm-builder", + "xcm-executor", +] + [[package]] name = "parachains-common" version = "1.0.0" diff --git a/cumulus/Cargo.toml b/cumulus/Cargo.toml index 7917dc11817..e7ef9070081 100644 --- a/cumulus/Cargo.toml +++ b/cumulus/Cargo.toml @@ -15,6 +15,8 @@ members = [ "pallets/session-benchmarking", "pallets/xcm", "pallets/xcmp-queue", + "parachain-template/node", + "parachain-template/runtime", "primitives/core", "primitives/parachain-inherent", "primitives/timestamp", @@ -28,12 +30,12 @@ members = [ "polkadot-parachains/statemint", "polkadot-parachains/statemine", "polkadot-parachains/westmint", - "test/runtime", - "test/runtime-upgrade", "test/client", - "test/service", "test/relay-sproof-builder", "test/relay-validation-worker-provider", + "test/runtime", + "test/runtime-upgrade", + "test/service", ] [profile.release] diff --git a/cumulus/parachain-template/LICENSE b/cumulus/parachain-template/LICENSE new file mode 100644 index 00000000000..cf1ab25da03 --- /dev/null +++ b/cumulus/parachain-template/LICENSE @@ -0,0 +1,24 @@ +This is free and unencumbered software released into the public domain. + +Anyone is free to copy, modify, publish, use, compile, sell, or +distribute this software, either in source code form or as a compiled +binary, for any purpose, commercial or non-commercial, and by any +means. + +In jurisdictions that recognize copyright laws, the author or authors +of this software dedicate any and all copyright interest in the +software to the public domain. We make this dedication for the benefit +of the public at large and to the detriment of our heirs and +successors. We intend this dedication to be an overt act of +relinquishment in perpetuity of all present and future rights to this +software under copyright law. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +For more information, please refer to <http://unlicense.org> diff --git a/cumulus/parachain-template/README.md b/cumulus/parachain-template/README.md new file mode 100644 index 00000000000..1580521ccd8 --- /dev/null +++ b/cumulus/parachain-template/README.md @@ -0,0 +1,14 @@ +# Substrate Cumulus Parachain Template + +A new [Cumulus](https://github.com/paritytech/cumulus/)-based Substrate node, ready for hacking â˜ï¸.. + +This project is a fork of the [Substrate Node Template](https://github.com/substrate-developer-hub/substrate-node-template) +modified to include dependencies required for registering this node as a **parathread** or +**parachain** to the Rococo **relay chain**. +Rococo is [Polkadot's parachain testnet](https://polkadot.network/blog/introducing-rococo-polkadots-parachain-testnet/) 👑. + +👉 Learn more about parachains [here](https://wiki.polkadot.network/docs/learn-parachains), and +parathreads [here](https://wiki.polkadot.network/docs/learn-parathreads). + +To learn about how to actually use the template to hack together your own parachain check out the +`README` from the [`substrate-parachain-template` repository](https://github.com/substrate-developer-hub/substrate-parachain-template/). diff --git a/cumulus/parachain-template/node/Cargo.toml b/cumulus/parachain-template/node/Cargo.toml new file mode 100644 index 00000000000..605f7a912fb --- /dev/null +++ b/cumulus/parachain-template/node/Cargo.toml @@ -0,0 +1,95 @@ +[package] +name = "parachain-template-node" +version = "0.1.0" +authors = ["Anonymous"] +description = "A new Cumulus FRAME-based Substrate Node, ready for hacking together a parachain." +license = "Unlicense" +homepage = "https://substrate.dev" +repository = "https://github.com/paritytech/cumulus/" +edition = "2018" +build = "build.rs" + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[build-dependencies] +substrate-build-script-utils = { git = "https://github.com/paritytech/substrate", branch = "master" } + +[[bin]] +name = "parachain-collator" +path = "src/main.rs" + +[features] +runtime-benchmarks = ["parachain-template-runtime/runtime-benchmarks"] + +[dependencies] +derive_more = "0.99.2" +log = "0.4.14" +codec = { package = "parity-scale-codec", version = "2.0.0" } +structopt = "0.3.8" +serde = { version = "1.0.119", features = ["derive"] } +hex-literal = "0.3.1" + +# RPC related Dependencies +jsonrpc-core = "18.0.0" + +# Local Dependencies +parachain-template-runtime = { path = "../runtime" } + +# Substrate Dependencies +frame-benchmarking = { git = "https://github.com/paritytech/substrate", branch = "master" } +frame-benchmarking-cli = { git = "https://github.com/paritytech/substrate", branch = "master" } + +pallet-transaction-payment-rpc = { git = "https://github.com/paritytech/substrate", branch = "master" } + +substrate-frame-rpc-system = { git = "https://github.com/paritytech/substrate", branch = "master" } +substrate-prometheus-endpoint = { git = "https://github.com/paritytech/substrate", branch = "master" } + +## Substrate Client Dependencies +sc-basic-authorship = { git = "https://github.com/paritytech/substrate", branch = "master" } +sc-chain-spec = { git = "https://github.com/paritytech/substrate", branch = "master" } +sc-cli = { git = "https://github.com/paritytech/substrate", branch = "master" } +sc-client-api = { git = "https://github.com/paritytech/substrate", branch = "master" } +sc-consensus = { git = "https://github.com/paritytech/substrate", branch = "master" } +sc-executor = { git = "https://github.com/paritytech/substrate", branch = "master" } +sc-network = { git = "https://github.com/paritytech/substrate", branch = "master" } +sc-keystore = { git = "https://github.com/paritytech/substrate", branch = "master" } +sc-rpc = { git = "https://github.com/paritytech/substrate", branch = "master" } +sc-rpc-api = { git = "https://github.com/paritytech/substrate", branch = "master" } +sc-service = { git = "https://github.com/paritytech/substrate", features = ["wasmtime"] , branch = "master" } +sc-telemetry = { git = "https://github.com/paritytech/substrate", branch = "master" } +sc-transaction-pool = { git = "https://github.com/paritytech/substrate", branch = "master" } +sc-transaction-pool-api = { git = "https://github.com/paritytech/substrate", branch = "master" } +sc-tracing = { git = "https://github.com/paritytech/substrate", branch = "master" } + +## Substrate Primitive Dependencies +sp-api = { git = "https://github.com/paritytech/substrate", branch = "master" } +sp-block-builder = { git = "https://github.com/paritytech/substrate", branch = "master" } +sp-blockchain = { git = "https://github.com/paritytech/substrate", branch = "master" } +sp-consensus = { git = "https://github.com/paritytech/substrate", branch = "master" } +sp-consensus-aura = { git = "https://github.com/paritytech/substrate", branch = "master" } +sp-core = { git = "https://github.com/paritytech/substrate", branch = "master" } +sp-inherents = { git = "https://github.com/paritytech/substrate", branch = "master" } +sp-keystore = { git = "https://github.com/paritytech/substrate", branch = "master" } +sp-offchain = { git = "https://github.com/paritytech/substrate", branch = "master" } +sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master" } +sp-session = { git = "https://github.com/paritytech/substrate", branch = "master" } +sp-timestamp = { git = "https://github.com/paritytech/substrate", branch = "master" } +sp-transaction-pool = { git = "https://github.com/paritytech/substrate", branch = "master" } + +# Cumulus dependencies +cumulus-client-cli = { path = "../../client/cli" } +cumulus-client-collator = { path = "../../client/collator" } +cumulus-client-consensus-aura = { path = "../../client/consensus/aura" } +cumulus-client-consensus-common = { path = "../../client/consensus/common" } +cumulus-client-network = { path = "../../client/network" } +cumulus-client-service = { path = "../../client/service" } +cumulus-primitives-core = { path = "../../primitives/core" } +cumulus-primitives-parachain-inherent = { path = "../../primitives/parachain-inherent" } + +# Polkadot dependencies +polkadot-cli = { git = "https://github.com/paritytech/polkadot", branch = "master" } +polkadot-parachain = { git = "https://github.com/paritytech/polkadot", branch = "master" } +polkadot-primitives = { git = "https://github.com/paritytech/polkadot", branch = "master" } +polkadot-service = { git = "https://github.com/paritytech/polkadot", branch = "master" } +polkadot-test-service = { git = "https://github.com/paritytech/polkadot", branch = "master" } diff --git a/cumulus/parachain-template/node/build.rs b/cumulus/parachain-template/node/build.rs new file mode 100644 index 00000000000..e3bfe3116bf --- /dev/null +++ b/cumulus/parachain-template/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/cumulus/parachain-template/node/src/chain_spec.rs b/cumulus/parachain-template/node/src/chain_spec.rs new file mode 100644 index 00000000000..1609bfb06c6 --- /dev/null +++ b/cumulus/parachain-template/node/src/chain_spec.rs @@ -0,0 +1,214 @@ +use cumulus_primitives_core::ParaId; +use parachain_template_runtime::{AccountId, AuraId, Signature, EXISTENTIAL_DEPOSIT}; +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}; + +/// Specialized `ChainSpec` for the normal parachain runtime. +pub type ChainSpec = + sc_service::GenericChainSpec<parachain_template_runtime::GenesisConfig, Extensions>; + +/// Helper function to generate a crypto pair from seed +pub fn get_pair_from_seed<TPublic: Public>(seed: &str) -> <TPublic::Pair as Pair>::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 = <Signature as Verify>::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_pair_from_seed::<AuraId>(seed) +} + +/// Helper function to generate an account ID from seed +pub fn get_account_id_from_seed<TPublic: Public>(seed: &str) -> AccountId +where + AccountPublic: From<<TPublic::Pair as Pair>::Public>, +{ + AccountPublic::from(get_pair_from_seed::<TPublic>(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 template_session_keys(keys: AuraId) -> parachain_template_runtime::SessionKeys { + parachain_template_runtime::SessionKeys { aura: keys } +} + +pub fn development_config(id: ParaId) -> ChainSpec { + // Give your base currency a unit name and decimal places + let mut properties = sc_chain_spec::Properties::new(); + properties.insert("tokenSymbol".into(), "ROC".into()); + properties.insert("tokenDecimals".into(), 12.into()); + properties.insert("ss58Format".into(), 42.into()); + + ChainSpec::from_genesis( + // Name + "Development", + // ID + "dev", + ChainType::Development, + move || { + testnet_genesis( + // initial collators. + vec![ + ( + get_account_id_from_seed::<sr25519::Public>("Alice"), + get_collator_keys_from_seed("Alice"), + ), + ( + get_account_id_from_seed::<sr25519::Public>("Bob"), + get_collator_keys_from_seed("Bob"), + ), + ], + vec![ + get_account_id_from_seed::<sr25519::Public>("Alice"), + get_account_id_from_seed::<sr25519::Public>("Bob"), + get_account_id_from_seed::<sr25519::Public>("Charlie"), + get_account_id_from_seed::<sr25519::Public>("Dave"), + get_account_id_from_seed::<sr25519::Public>("Eve"), + get_account_id_from_seed::<sr25519::Public>("Ferdie"), + get_account_id_from_seed::<sr25519::Public>("Alice//stash"), + get_account_id_from_seed::<sr25519::Public>("Bob//stash"), + get_account_id_from_seed::<sr25519::Public>("Charlie//stash"), + get_account_id_from_seed::<sr25519::Public>("Dave//stash"), + get_account_id_from_seed::<sr25519::Public>("Eve//stash"), + get_account_id_from_seed::<sr25519::Public>("Ferdie//stash"), + ], + id, + ) + }, + vec![], + None, + None, + None, + Extensions { + relay_chain: "rococo-local".into(), // You MUST set this to the correct network! + para_id: id.into(), + }, + ) +} + +pub fn local_testnet_config(id: ParaId) -> ChainSpec { + // Give your base currency a unit name and decimal places + let mut properties = sc_chain_spec::Properties::new(); + properties.insert("tokenSymbol".into(), "ROC".into()); + properties.insert("tokenDecimals".into(), 12.into()); + properties.insert("ss58Format".into(), 42.into()); + + ChainSpec::from_genesis( + // Name + "Local Testnet", + // ID + "local_testnet", + ChainType::Local, + move || { + testnet_genesis( + // initial collators. + vec![ + ( + get_account_id_from_seed::<sr25519::Public>("Alice"), + get_collator_keys_from_seed("Alice"), + ), + ( + get_account_id_from_seed::<sr25519::Public>("Bob"), + get_collator_keys_from_seed("Bob"), + ), + ], + vec![ + get_account_id_from_seed::<sr25519::Public>("Alice"), + get_account_id_from_seed::<sr25519::Public>("Bob"), + get_account_id_from_seed::<sr25519::Public>("Charlie"), + get_account_id_from_seed::<sr25519::Public>("Dave"), + get_account_id_from_seed::<sr25519::Public>("Eve"), + get_account_id_from_seed::<sr25519::Public>("Ferdie"), + get_account_id_from_seed::<sr25519::Public>("Alice//stash"), + get_account_id_from_seed::<sr25519::Public>("Bob//stash"), + get_account_id_from_seed::<sr25519::Public>("Charlie//stash"), + get_account_id_from_seed::<sr25519::Public>("Dave//stash"), + get_account_id_from_seed::<sr25519::Public>("Eve//stash"), + get_account_id_from_seed::<sr25519::Public>("Ferdie//stash"), + ], + id, + ) + }, + // Bootnodes + vec![], + // Telemetry + None, + // Protocol ID + Some("template-local"), + // Properties + Some(properties), + // Extensions + Extensions { + relay_chain: "rococo-local".into(), // You MUST set this to the correct network! + para_id: id.into(), + }, + ) +} + +fn testnet_genesis( + invulnerables: Vec<(AccountId, AuraId)>, + endowed_accounts: Vec<AccountId>, + id: ParaId, +) -> parachain_template_runtime::GenesisConfig { + parachain_template_runtime::GenesisConfig { + system: parachain_template_runtime::SystemConfig { + code: parachain_template_runtime::WASM_BINARY + .expect("WASM binary was not build, please build it!") + .to_vec(), + changes_trie_config: Default::default(), + }, + balances: parachain_template_runtime::BalancesConfig { + balances: endowed_accounts.iter().cloned().map(|k| (k, 1 << 60)).collect(), + }, + parachain_info: parachain_template_runtime::ParachainInfoConfig { parachain_id: id }, + collator_selection: parachain_template_runtime::CollatorSelectionConfig { + invulnerables: invulnerables.iter().cloned().map(|(acc, _)| acc).collect(), + candidacy_bond: EXISTENTIAL_DEPOSIT * 16, + ..Default::default() + }, + session: parachain_template_runtime::SessionConfig { + keys: invulnerables + .iter() + .cloned() + .map(|(acc, aura)| { + ( + acc.clone(), // account id + acc, // validator id + template_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(), + } +} diff --git a/cumulus/parachain-template/node/src/cli.rs b/cumulus/parachain-template/node/src/cli.rs new file mode 100644 index 00000000000..319893a0c79 --- /dev/null +++ b/cumulus/parachain-template/node/src/cli.rs @@ -0,0 +1,121 @@ +use crate::chain_spec; +use std::path::PathBuf; +use structopt::StructOpt; + +/// Sub-commands supported by the collator. +#[derive(Debug, StructOpt)] +pub enum Subcommand { + /// Export the genesis state of the parachain. + #[structopt(name = "export-genesis-state")] + ExportGenesisState(ExportGenesisStateCommand), + + /// Export the genesis wasm of the parachain. + #[structopt(name = "export-genesis-wasm")] + ExportGenesisWasm(ExportGenesisWasmCommand), + + /// 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), + + /// Remove the whole chain. + PurgeChain(cumulus_client_cli::PurgeChainCmd), + + /// Revert the chain to a previous state. + Revert(sc_cli::RevertCmd), + + /// The custom benchmark subcommmand benchmarking runtime pallets. + #[structopt(name = "benchmark", about = "Benchmark runtime pallets.")] + Benchmark(frame_benchmarking_cli::BenchmarkCmd), +} + +/// Command for exporting the genesis state of the parachain +#[derive(Debug, StructOpt)] +pub struct ExportGenesisStateCommand { + /// Output file name or stdout if unspecified. + #[structopt(parse(from_os_str))] + pub output: Option<PathBuf>, + + /// Id of the parachain this state is for. + /// + /// Default: 100 + #[structopt(long, conflicts_with = "chain")] + pub parachain_id: Option<u32>, + + /// Write output in binary. Default is to write in hex. + #[structopt(short, long)] + pub raw: bool, + + /// The name of the chain for that the genesis state should be exported. + #[structopt(long, conflicts_with = "parachain-id")] + pub chain: Option<String>, +} + +/// Command for exporting the genesis wasm file. +#[derive(Debug, StructOpt)] +pub struct ExportGenesisWasmCommand { + /// Output file name or stdout if unspecified. + #[structopt(parse(from_os_str))] + pub output: Option<PathBuf>, + + /// Write output in binary. Default is to write in hex. + #[structopt(short, long)] + pub raw: bool, + + /// The name of the chain for that the genesis wasm file should be exported. + #[structopt(long)] + pub chain: Option<String>, +} + +#[derive(Debug, StructOpt)] +#[structopt(settings = &[ + structopt::clap::AppSettings::GlobalVersion, + structopt::clap::AppSettings::ArgsNegateSubcommands, + structopt::clap::AppSettings::SubcommandsNegateReqs, +])] +pub struct Cli { + #[structopt(subcommand)] + pub subcommand: Option<Subcommand>, + + #[structopt(flatten)] + pub run: cumulus_client_cli::RunCmd, + + /// Relaychain arguments + #[structopt(raw = true)] + pub relaychain_args: Vec<String>, +} + +#[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<String>, + + /// The base path that should be used by the relay chain. + pub base_path: Option<PathBuf>, +} + +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<Item = &'a String>, + ) -> Self { + let extension = 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: polkadot_cli::RunCmd::from_iter(relay_chain_args) } + } +} diff --git a/cumulus/parachain-template/node/src/command.rs b/cumulus/parachain-template/node/src/command.rs new file mode 100644 index 00000000000..e09fee29d97 --- /dev/null +++ b/cumulus/parachain-template/node/src/command.rs @@ -0,0 +1,405 @@ +use crate::{ + chain_spec, + cli::{Cli, RelayChainCli, Subcommand}, + service::{new_partial, TemplateRuntimeExecutor}, +}; +use codec::Encode; +use cumulus_client_service::genesis::generate_genesis_block; +use cumulus_primitives_core::ParaId; +use log::info; +use parachain_template_runtime::{Block, RuntimeApi}; +use polkadot_parachain::primitives::AccountIdConversion; +use sc_cli::{ + ChainSpec, CliConfiguration, DefaultConfigurationValues, ImportParams, KeystoreParams, + NetworkParams, Result, RuntimeVersion, SharedParams, SubstrateCli, +}; +use sc_service::config::{BasePath, PrometheusConfig}; +use sp_core::hexdisplay::HexDisplay; +use sp_runtime::traits::Block as BlockT; +use std::{io::Write, net::SocketAddr}; + +fn load_spec( + id: &str, + para_id: ParaId, +) -> std::result::Result<Box<dyn sc_service::ChainSpec>, String> { + Ok(match id { + "dev" => Box::new(chain_spec::development_config(para_id)), + "template-rococo" => Box::new(chain_spec::local_testnet_config(para_id)), + "" | "local" => Box::new(chain_spec::local_testnet_config(para_id)), + path => Box::new(chain_spec::ChainSpec::from_json_file(std::path::PathBuf::from(path))?), + }) +} + +impl SubstrateCli for Cli { + fn impl_name() -> String { + "Parachain Collator Template".into() + } + + fn impl_version() -> String { + env!("SUBSTRATE_CLI_IMPL_VERSION").into() + } + + fn description() -> String { + format!( + "Parachain Collator Template\n\nThe command-line arguments provided first will be \ + passed to the parachain node, while the arguments provided after -- will be passed \ + to the relaychain node.\n\n\ + {} [parachain-args] -- [relaychain-args]", + Self::executable_name() + ) + } + + fn author() -> String { + env!("CARGO_PKG_AUTHORS").into() + } + + fn support_url() -> String { + "https://github.com/paritytech/cumulus/issues/new".into() + } + + fn copyright_start_year() -> i32 { + 2020 + } + + fn load_spec(&self, id: &str) -> std::result::Result<Box<dyn sc_service::ChainSpec>, String> { + load_spec(id, self.run.parachain_id.unwrap_or(2000).into()) + } + + fn native_runtime_version(_: &Box<dyn ChainSpec>) -> &'static RuntimeVersion { + ¶chain_template_runtime::VERSION + } +} + +impl SubstrateCli for RelayChainCli { + fn impl_name() -> String { + "Parachain Collator Template".into() + } + + fn impl_version() -> String { + env!("SUBSTRATE_CLI_IMPL_VERSION").into() + } + + fn description() -> String { + "Parachain Collator Template\n\nThe command-line arguments provided first will be \ + passed to the parachain node, while the arguments provided after -- will be passed \ + to the relaychain node.\n\n\ + parachain-collator [parachain-args] -- [relaychain-args]" + .into() + } + + fn author() -> String { + env!("CARGO_PKG_AUTHORS").into() + } + + fn support_url() -> String { + "https://github.com/paritytech/cumulus/issues/new".into() + } + + fn copyright_start_year() -> i32 { + 2020 + } + + fn load_spec(&self, id: &str) -> std::result::Result<Box<dyn sc_service::ChainSpec>, String> { + polkadot_cli::Cli::from_iter([RelayChainCli::executable_name()].iter()).load_spec(id) + } + + fn native_runtime_version(chain_spec: &Box<dyn ChainSpec>) -> &'static RuntimeVersion { + polkadot_cli::Cli::native_runtime_version(chain_spec) + } +} + +#[allow(clippy::borrowed_box)] +fn extract_genesis_wasm(chain_spec: &Box<dyn sc_service::ChainSpec>) -> Result<Vec<u8>> { + let mut storage = chain_spec.build_storage()?; + + storage + .top + .remove(sp_core::storage::well_known_keys::CODE) + .ok_or_else(|| "Could not find wasm file in genesis state!".into()) +} + +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, + TemplateRuntimeExecutor, + _ + >( + &$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::PurgeChain(cmd)) => { + let runner = cli.create_runner(cmd)?; + + runner.sync_run(|config| { + let polkadot_cli = RelayChainCli::new( + &config, + [RelayChainCli::executable_name()].iter().chain(cli.relaychain_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::Revert(cmd)) => { + construct_async_run!(|components, cli, cmd, config| { + Ok(cmd.run(components.client, components.backend)) + }) + }, + Some(Subcommand::ExportGenesisState(params)) => { + let mut builder = sc_cli::LoggerBuilder::new(""); + builder.with_profiling(sc_tracing::TracingReceiver::Log, ""); + let _ = builder.init(); + + let block: Block = generate_genesis_block(&load_spec( + ¶ms.chain.clone().unwrap_or_default(), + params.parachain_id.unwrap_or(2000).into(), + )?)?; + let raw_header = block.header().encode(); + let output_buf = if params.raw { + raw_header + } else { + format!("0x{:?}", HexDisplay::from(&block.header().encode())).into_bytes() + }; + + if let Some(output) = ¶ms.output { + std::fs::write(output, output_buf)?; + } else { + std::io::stdout().write_all(&output_buf)?; + } + + Ok(()) + }, + Some(Subcommand::ExportGenesisWasm(params)) => { + let mut builder = sc_cli::LoggerBuilder::new(""); + builder.with_profiling(sc_tracing::TracingReceiver::Log, ""); + let _ = builder.init(); + + let raw_wasm_blob = + extract_genesis_wasm(&cli.load_spec(¶ms.chain.clone().unwrap_or_default())?)?; + let output_buf = if params.raw { + raw_wasm_blob + } else { + format!("0x{:?}", HexDisplay::from(&raw_wasm_blob)).into_bytes() + }; + + if let Some(output) = ¶ms.output { + std::fs::write(output, output_buf)?; + } else { + std::io::stdout().write_all(&output_buf)?; + } + + Ok(()) + }, + Some(Subcommand::Benchmark(cmd)) => + if cfg!(feature = "runtime-benchmarks") { + let runner = cli.create_runner(cmd)?; + + runner.sync_run(|config| cmd.run::<Block, TemplateRuntimeExecutor>(config)) + } else { + Err("Benchmarking wasn't enabled when building the node. \ + You can enable it with `--features runtime-benchmarks`." + .into()) + }, + None => { + let runner = cli.create_runner(&cli.run.normalize())?; + + runner.run_node_until_exit(|config| async move { + let para_id = + chain_spec::Extensions::try_get(&*config.chain_spec).map(|e| e.para_id); + + let polkadot_cli = RelayChainCli::new( + &config, + [RelayChainCli::executable_name()].iter().chain(cli.relaychain_args.iter()), + ); + + let id = ParaId::from(cli.run.parachain_id.or(para_id).unwrap_or(2000)); + + let parachain_account = + AccountIdConversion::<polkadot_primitives::v0::AccountId>::into_account(&id); + + let block: Block = + generate_genesis_block(&config.chain_spec).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, id) + .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<Self> 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<Option<BasePath>> { + Ok(self + .shared_params() + .base_path() + .or_else(|| self.base_path.clone().map(Into::into))) + } + + fn rpc_http(&self, default_listen_port: u16) -> Result<Option<SocketAddr>> { + self.base.base.rpc_http(default_listen_port) + } + + fn rpc_ipc(&self) -> Result<Option<String>> { + self.base.base.rpc_ipc() + } + + fn rpc_ws(&self, default_listen_port: u16) -> Result<Option<SocketAddr>> { + self.base.base.rpc_ws(default_listen_port) + } + + fn prometheus_config(&self, default_listen_port: u16) -> Result<Option<PrometheusConfig>> { + self.base.base.prometheus_config(default_listen_port) + } + + fn init<C: SubstrateCli>(&self) -> Result<()> { + unreachable!("PolkadotCli is never initialized; qed"); + } + + fn chain_id(&self, is_dev: bool) -> Result<String> { + 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<sc_service::Role> { + self.base.base.role(is_dev) + } + + fn transaction_pool(&self) -> Result<sc_service::config::TransactionPoolOptions> { + self.base.base.transaction_pool() + } + + fn state_cache_child_ratio(&self) -> Result<Option<usize>> { + self.base.base.state_cache_child_ratio() + } + + fn rpc_methods(&self) -> Result<sc_service::config::RpcMethods> { + self.base.base.rpc_methods() + } + + fn rpc_ws_max_connections(&self) -> Result<Option<usize>> { + self.base.base.rpc_ws_max_connections() + } + + fn rpc_cors(&self, is_dev: bool) -> Result<Option<Vec<String>>> { + self.base.base.rpc_cors(is_dev) + } + + fn default_heap_pages(&self) -> Result<Option<u64>> { + self.base.base.default_heap_pages() + } + + fn force_authoring(&self) -> Result<bool> { + self.base.base.force_authoring() + } + + fn disable_grandpa(&self) -> Result<bool> { + self.base.base.disable_grandpa() + } + + fn max_runtime_instances(&self) -> Result<Option<usize>> { + self.base.base.max_runtime_instances() + } + + fn announce_block(&self) -> Result<bool> { + self.base.base.announce_block() + } + + fn telemetry_endpoints( + &self, + chain_spec: &Box<dyn ChainSpec>, + ) -> Result<Option<sc_telemetry::TelemetryEndpoints>> { + self.base.base.telemetry_endpoints(chain_spec) + } +} diff --git a/cumulus/parachain-template/node/src/main.rs b/cumulus/parachain-template/node/src/main.rs new file mode 100644 index 00000000000..99dc7849cf6 --- /dev/null +++ b/cumulus/parachain-template/node/src/main.rs @@ -0,0 +1,14 @@ +//! Substrate Node CLI library. + +#![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/cumulus/parachain-template/node/src/rpc.rs b/cumulus/parachain-template/node/src/rpc.rs new file mode 100644 index 00000000000..5d3dd817c8a --- /dev/null +++ b/cumulus/parachain-template/node/src/rpc.rs @@ -0,0 +1,57 @@ +//! 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_template_runtime::{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 = jsonrpc_core::IoHandler<sc_rpc::Metadata>; + +/// Full client dependencies +pub struct FullDeps<C, P> { + /// The client instance to use. + pub client: Arc<C>, + /// Transaction pool instance. + pub pool: Arc<P>, + /// Whether to deny unsafe calls + pub deny_unsafe: DenyUnsafe, +} + +/// Instantiate all RPC extensions. +pub fn create_full<C, P>(deps: FullDeps<C, P>) -> RpcExtension +where + C: ProvideRuntimeApi<Block> + + HeaderBackend<Block> + + AuxStore + + HeaderMetadata<Block, Error = BlockChainError> + + Send + + Sync + + 'static, + C::Api: pallet_transaction_payment_rpc::TransactionPaymentRuntimeApi<Block, Balance>, + C::Api: substrate_frame_rpc_system::AccountNonceApi<Block, AccountId, Nonce>, + C::Api: BlockBuilder<Block>, + P: TransactionPool + Sync + Send + 'static, +{ + use pallet_transaction_payment_rpc::{TransactionPayment, TransactionPaymentApi}; + use substrate_frame_rpc_system::{FullSystem, SystemApi}; + + let mut io = jsonrpc_core::IoHandler::default(); + let FullDeps { client, pool, deny_unsafe } = deps; + + io.extend_with(SystemApi::to_delegate(FullSystem::new(client.clone(), pool, deny_unsafe))); + io.extend_with(TransactionPaymentApi::to_delegate(TransactionPayment::new(client))); + + io +} diff --git a/cumulus/parachain-template/node/src/service.rs b/cumulus/parachain-template/node/src/service.rs new file mode 100644 index 00000000000..ff11038ad0f --- /dev/null +++ b/cumulus/parachain-template/node/src/service.rs @@ -0,0 +1,492 @@ +//! Service and ServiceFactory implementation. Specialized wrapper over substrate service. + +// std +use std::sync::Arc; + +// Local Runtime Types +use parachain_template_runtime::{ + opaque::Block, AccountId, Balance, Hash, Index as Nonce, RuntimeApi, +}; + +// Cumulus Imports +use cumulus_client_consensus_aura::{ + build_aura_consensus, BuildAuraConsensusParams, SlotProportion, +}; +use cumulus_client_consensus_common::ParachainConsensus; +use cumulus_client_network::build_block_announce_validator; +use cumulus_client_service::{ + prepare_node_config, start_collator, start_full_node, StartCollatorParams, StartFullNodeParams, +}; +use cumulus_primitives_core::ParaId; + +// 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_consensus::SlotData; +use sp_keystore::SyncCryptoStorePtr; +use sp_runtime::traits::BlakeTwo256; +use substrate_prometheus_endpoint::Registry; + +/// Native executor instance. +pub struct TemplateRuntimeExecutor; + +impl sc_executor::NativeExecutionDispatch for TemplateRuntimeExecutor { + type ExtendHostFunctions = frame_benchmarking::benchmarking::HostFunctions; + + fn dispatch(method: &str, data: &[u8]) -> Option<Vec<u8>> { + parachain_template_runtime::api::dispatch(method, data) + } + + fn native_version() -> sc_executor::NativeVersion { + parachain_template_runtime::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<RuntimeApi, Executor, BIQ>( + config: &Configuration, + build_import_queue: BIQ, +) -> Result< + PartialComponents< + TFullClient<Block, RuntimeApi, NativeElseWasmExecutor<Executor>>, + TFullBackend<Block>, + (), + sc_consensus::DefaultImportQueue< + Block, + TFullClient<Block, RuntimeApi, NativeElseWasmExecutor<Executor>>, + >, + sc_transaction_pool::FullPool< + Block, + TFullClient<Block, RuntimeApi, NativeElseWasmExecutor<Executor>>, + >, + (Option<Telemetry>, Option<TelemetryWorkerHandle>), + >, + sc_service::Error, +> +where + RuntimeApi: ConstructRuntimeApi<Block, TFullClient<Block, RuntimeApi, NativeElseWasmExecutor<Executor>>> + + Send + + Sync + + 'static, + RuntimeApi::RuntimeApi: sp_transaction_pool::runtime_api::TaggedTransactionQueue<Block> + + sp_api::Metadata<Block> + + sp_session::SessionKeys<Block> + + sp_api::ApiExt< + Block, + StateBackend = sc_client_api::StateBackendFor<TFullBackend<Block>, Block>, + > + sp_offchain::OffchainWorkerApi<Block> + + sp_block_builder::BlockBuilder<Block>, + sc_client_api::StateBackendFor<TFullBackend<Block>, Block>: sp_api::StateBackend<BlakeTwo256>, + Executor: sc_executor::NativeExecutionDispatch + 'static, + BIQ: FnOnce( + Arc<TFullClient<Block, RuntimeApi, NativeElseWasmExecutor<Executor>>>, + &Configuration, + Option<TelemetryHandle>, + &TaskManager, + ) -> Result< + sc_consensus::DefaultImportQueue< + Block, + TFullClient<Block, RuntimeApi, NativeElseWasmExecutor<Executor>>, + >, + 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::<Executor>::new( + config.wasm_method, + config.default_heap_pages, + config.max_runtime_instances, + ); + + let (client, backend, keystore_container, task_manager) = + sc_service::new_full_parts::<Block, RuntimeApi, _>( + 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", 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) +} + +/// 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<RuntimeApi, Executor, RB, BIQ, BIC>( + parachain_config: Configuration, + polkadot_config: Configuration, + id: ParaId, + _rpc_ext_builder: RB, + build_import_queue: BIQ, + build_consensus: BIC, +) -> sc_service::error::Result<( + TaskManager, + Arc<TFullClient<Block, RuntimeApi, NativeElseWasmExecutor<Executor>>>, +)> +where + RuntimeApi: ConstructRuntimeApi<Block, TFullClient<Block, RuntimeApi, NativeElseWasmExecutor<Executor>>> + + Send + + Sync + + 'static, + RuntimeApi::RuntimeApi: sp_transaction_pool::runtime_api::TaggedTransactionQueue<Block> + + sp_api::Metadata<Block> + + sp_session::SessionKeys<Block> + + sp_api::ApiExt< + Block, + StateBackend = sc_client_api::StateBackendFor<TFullBackend<Block>, Block>, + > + sp_offchain::OffchainWorkerApi<Block> + + sp_block_builder::BlockBuilder<Block> + + cumulus_primitives_core::CollectCollationInfo<Block> + + pallet_transaction_payment_rpc::TransactionPaymentRuntimeApi<Block, Balance> + + substrate_frame_rpc_system::AccountNonceApi<Block, AccountId, Nonce>, + sc_client_api::StateBackendFor<TFullBackend<Block>, Block>: sp_api::StateBackend<BlakeTwo256>, + Executor: sc_executor::NativeExecutionDispatch + 'static, + RB: Fn( + Arc<TFullClient<Block, RuntimeApi, Executor>>, + ) -> Result<jsonrpc_core::IoHandler<sc_rpc::Metadata>, sc_service::Error> + + Send + + 'static, + BIQ: FnOnce( + Arc<TFullClient<Block, RuntimeApi, NativeElseWasmExecutor<Executor>>>, + &Configuration, + Option<TelemetryHandle>, + &TaskManager, + ) -> Result< + sc_consensus::DefaultImportQueue< + Block, + TFullClient<Block, RuntimeApi, NativeElseWasmExecutor<Executor>>, + >, + sc_service::Error, + > + 'static, + BIC: FnOnce( + Arc<TFullClient<Block, RuntimeApi, NativeElseWasmExecutor<Executor>>>, + Option<&Registry>, + Option<TelemetryHandle>, + &TaskManager, + &polkadot_service::NewFull<polkadot_service::Client>, + Arc< + sc_transaction_pool::FullPool< + Block, + TFullClient<Block, RuntimeApi, NativeElseWasmExecutor<Executor>>, + >, + >, + Arc<NetworkService<Block, Hash>>, + SyncCryptoStorePtr, + bool, + ) -> Result<Box<dyn ParachainConsensus<Block>>, 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::<RuntimeApi, Executor, BIQ>(¶chain_config, build_import_queue)?; + let (mut telemetry, telemetry_worker_handle) = params.other; + + let relay_chain_full_node = + cumulus_client_service::build_polkadot_full_node(polkadot_config, telemetry_worker_handle) + .map_err(|e| match e { + polkadot_service::Error::Sub(x) => x, + s => format!("{}", s).into(), + })?; + + let client = params.client.clone(); + let backend = params.backend.clone(); + let block_announce_validator = build_block_announce_validator( + relay_chain_full_node.client.clone(), + id, + Box::new(relay_chain_full_node.network.clone()), + relay_chain_full_node.backend.clone(), + ); + + 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 mut task_manager = params.task_manager; + 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(), + on_demand: None, + block_announce_validator_builder: Some(Box::new(|_| block_announce_validator)), + warp_sync: None, + })?; + + let rpc_extensions_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, + }; + + Ok(crate::rpc::create_full(deps)) + }) + }; + + sc_service::spawn_tasks(sc_service::SpawnTasksParams { + on_demand: None, + remote_blockchain: None, + rpc_extensions_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(), + })?; + + let announce_block = { + let network = network.clone(); + Arc::new(move |hash, data| network.announce_block(hash, data)) + }; + + if validator { + let parachain_consensus = build_consensus( + client.clone(), + prometheus_registry.as_ref(), + telemetry.as_ref().map(|t| t.handle()), + &task_manager, + &relay_chain_full_node, + 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_full_node, + spawner, + parachain_consensus, + import_queue, + }; + + start_collator(params).await?; + } else { + let params = StartFullNodeParams { + client: client.clone(), + announce_block, + task_manager: &mut task_manager, + para_id: id, + relay_chain_full_node, + }; + + 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<TFullClient<Block, RuntimeApi, NativeElseWasmExecutor<TemplateRuntimeExecutor>>>, + config: &Configuration, + telemetry: Option<TelemetryHandle>, + task_manager: &TaskManager, +) -> Result< + sc_consensus::DefaultImportQueue< + Block, + TFullClient<Block, RuntimeApi, NativeElseWasmExecutor<TemplateRuntimeExecutor>>, + >, + 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_duration( + *time, + slot_duration.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, + id: ParaId, +) -> sc_service::error::Result<( + TaskManager, + Arc<TFullClient<Block, RuntimeApi, NativeElseWasmExecutor<TemplateRuntimeExecutor>>>, +)> { + start_node_impl::<RuntimeApi, TemplateRuntimeExecutor, _, _, _>( + parachain_config, + polkadot_config, + id, + |_| Ok(Default::default()), + parachain_build_import_queue, + |client, + prometheus_registry, + telemetry, + task_manager, + relay_chain_node, + 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(), + ); + + let relay_chain_backend = relay_chain_node.backend.clone(); + let relay_chain_client = relay_chain_node.client.clone(); + Ok(build_aura_consensus::< + sp_consensus_aura::sr25519::AuthorityPair, + _, + _, + _, + _, + _, + _, + _, + _, + _, + >(BuildAuraConsensusParams { + proposer_factory, + create_inherent_data_providers: move |_, (relay_parent, validation_data)| { + let parachain_inherent = + cumulus_primitives_parachain_inherent::ParachainInherentData::create_at_with_client( + relay_parent, + &relay_chain_client, + &*relay_chain_backend, + &validation_data, + id, + ); + async move { + let time = sp_timestamp::InherentDataProvider::from_system_time(); + + let slot = + sp_consensus_aura::inherents::InherentDataProvider::from_timestamp_and_duration( + *time, + slot_duration.slot_duration(), + ); + + let parachain_inherent = parachain_inherent.ok_or_else(|| { + Box::<dyn std::error::Error + Send + Sync>::from( + "Failed to create parachain inherent", + ) + })?; + Ok((time, slot, parachain_inherent)) + } + }, + block_import: client.clone(), + relay_chain_client: relay_chain_node.client.clone(), + relay_chain_backend: relay_chain_node.backend.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, + })) + }, + ) + .await +} diff --git a/cumulus/parachain-template/pallets/template/Cargo.toml b/cumulus/parachain-template/pallets/template/Cargo.toml new file mode 100644 index 00000000000..934fc43468e --- /dev/null +++ b/cumulus/parachain-template/pallets/template/Cargo.toml @@ -0,0 +1,37 @@ +[package] +name = "pallet-template" +authors = ["Anonymous"] +description = "FRAME pallet template for defining custom runtime logic." +version = "0.1.0" +license = "Unlicense" +homepage = "https://substrate.dev" +repository = "https://github.com/paritytech/substrate/" +edition = "2018" + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[dependencies] +codec = { package = "parity-scale-codec", version = "2.0.0", features = ["derive"], default-features = false } +scale-info = { version = "1.0.0", default-features = false, features = ["derive"] } + +frame-benchmarking = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false, optional = true } +frame-support = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +frame-system = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } + +[dev-dependencies] +serde = { version = "1.0.119" } +sp-core = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +sp-io = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } + +[features] +default = ["std"] +runtime-benchmarks = ["frame-benchmarking"] +std = [ + "codec/std", + "scale-info/std", + "frame-support/std", + "frame-system/std", + "frame-benchmarking/std", +] diff --git a/cumulus/parachain-template/pallets/template/README.md b/cumulus/parachain-template/pallets/template/README.md new file mode 100644 index 00000000000..5a646123346 --- /dev/null +++ b/cumulus/parachain-template/pallets/template/README.md @@ -0,0 +1 @@ +License: Unlicense diff --git a/cumulus/parachain-template/pallets/template/src/benchmarking.rs b/cumulus/parachain-template/pallets/template/src/benchmarking.rs new file mode 100644 index 00000000000..4e1acc8bef6 --- /dev/null +++ b/cumulus/parachain-template/pallets/template/src/benchmarking.rs @@ -0,0 +1,20 @@ +//! Benchmarking setup for pallet-template + +use super::*; + +#[allow(unused)] +use crate::Module as Template; +use frame_benchmarking::{benchmarks, impl_benchmark_test_suite, whitelisted_caller}; +use frame_system::RawOrigin; + +benchmarks! { + do_something { + let s in 0 .. 100; + let caller: T::AccountId = whitelisted_caller(); + }: _(RawOrigin::Signed(caller), s) + verify { + assert_eq!(Something::<T>::get(), Some(s)); + } +} + +impl_benchmark_test_suite!(Template, crate::mock::new_test_ext(), crate::mock::Test,); diff --git a/cumulus/parachain-template/pallets/template/src/lib.rs b/cumulus/parachain-template/pallets/template/src/lib.rs new file mode 100644 index 00000000000..e744ec7a441 --- /dev/null +++ b/cumulus/parachain-template/pallets/template/src/lib.rs @@ -0,0 +1,105 @@ +#![cfg_attr(not(feature = "std"), no_std)] + +/// Edit this file to define custom logic or remove it if it is not needed. +/// Learn more about FRAME and the core library of Substrate FRAME pallets: +/// <https://substrate.dev/docs/en/knowledgebase/runtime/frame> +pub use pallet::*; + +#[cfg(test)] +mod mock; + +#[cfg(test)] +mod tests; + +#[cfg(feature = "runtime-benchmarks")] +mod benchmarking; + +#[frame_support::pallet] +pub mod pallet { + use frame_support::{dispatch::DispatchResultWithPostInfo, pallet_prelude::*}; + use frame_system::pallet_prelude::*; + + /// Configure the pallet by specifying the parameters and types on which it depends. + #[pallet::config] + pub trait Config: frame_system::Config { + /// Because this pallet emits events, it depends on the runtime's definition of an event. + type Event: From<Event<Self>> + IsType<<Self as frame_system::Config>::Event>; + } + + #[pallet::pallet] + #[pallet::generate_store(pub(super) trait Store)] + pub struct Pallet<T>(_); + + // The pallet's runtime storage items. + // https://substrate.dev/docs/en/knowledgebase/runtime/storage + #[pallet::storage] + #[pallet::getter(fn something)] + // Learn more about declaring storage items: + // https://substrate.dev/docs/en/knowledgebase/runtime/storage#declaring-storage-items + pub type Something<T> = StorageValue<_, u32>; + + // Pallets use events to inform users when important changes are made. + // https://substrate.dev/docs/en/knowledgebase/runtime/events + #[pallet::event] + #[pallet::generate_deposit(pub(super) fn deposit_event)] + pub enum Event<T: Config> { + /// Event documentation should end with an array that provides descriptive names for event + /// parameters. [something, who] + SomethingStored(u32, T::AccountId), + } + + // Errors inform users that something went wrong. + #[pallet::error] + pub enum Error<T> { + /// Error names should be descriptive. + NoneValue, + /// Errors should have helpful documentation associated with them. + StorageOverflow, + } + + #[pallet::hooks] + impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {} + + // Dispatchable functions allows users to interact with the pallet and invoke state changes. + // These functions materialize as "extrinsics", which are often compared to transactions. + // Dispatchable functions must be annotated with a weight and must return a DispatchResult. + #[pallet::call] + impl<T: Config> Pallet<T> { + /// An example dispatchable that takes a singles value as a parameter, writes the value to + /// storage and emits an event. This function must be dispatched by a signed extrinsic. + #[pallet::weight(10_000 + T::DbWeight::get().writes(1))] + pub fn do_something(origin: OriginFor<T>, something: u32) -> DispatchResultWithPostInfo { + // Check that the extrinsic was signed and get the signer. + // This function will return an error if the extrinsic is not signed. + // https://substrate.dev/docs/en/knowledgebase/runtime/origin + let who = ensure_signed(origin)?; + + // Update storage. + <Something<T>>::put(something); + + // Emit an event. + Self::deposit_event(Event::SomethingStored(something, who)); + // Return a successful DispatchResultWithPostInfo + Ok(().into()) + } + + /// An example dispatchable that may throw a custom error. + #[pallet::weight(10_000 + T::DbWeight::get().reads_writes(1,1))] + pub fn cause_error(origin: OriginFor<T>) -> DispatchResultWithPostInfo { + let _who = ensure_signed(origin)?; + + // Read a value from storage. + match <Something<T>>::get() { + // Return an error if the value has not been set. + None => Err(Error::<T>::NoneValue)?, + Some(old) => { + // Increment the value read from storage; will error in the event of overflow. + let new = old.checked_add(1).ok_or(Error::<T>::StorageOverflow)?; + // Update the value in storage with the incremented result. + <Something<T>>::put(new); + Ok(().into()) + }, + } + } + } +} diff --git a/cumulus/parachain-template/pallets/template/src/mock.rs b/cumulus/parachain-template/pallets/template/src/mock.rs new file mode 100644 index 00000000000..525375e2d82 --- /dev/null +++ b/cumulus/parachain-template/pallets/template/src/mock.rs @@ -0,0 +1,63 @@ +use crate as pallet_template; +use frame_support::{parameter_types, traits::Everything}; +use frame_system as system; +use sp_core::H256; +use sp_runtime::{ + testing::Header, + traits::{BlakeTwo256, IdentityLookup}, +}; + +type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic<Test>; +type Block = frame_system::mocking::MockBlock<Test>; + +// Configure a mock runtime to test the pallet. +frame_support::construct_runtime!( + pub enum Test where + Block = Block, + NodeBlock = Block, + UncheckedExtrinsic = UncheckedExtrinsic, + { + System: frame_system::{Pallet, Call, Config, Storage, Event<T>}, + TemplateModule: pallet_template::{Pallet, Call, Storage, Event<T>}, + } +); + +parameter_types! { + pub const BlockHashCount: u64 = 250; + pub const SS58Prefix: u8 = 42; +} + +impl system::Config for Test { + type BaseCallFilter = Everything; + type BlockWeights = (); + type BlockLength = (); + type DbWeight = (); + type Origin = Origin; + type Call = Call; + type Index = u64; + type BlockNumber = u64; + type Hash = H256; + type Hashing = BlakeTwo256; + type AccountId = u64; + type Lookup = IdentityLookup<Self::AccountId>; + type Header = Header; + type Event = Event; + type BlockHashCount = BlockHashCount; + type Version = (); + type PalletInfo = PalletInfo; + type AccountData = (); + type OnNewAccount = (); + type OnKilledAccount = (); + type SystemWeightInfo = (); + type SS58Prefix = SS58Prefix; + type OnSetCode = (); +} + +impl pallet_template::Config for Test { + type Event = Event; +} + +// Build genesis storage according to the mock runtime. +pub fn new_test_ext() -> sp_io::TestExternalities { + system::GenesisConfig::default().build_storage::<Test>().unwrap().into() +} diff --git a/cumulus/parachain-template/pallets/template/src/tests.rs b/cumulus/parachain-template/pallets/template/src/tests.rs new file mode 100644 index 00000000000..22056586017 --- /dev/null +++ b/cumulus/parachain-template/pallets/template/src/tests.rs @@ -0,0 +1,20 @@ +use crate::{mock::*, Error}; +use frame_support::{assert_noop, assert_ok}; + +#[test] +fn it_works_for_default_value() { + new_test_ext().execute_with(|| { + // Dispatch a signed extrinsic. + assert_ok!(TemplateModule::do_something(Origin::signed(1), 42)); + // Read pallet storage and assert an expected result. + assert_eq!(TemplateModule::something(), Some(42)); + }); +} + +#[test] +fn correct_error_for_none_value() { + new_test_ext().execute_with(|| { + // Ensure the expected error is thrown when no value is present. + assert_noop!(TemplateModule::cause_error(Origin::signed(1)), Error::<Test>::NoneValue); + }); +} diff --git a/cumulus/parachain-template/polkadot-launch/config.json b/cumulus/parachain-template/polkadot-launch/config.json new file mode 100644 index 00000000000..4dd6ebf7cf4 --- /dev/null +++ b/cumulus/parachain-template/polkadot-launch/config.json @@ -0,0 +1,39 @@ +{ + "relaychain": { + "bin": "../../polkadot/target/release/polkadot", + "chain": "rococo-local", + "nodes": [ + { + "name": "alice", + "wsPort": 9944, + "port": 30444 + }, + { + "name": "bob", + "wsPort": 9955, + "port": 30555 + } + ] + }, + "parachains": [ + { + "bin": "../target/release/parachain-collator", + "id": "200", + "balance": "1000000000000000000000", + "nodes": [ + { + "wsPort": 9988, + "name": "alice", + "port": 31200, + "flags": [ + "--force-authoring", + "--", + "--execution=wasm" + ] + } + ] + } + ], + "types": { + } +} diff --git a/cumulus/parachain-template/runtime/Cargo.toml b/cumulus/parachain-template/runtime/Cargo.toml new file mode 100644 index 00000000000..c4edd43d643 --- /dev/null +++ b/cumulus/parachain-template/runtime/Cargo.toml @@ -0,0 +1,144 @@ +[package] +name = "parachain-template-runtime" +version = "0.1.0" +authors = ["Anonymous"] +description = "A new Cumulus FRAME-based Substrate Runtime, ready for hacking together a parachain." +license = "Unlicense" +homepage = "https://substrate.dev" +repository = "https://github.com/paritytech/cumulus/" +edition = "2018" + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[build-dependencies] +substrate-wasm-builder = { git = "https://github.com/paritytech/substrate", branch = "master" } + +[dependencies] +codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"]} +log = { version = "0.4.14", default-features = false } +scale-info = { version = "1.0.0", default-features = false, features = ["derive"] } +serde = { version = "1.0.119", optional = true, features = ["derive"] } +smallvec = "1.6.1" + +# Local Dependencies +pallet-template = { path = "../pallets/template", default-features = false } + +# Substrate Dependencies +## Substrate Primitive Dependencies +sp-api = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" } +sp-block-builder = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" } +sp-consensus-aura = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" } +sp-core = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" } +sp-inherents = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" } +sp-io = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" } +sp-offchain = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" } +sp-runtime = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" } +sp-session = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" } +sp-std = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" } +sp-transaction-pool = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" } +sp-version = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" } + +## Substrate FRAME Dependencies +frame-benchmarking = { git = "https://github.com/paritytech/substrate", default-features = false, optional = true , branch = "master" } +frame-executive = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" } +frame-support = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } +frame-system = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" } +frame-system-benchmarking = { git = "https://github.com/paritytech/substrate", default-features = false, optional = true , branch = "master" } +frame-system-rpc-runtime-api = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" } + +## Substrate Pallet Dependencies +pallet-aura = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" } +pallet-authorship = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" } +pallet-balances = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" } +pallet-randomness-collective-flip = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" } +pallet-session = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" } +pallet-sudo = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" } +pallet-timestamp = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" } +pallet-transaction-payment = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" } +pallet-transaction-payment-rpc-runtime-api = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" } + +# Cumulus dependencies +cumulus-pallet-aura-ext = { path = "../../pallets/aura-ext", default-features = false } +cumulus-pallet-dmp-queue = { path = "../../pallets/dmp-queue", default-features = false } +cumulus-pallet-parachain-system = { path = "../../pallets/parachain-system", default-features = false } +cumulus-pallet-xcm = { path = "../../pallets/xcm", default-features = false } +cumulus-pallet-xcmp-queue = { path = "../../pallets/xcmp-queue", default-features = false } +cumulus-primitives-core = { path = "../../primitives/core", default-features = false } +cumulus-primitives-timestamp = { path = "../../primitives/timestamp", default-features = false } +cumulus-primitives-utility = { path = "../../primitives/utility", default-features = false } +pallet-collator-selection = { path = "../../pallets/collator-selection", default-features = false } +parachain-info = { path = "../../polkadot-parachains/pallets/parachain-info", default-features = false } + +# Polkadot Dependencies +pallet-xcm = { git = "https://github.com/paritytech/polkadot", default-features = false , branch = "master" } +polkadot-parachain = { git = "https://github.com/paritytech/polkadot", default-features = false , branch = "master" } +polkadot-runtime-common = { git = "https://github.com/paritytech/polkadot", default-features = false, branch = "master" } +xcm = { git = "https://github.com/paritytech/polkadot", default-features = false , branch = "master" } +xcm-builder = { git = "https://github.com/paritytech/polkadot", default-features = false , branch = "master" } +xcm-executor = { git = "https://github.com/paritytech/polkadot", default-features = false , branch = "master" } + +[features] +default = [ + "std", +] +std = [ + "codec/std", + "serde", + "scale-info/std", + "log/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", + "frame-executive/std", + "frame-support/std", + "frame-system/std", + "pallet-aura/std", + "pallet-authorship/std", + "pallet-balances/std", + "pallet-collator-selection/std", + "pallet-randomness-collective-flip/std", + "pallet-session/std", + "pallet-sudo/std", + "pallet-template/std", + "pallet-timestamp/std", + "pallet-transaction-payment-rpc-runtime-api/std", + "pallet-transaction-payment/std", + "cumulus-pallet-aura-ext/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", + "cumulus-pallet-dmp-queue/std", + "parachain-info/std", + "polkadot-parachain/std", + "polkadot-runtime-common/std", + "xcm-builder/std", + "xcm-executor/std", + "xcm/std", +] + +runtime-benchmarks = [ + "sp-runtime/runtime-benchmarks", + "xcm-builder/runtime-benchmarks", + "frame-benchmarking", + "frame-system-benchmarking", + "frame-support/runtime-benchmarks", + "frame-system/runtime-benchmarks", + "pallet-balances/runtime-benchmarks", + "pallet-collator-selection/runtime-benchmarks", + "pallet-template/runtime-benchmarks", + "pallet-timestamp/runtime-benchmarks", + "pallet-xcm/runtime-benchmarks", +] diff --git a/cumulus/parachain-template/runtime/build.rs b/cumulus/parachain-template/runtime/build.rs new file mode 100644 index 00000000000..9b53d2457df --- /dev/null +++ b/cumulus/parachain-template/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/cumulus/parachain-template/runtime/src/lib.rs b/cumulus/parachain-template/runtime/src/lib.rs new file mode 100644 index 00000000000..31b6bddef50 --- /dev/null +++ b/cumulus/parachain-template/runtime/src/lib.rs @@ -0,0 +1,845 @@ +#![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")); + +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::{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, match_type, parameter_types, + traits::Everything, + weights::{ + constants::{BlockExecutionWeight, ExtrinsicBaseWeight, WEIGHT_PER_SECOND}, + DispatchClass, IdentityFee, Weight, WeightToFeeCoefficient, WeightToFeeCoefficients, + WeightToFeePolynomial, + }, + PalletId, +}; +use frame_system::{ + limits::{BlockLength, BlockWeights}, + EnsureOneOf, EnsureRoot, +}; +pub use sp_consensus_aura::sr25519::AuthorityId as AuraId; +pub use sp_runtime::{MultiAddress, Perbill, Permill}; + +#[cfg(any(feature = "std", test))] +pub use sp_runtime::BuildStorage; + +// Polkadot Imports +use pallet_xcm::{EnsureXcm, IsMajorityOfBody, XcmPassthrough}; +use polkadot_parachain::primitives::Sibling; +use polkadot_runtime_common::{BlockHashCount, RocksDbWeight, SlowAdjustingFeeUpdate}; + +// XCM Imports +use xcm::latest::prelude::*; +use xcm_builder::{ + AccountId32Aliases, AllowTopLevelPaidExecutionFrom, AllowUnpaidExecutionFrom, CurrencyAdapter, + EnsureXcmOrigin, FixedWeightBounds, IsConcrete, LocationInverter, NativeAsset, + ParentAsSuperuser, ParentIsDefault, RelayChainAsNative, SiblingParachainAsNative, + SiblingParachainConvertsVia, SignedAccountId32AsNative, SignedToAccountId32, + SovereignSignedViaLocation, TakeWeightCredit, UsingComponents, +}; +use xcm_executor::{Config, XcmExecutor}; + +/// Import the template pallet. +pub use pallet_template; + +/// 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 = <<Signature as Verify>::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<AccountId, ()>; + +/// Block header type as expected by this runtime. +pub type Header = generic::Header<BlockNumber, BlakeTwo256>; + +/// Block type as expected by this runtime. +pub type Block = generic::Block<Header, UncheckedExtrinsic>; + +/// A Block signed with a Justification +pub type SignedBlock = generic::SignedBlock<Block>; + +/// BlockId type as expected by this runtime. +pub type BlockId = generic::BlockId<Block>; + +/// The SignedExtension to the basic transaction logic. +pub type SignedExtra = ( + frame_system::CheckSpecVersion<Runtime>, + frame_system::CheckTxVersion<Runtime>, + frame_system::CheckGenesis<Runtime>, + frame_system::CheckEra<Runtime>, + frame_system::CheckNonce<Runtime>, + frame_system::CheckWeight<Runtime>, + pallet_transaction_payment::ChargeTransactionPayment<Runtime>, +); + +/// Unchecked extrinsic type as expected by this runtime. +pub type UncheckedExtrinsic = generic::UncheckedExtrinsic<Address, Call, Signature, SignedExtra>; + +/// Extrinsic type that has already been checked. +pub type CheckedExtrinsic = generic::CheckedExtrinsic<AccountId, Call, SignedExtra>; + +/// Executive: handles dispatch to the various modules. +pub type Executive = frame_executive::Executive< + Runtime, + Block, + frame_system::ChainContext<Runtime>, + Runtime, + AllPallets, + OnRuntimeUpgrade, +>; + +pub struct OnRuntimeUpgrade; +impl frame_support::traits::OnRuntimeUpgrade for OnRuntimeUpgrade { + fn on_runtime_upgrade() -> u64 { + frame_support::migrations::migrate_from_pallet_version_to_storage_version::< + AllPalletsWithSystem, + >(&RocksDbWeight::get()) + } +} + +/// 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<Self::Balance> { + // 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<BlockNumber, BlakeTwo256>; + /// Opaque block type. + pub type Block = generic::Block<Header, UncheckedExtrinsic>; + /// Opaque block identifier type. + pub type BlockId = generic::BlockId<Block>; +} + +impl_opaque_keys! { + pub struct SessionKeys { + pub aura: Aura, + } +} + +#[sp_version::runtime_version] +pub const VERSION: RuntimeVersion = RuntimeVersion { + spec_name: create_runtime_str!("template-parachain"), + impl_name: create_runtime_str!("template-parachain"), + authoring_version: 1, + spec_version: 1, + impl_version: 0, + apis: RUNTIME_API_VERSIONS, + transaction_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 Rococo Relay Chain. +pub const EXISTENTIAL_DEPOSIT: Balance = MILLIUNIT; + +// 1 in 4 blocks (on average, not counting collisions) will be primary babe blocks. +pub const PRIMARY_PROBABILITY: (u64, u64) = (1, 4); + +/// 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 = 42; +} + +// 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<AccountId, ()>; + /// 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<BlockNumber, BlakeTwo256>; + /// 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<Balance>; + /// 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<Self>; +} + +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<Self, Aura>; + type UncleGenerations = UncleGenerations; + type FilterUncle = (); + type EventHandler = (CollatorSelection,); +} + +parameter_types! { + pub const ExistentialDeposit: Balance = EXISTENTIAL_DEPOSIT; + pub const MaxLocks: u32 = 50; + pub const MaxReserves: u32 = 50; +} + +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<Runtime>; + type MaxReserves = MaxReserves; + type ReserveIdentifier = [u8; 8]; +} + +parameter_types! { + /// Relay Chain `TransactionByteFee` / 10 + pub const TransactionByteFee: Balance = 10 * MICROUNIT; +} + +impl pallet_transaction_payment::Config for Runtime { + type OnChargeTransaction = pallet_transaction_payment::CurrencyAdapter<Balances, ()>; + type TransactionByteFee = TransactionByteFee; + type WeightToFee = WeightToFee; + type FeeMultiplierUpdate = SlowAdjustingFeeUpdate<Self>; +} + +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 OnValidationData = (); + type SelfParaId = parachain_info::Pallet<Runtime>; + type DmpMessageHandler = DmpQueue; + type ReservedDmpWeight = ReservedDmpWeight; + type OutboundXcmpMessageSource = XcmpQueue; + type XcmpMessageHandler = XcmpQueue; + type ReservedXcmpWeight = ReservedXcmpWeight; +} + +impl pallet_randomness_collective_flip::Config for Runtime {} + +impl parachain_info::Config for Runtime {} + +impl cumulus_pallet_aura_ext::Config for Runtime {} + +parameter_types! { + pub const RocLocation: 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 default `AccountId`. + ParentIsDefault<AccountId>, + // Sibling parachain origins convert to AccountId via the `ParaId::into`. + SiblingParachainConvertsVia<Sibling, AccountId>, + // Straight up local `AccountId32` origins just alias directly to `AccountId`. + AccountId32Aliases<RelayNetwork, AccountId>, +); + +/// 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<RocLocation>, + // 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<LocationToAccountId, Origin>, + // Native converter for Relay-chain (Parent) location; will converts to a `Relay` origin when + // recognised. + RelayChainAsNative<RelayChainOrigin, Origin>, + // Native converter for sibling Parachains; will convert to a `SiblingPara` origin when + // recognised. + SiblingParachainAsNative<cumulus_pallet_xcm::Origin, Origin>, + // Superuser converter for the Relay-chain (Parent) location. This will allow it to issue a + // transaction from the Root origin. + ParentAsSuperuser<Origin>, + // Native signed account converter; this just converts an `AccountId32` origin into a normal + // `Origin::Signed` origin of the same 32-byte value. + SignedAccountId32AsNative<RelayNetwork, Origin>, + // Xcm origins can be represented natively under the Xcm pallet's Xcm origin. + XcmPassthrough<Origin>, +); + +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_type! { + pub type ParentOrParentsExecutivePlurality: impl Contains<MultiLocation> = { + MultiLocation { parents: 1, interior: Here } | + MultiLocation { parents: 1, interior: X1(Plurality { id: BodyId::Executive, .. }) } + }; +} + +pub type Barrier = ( + TakeWeightCredit, + AllowTopLevelPaidExecutionFrom<Everything>, + AllowUnpaidExecutionFrom<ParentOrParentsExecutivePlurality>, + // ^^^ Parent and its exec plurality get free execution +); + +pub struct XcmConfig; +impl 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 = NativeAsset; // Should be enough to allow teleportation of ROC + type LocationInverter = LocationInverter<Ancestry>; + type Barrier = Barrier; + type Weigher = FixedWeightBounds<UnitWeightCost, Call, MaxInstructions>; + type Trader = UsingComponents<IdentityFee<Balance>, RocLocation, AccountId, Balances, ()>; + type ResponseHandler = PolkadotXcm; + type AssetTrap = PolkadotXcm; + type AssetClaims = PolkadotXcm; + type SubscriptionService = PolkadotXcm; +} + +parameter_types! { + pub const MaxDownwardMessageWeight: Weight = MAXIMUM_BLOCK_WEIGHT / 10; +} + +/// No local origins on this chain are allowed to dispatch XCM sends/executions. +pub type LocalOriginToLocation = SignedToAccountId32<Origin, AccountId, RelayNetwork>; + +/// 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<ParachainSystem, ()>, + // ..and XCMP to communicate with the sibling chains. + XcmpQueue, +); + +impl pallet_xcm::Config for Runtime { + type Event = Event; + type SendXcmOrigin = EnsureXcmOrigin<Origin, LocalOriginToLocation>; + type XcmRouter = XcmRouter; + type ExecuteXcmOrigin = EnsureXcmOrigin<Origin, LocalOriginToLocation>; + type XcmExecuteFilter = Everything; + type XcmExecutor = XcmExecutor<XcmConfig>; + type XcmTeleportFilter = Everything; + type XcmReserveTransferFilter = Everything; + type Weigher = FixedWeightBounds<UnitWeightCost, Call, MaxInstructions>; + type LocationInverter = LocationInverter<Ancestry>; + type Origin = Origin; + type Call = Call; + + const VERSION_DISCOVERY_QUEUE_SIZE: u32 = 100; + type AdvertisedXcmVersion = pallet_xcm::CurrentXcmVersion; +} + +impl cumulus_pallet_xcm::Config for Runtime { + type Event = Event; + type XcmExecutor = XcmExecutor<XcmConfig>; +} + +impl cumulus_pallet_xcmp_queue::Config for Runtime { + type Event = Event; + type XcmExecutor = XcmExecutor<XcmConfig>; + type ChannelInfo = ParachainSystem; + type VersionWrapper = (); +} + +impl cumulus_pallet_dmp_queue::Config for Runtime { + type Event = Event; + type XcmExecutor = XcmExecutor<XcmConfig>; + type ExecuteOverweightOrigin = EnsureRoot<AccountId>; +} + +parameter_types! { + pub const DisabledValidatorsThreshold: Perbill = Perbill::from_percent(33); + 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 = <Self as frame_system::Config>::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<Period, Offset>; + type NextSessionRotation = pallet_session::PeriodicSessions<Period, Offset>; + type SessionManager = CollatorSelection; + // Essentially just Aura, but lets be pedantic. + type SessionHandler = <SessionKeys as sp_runtime::traits::OpaqueKeys>::KeyTypeIdProviders; + type Keys = SessionKeys; + type DisabledValidatorsThreshold = DisabledValidatorsThreshold; + 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 and the Relay Chain council to execute privileged collator selection operations. +pub type CollatorSelectionUpdateOrigin = EnsureOneOf< + AccountId, + EnsureRoot<AccountId>, + EnsureXcm<IsMajorityOfBody<RocLocation, ExecutiveBody>>, +>; + +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 = <Self as frame_system::Config>::AccountId; + type ValidatorIdOf = pallet_collator_selection::IdentityCollator; + type ValidatorRegistration = Session; + type WeightInfo = (); +} + +/// Configure the pallet template in pallets/template. +impl pallet_template::Config for Runtime { + type Event = Event; +} + +// 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<T>} = 0, + ParachainSystem: cumulus_pallet_parachain_system::{ + Pallet, Call, Config, Storage, Inherent, Event<T>, ValidateUnsigned, + } = 1, + RandomnessCollectiveFlip: pallet_randomness_collective_flip::{Pallet, Storage} = 2, + Timestamp: pallet_timestamp::{Pallet, Call, Storage, Inherent} = 3, + ParachainInfo: parachain_info::{Pallet, Storage, Config} = 4, + + // Monetary stuff. + Balances: pallet_balances::{Pallet, Call, Storage, Config<T>, Event<T>} = 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<T>, Config<T>} = 21, + Session: pallet_session::{Pallet, Call, Storage, Event, Config<T>} = 22, + Aura: pallet_aura::{Pallet, Storage, Config<T>} = 23, + AuraExt: cumulus_pallet_aura_ext::{Pallet, Storage, Config} = 24, + + // XCM helpers. + XcmpQueue: cumulus_pallet_xcmp_queue::{Pallet, Call, Storage, Event<T>} = 30, + PolkadotXcm: pallet_xcm::{Pallet, Call, Event<T>, Origin} = 31, + CumulusXcm: cumulus_pallet_xcm::{Pallet, Event<T>, Origin} = 32, + DmpQueue: cumulus_pallet_dmp_queue::{Pallet, Call, Storage, Event<T>} = 33, + + // Template + TemplatePallet: pallet_template::{Pallet, Call, Storage, Event<T>} = 40, + } +); + +impl_runtime_apis! { + impl sp_consensus_aura::AuraApi<Block, AuraId> for Runtime { + fn slot_duration() -> sp_consensus_aura::SlotDuration { + sp_consensus_aura::SlotDuration::from_millis(Aura::slot_duration()) + } + + fn authorities() -> Vec<AuraId> { + Aura::authorities().into_inner() + } + } + + impl sp_api::Core<Block> for Runtime { + fn version() -> RuntimeVersion { + VERSION + } + + fn execute_block(block: Block) { + Executive::execute_block(block) + } + + fn initialize_block(header: &<Block as BlockT>::Header) { + Executive::initialize_block(header) + } + } + + impl sp_api::Metadata<Block> for Runtime { + fn metadata() -> OpaqueMetadata { + OpaqueMetadata::new(Runtime::metadata().into()) + } + } + + impl sp_block_builder::BlockBuilder<Block> for Runtime { + fn apply_extrinsic(extrinsic: <Block as BlockT>::Extrinsic) -> ApplyExtrinsicResult { + Executive::apply_extrinsic(extrinsic) + } + + fn finalize_block() -> <Block as BlockT>::Header { + Executive::finalize_block() + } + + fn inherent_extrinsics(data: sp_inherents::InherentData) -> Vec<<Block as BlockT>::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<Block> for Runtime { + fn validate_transaction( + source: TransactionSource, + tx: <Block as BlockT>::Extrinsic, + block_hash: <Block as BlockT>::Hash, + ) -> TransactionValidity { + Executive::validate_transaction(source, tx, block_hash) + } + } + + impl sp_offchain::OffchainWorkerApi<Block> for Runtime { + fn offchain_worker(header: &<Block as BlockT>::Header) { + Executive::offchain_worker(header) + } + } + + impl sp_session::SessionKeys<Block> for Runtime { + fn generate_session_keys(seed: Option<Vec<u8>>) -> Vec<u8> { + SessionKeys::generate(seed) + } + + fn decode_session_keys( + encoded: Vec<u8>, + ) -> Option<Vec<(Vec<u8>, KeyTypeId)>> { + SessionKeys::decode_into_raw_public_keys(&encoded) + } + } + + impl frame_system_rpc_runtime_api::AccountNonceApi<Block, AccountId, Index> for Runtime { + fn account_nonce(account: AccountId) -> Index { + System::account_nonce(account) + } + } + + impl pallet_transaction_payment_rpc_runtime_api::TransactionPaymentApi<Block, Balance> for Runtime { + fn query_info( + uxt: <Block as BlockT>::Extrinsic, + len: u32, + ) -> pallet_transaction_payment_rpc_runtime_api::RuntimeDispatchInfo<Balance> { + TransactionPayment::query_info(uxt, len) + } + fn query_fee_details( + uxt: <Block as BlockT>::Extrinsic, + len: u32, + ) -> pallet_transaction_payment::FeeDetails<Balance> { + TransactionPayment::query_fee_details(uxt, len) + } + } + + impl cumulus_primitives_core::CollectCollationInfo<Block> for Runtime { + fn collect_collation_info() -> cumulus_primitives_core::CollationInfo { + ParachainSystem::collect_collation_info() + } + } + + + #[cfg(feature = "runtime-benchmarks")] + impl frame_benchmarking::Benchmark<Block> for Runtime { + fn benchmark_metadata(extra: bool) -> ( + Vec<frame_benchmarking::BenchmarkList>, + Vec<frame_support::traits::StorageInfo>, + ) { + use frame_benchmarking::{list_benchmark, 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::<BenchmarkList>::new(); + + list_benchmark!(list, extra, frame_system, SystemBench::<Runtime>); + list_benchmark!(list, extra, pallet_balances, Balances); + list_benchmark!(list, extra, pallet_timestamp, Timestamp); + list_benchmark!(list, extra, pallet_collator_selection, CollatorSelection); + + let storage_info = AllPalletsWithSystem::storage_info(); + + return (list, storage_info) + } + + fn dispatch_benchmark( + config: frame_benchmarking::BenchmarkConfig + ) -> Result<Vec<frame_benchmarking::BenchmarkBatch>, sp_runtime::RuntimeString> { + use frame_benchmarking::{Benchmarking, BenchmarkBatch, add_benchmark, 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<TrackedStorageKey> = 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::<BenchmarkBatch>::new(); + let params = (&config, &whitelist); + + add_benchmark!(params, batches, frame_system, SystemBench::<Runtime>); + add_benchmark!(params, batches, pallet_balances, Balances); + add_benchmark!(params, batches, pallet_session, SessionBench::<Runtime>); + add_benchmark!(params, batches, pallet_timestamp, Timestamp); + add_benchmark!(params, batches, pallet_collator_selection, CollatorSelection); + + if batches.is_empty() { return Err("Benchmark not found for this pallet.".into()) } + Ok(batches) + } + } +} + +struct CheckInherents; + +impl cumulus_pallet_parachain_system::CheckInherents<Block> 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::<Runtime, Executive>, + CheckInherents = CheckInherents, +} -- GitLab