├── CODEOWNERS ├── pallets └── template │ ├── README.md │ ├── src │ ├── benchmarking.rs │ ├── tests.rs │ ├── mock.rs │ └── lib.rs │ └── Cargo.toml ├── node ├── src │ ├── lib.rs │ ├── main.rs │ ├── cli.rs │ ├── rpc.rs │ ├── benchmarking.rs │ ├── chain_spec.rs │ ├── command.rs │ └── service.rs ├── build.rs └── Cargo.toml ├── Cargo.toml ├── .gitignore ├── runtime ├── build.rs ├── Cargo.toml └── src │ └── lib.rs ├── .editorconfig ├── scripts └── init.sh ├── rustfmt.toml ├── .devcontainer └── devcontainer.json ├── .github ├── ISSUE_TEMPLATE │ └── config.yml └── workflows │ ├── check.yml │ └── build-publish-image.yml ├── .vscode └── tasks.json ├── LICENSE ├── shell.nix ├── docs └── rust-setup.md └── README.md /CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @sacha-l @lisa-parity 2 | -------------------------------------------------------------------------------- /pallets/template/README.md: -------------------------------------------------------------------------------- 1 | License: Unlicense -------------------------------------------------------------------------------- /node/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub mod chain_spec; 2 | pub mod rpc; 3 | pub mod service; 4 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = [ 3 | "node", 4 | "pallets/template", 5 | "runtime", 6 | ] 7 | [profile.release] 8 | panic = "unwind" 9 | -------------------------------------------------------------------------------- /node/build.rs: -------------------------------------------------------------------------------- 1 | use substrate_build_script_utils::{generate_cargo_keys, rerun_if_git_head_changed}; 2 | 3 | fn main() { 4 | generate_cargo_keys(); 5 | 6 | rerun_if_git_head_changed(); 7 | } 8 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Generated by Cargo 2 | # will have compiled files and executables 3 | **/target/ 4 | # These are backup files generated by rustfmt 5 | **/*.rs.bk 6 | 7 | .DS_Store 8 | 9 | # direnv files 10 | .envrc 11 | .direnv 12 | -------------------------------------------------------------------------------- /runtime/build.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | #[cfg(feature = "std")] 3 | { 4 | substrate_wasm_builder::WasmBuilder::new() 5 | .with_current_project() 6 | .export_heap_base() 7 | .import_memory() 8 | .build(); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /node/src/main.rs: -------------------------------------------------------------------------------- 1 | //! Substrate Node Template CLI library. 2 | #![warn(missing_docs)] 3 | 4 | mod chain_spec; 5 | #[macro_use] 6 | mod service; 7 | mod benchmarking; 8 | mod cli; 9 | mod command; 10 | mod rpc; 11 | 12 | fn main() -> sc_cli::Result<()> { 13 | command::run() 14 | } 15 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style=space 5 | indent_size=2 6 | tab_width=2 7 | end_of_line=lf 8 | charset=utf-8 9 | trim_trailing_whitespace=true 10 | insert_final_newline = true 11 | 12 | [*.{rs,toml}] 13 | indent_style=tab 14 | indent_size=tab 15 | tab_width=4 16 | max_line_length=100 17 | -------------------------------------------------------------------------------- /scripts/init.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # This script is meant to be run on Unix/Linux based systems 3 | set -e 4 | 5 | echo "*** Initializing WASM build environment" 6 | 7 | if [ -z $CI_PROJECT_NAME ] ; then 8 | rustup update nightly 9 | rustup update stable 10 | fi 11 | 12 | rustup target add wasm32-unknown-unknown --toolchain nightly 13 | -------------------------------------------------------------------------------- /pallets/template/src/benchmarking.rs: -------------------------------------------------------------------------------- 1 | //! Benchmarking setup for pallet-template 2 | 3 | use super::*; 4 | 5 | #[allow(unused)] 6 | use crate::Pallet as Template; 7 | use frame_benchmarking::v1::{benchmarks, whitelisted_caller}; 8 | use frame_system::RawOrigin; 9 | 10 | benchmarks! { 11 | do_something { 12 | let s in 0 .. 100; 13 | let caller: T::AccountId = whitelisted_caller(); 14 | }: _(RawOrigin::Signed(caller), s) 15 | verify { 16 | assert_eq!(Something::::get(), Some(s)); 17 | } 18 | 19 | impl_benchmark_test_suite!(Template, crate::mock::new_test_ext(), crate::mock::Test); 20 | } 21 | -------------------------------------------------------------------------------- /rustfmt.toml: -------------------------------------------------------------------------------- 1 | # Basic 2 | hard_tabs = true 3 | max_width = 100 4 | use_small_heuristics = "Max" 5 | # Imports 6 | imports_granularity = "Crate" 7 | reorder_imports = true 8 | # Consistency 9 | newline_style = "Unix" 10 | # Format comments 11 | comment_width = 100 12 | wrap_comments = true 13 | # Misc 14 | chain_width = 80 15 | spaces_around_ranges = false 16 | binop_separator = "Back" 17 | reorder_impl_items = false 18 | match_arm_leading_pipes = "Preserve" 19 | match_arm_blocks = false 20 | match_block_trailing_comma = true 21 | trailing_comma = "Vertical" 22 | trailing_semicolon = false 23 | use_field_init_shorthand = true 24 | -------------------------------------------------------------------------------- /.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Substrate Node template", 3 | "context": "..", 4 | "settings": { 5 | "terminal.integrated.shell.linux": "/bin/bash", 6 | "lldb.executable": "/usr/bin/lldb" 7 | }, 8 | "extensions": [ 9 | "rust-lang.rust", 10 | "bungcip.better-toml", 11 | "vadimcn.vscode-lldb" 12 | ], 13 | "forwardPorts": [ 14 | 3000, 15 | 9944 16 | ], 17 | "onCreateCommand": ["cargo build", "cargo check"], 18 | "postStartCommand": "./target/debug/node-template --dev --ws-external", 19 | "menuActions": [ 20 | {"id": "polkadotjs", 21 | "label": "Open PolkadotJS Apps", 22 | "type": "external-preview", 23 | "args": ["https://polkadot.js.org/apps/?rpc=wss%3A%2F%2F/$HOST/wss"]} 24 | ] 25 | } 26 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false 2 | contact_links: 3 | - name: Support & Troubleshooting with the Substrate Stack Exchange Community 4 | url: https://substrate.stackexchange.com 5 | about: | 6 | For general problems with Substrate or related technologies, please search here first 7 | for solutions, by keyword and tags. If you discover no solution, please then ask and questions in our community! We highly encourage everyone also share their understanding by answering questions for others. 8 | - name: Feature Requests and PRs to be submitted upstream 9 | url: https://github.com/paritytech/substrate/tree/master/bin/node-template 10 | about: | 11 | This template is generated on tagged releases upstream, it is not independently updated and maintained. 12 | Please direct all suggestions for improvements and PRs upstream. 13 | -------------------------------------------------------------------------------- /pallets/template/src/tests.rs: -------------------------------------------------------------------------------- 1 | use crate::{mock::*, Error, Event}; 2 | use frame_support::{assert_noop, assert_ok}; 3 | 4 | #[test] 5 | fn it_works_for_default_value() { 6 | new_test_ext().execute_with(|| { 7 | // Go past genesis block so events get deposited 8 | System::set_block_number(1); 9 | // Dispatch a signed extrinsic. 10 | assert_ok!(TemplateModule::do_something(RuntimeOrigin::signed(1), 42)); 11 | // Read pallet storage and assert an expected result. 12 | assert_eq!(TemplateModule::something(), Some(42)); 13 | // Assert that the correct event was deposited 14 | System::assert_last_event(Event::SomethingStored { something: 42, who: 1 }.into()); 15 | }); 16 | } 17 | 18 | #[test] 19 | fn correct_error_for_none_value() { 20 | new_test_ext().execute_with(|| { 21 | // Ensure the expected error is thrown when no value is present. 22 | assert_noop!( 23 | TemplateModule::cause_error(RuntimeOrigin::signed(1)), 24 | Error::::NoneValue 25 | ); 26 | }); 27 | } 28 | -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | // See https://go.microsoft.com/fwlink/?LinkId=733558 3 | // for the documentation about the tasks.json format 4 | "version": "2.0.0", 5 | "tasks": [ 6 | { 7 | "label": "Run ", 8 | "type": "shell", 9 | "command": "cargo", 10 | "args": ["run", "--release", "--", "--dev"], 11 | "group": { 12 | "kind": "build", 13 | "isDefault": true 14 | }, 15 | "presentation": { 16 | "reveal": "always", 17 | "panel": "new" 18 | }, 19 | "problemMatcher": [ 20 | { 21 | "owner": "rust", 22 | "fileLocation": ["relative", "${workspaceRoot}"], 23 | "pattern": { 24 | "regexp": "^(.*):(\\d+):(\\d+):\\s+(\\d+):(\\d+)\\s+(warning|error):\\s+(.*)$", 25 | "file": 1, 26 | "line": 2, 27 | "column": 3, 28 | "endLine": 4, 29 | "endColumn": 5, 30 | "severity": 6, 31 | "message": 7 32 | } 33 | } 34 | ] 35 | } 36 | ] 37 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | This is free and unencumbered software released into the public domain. 2 | 3 | Anyone is free to copy, modify, publish, use, compile, sell, or 4 | distribute this software, either in source code form or as a compiled 5 | binary, for any purpose, commercial or non-commercial, and by any 6 | means. 7 | 8 | In jurisdictions that recognize copyright laws, the author or authors 9 | of this software dedicate any and all copyright interest in the 10 | software to the public domain. We make this dedication for the benefit 11 | of the public at large and to the detriment of our heirs and 12 | successors. We intend this dedication to be an overt act of 13 | relinquishment in perpetuity of all present and future rights to this 14 | software under copyright law. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | 24 | For more information, please refer to 25 | -------------------------------------------------------------------------------- /shell.nix: -------------------------------------------------------------------------------- 1 | let 2 | mozillaOverlay = 3 | import (builtins.fetchGit { 4 | url = "https://github.com/mozilla/nixpkgs-mozilla.git"; 5 | rev = "57c8084c7ef41366993909c20491e359bbb90f54"; 6 | }); 7 | pinned = builtins.fetchGit { 8 | # Descriptive name to make the store path easier to identify 9 | url = "https://github.com/nixos/nixpkgs/"; 10 | # Commit hash for nixos-unstable as of 2020-04-26 11 | # `git ls-remote https://github.com/nixos/nixpkgs nixos-unstable` 12 | ref = "refs/heads/nixos-unstable"; 13 | rev = "1fe6ed37fd9beb92afe90671c0c2a662a03463dd"; 14 | }; 15 | nixpkgs = import pinned { overlays = [ mozillaOverlay ]; }; 16 | toolchain = with nixpkgs; (rustChannelOf { date = "2021-09-14"; channel = "nightly"; }); 17 | rust-wasm = toolchain.rust.override { 18 | targets = [ "wasm32-unknown-unknown" ]; 19 | }; 20 | in 21 | with nixpkgs; pkgs.mkShell { 22 | buildInputs = [ 23 | clang 24 | pkg-config 25 | rust-wasm 26 | ] ++ stdenv.lib.optionals stdenv.isDarwin [ 27 | darwin.apple_sdk.frameworks.Security 28 | ]; 29 | 30 | LIBCLANG_PATH = "${llvmPackages.libclang}/lib"; 31 | PROTOC = "${protobuf}/bin/protoc"; 32 | RUST_SRC_PATH = "${toolchain.rust-src}/lib/rustlib/src/rust/library/"; 33 | ROCKSDB_LIB_DIR = "${rocksdb}/lib"; 34 | 35 | } 36 | -------------------------------------------------------------------------------- /node/src/cli.rs: -------------------------------------------------------------------------------- 1 | use sc_cli::RunCmd; 2 | 3 | #[derive(Debug, clap::Parser)] 4 | pub struct Cli { 5 | #[command(subcommand)] 6 | pub subcommand: Option, 7 | 8 | #[clap(flatten)] 9 | pub run: RunCmd, 10 | } 11 | 12 | #[derive(Debug, clap::Subcommand)] 13 | pub enum Subcommand { 14 | /// Key management cli utilities 15 | #[command(subcommand)] 16 | Key(sc_cli::KeySubcommand), 17 | 18 | /// Build a chain specification. 19 | BuildSpec(sc_cli::BuildSpecCmd), 20 | 21 | /// Validate blocks. 22 | CheckBlock(sc_cli::CheckBlockCmd), 23 | 24 | /// Export blocks. 25 | ExportBlocks(sc_cli::ExportBlocksCmd), 26 | 27 | /// Export the state of a given block into a chain spec. 28 | ExportState(sc_cli::ExportStateCmd), 29 | 30 | /// Import blocks. 31 | ImportBlocks(sc_cli::ImportBlocksCmd), 32 | 33 | /// Remove the whole chain. 34 | PurgeChain(sc_cli::PurgeChainCmd), 35 | 36 | /// Revert the chain to a previous state. 37 | Revert(sc_cli::RevertCmd), 38 | 39 | /// Sub-commands concerned with benchmarking. 40 | #[command(subcommand)] 41 | Benchmark(frame_benchmarking_cli::BenchmarkCmd), 42 | 43 | /// Try some command against runtime state. 44 | #[cfg(feature = "try-runtime")] 45 | TryRuntime(try_runtime_cli::TryRuntimeCmd), 46 | 47 | /// Try some command against runtime state. Note: `try-runtime` feature must be enabled. 48 | #[cfg(not(feature = "try-runtime"))] 49 | TryRuntime, 50 | 51 | /// Db meta columns information. 52 | ChainInfo(sc_cli::ChainInfoCmd), 53 | } 54 | -------------------------------------------------------------------------------- /.github/workflows/check.yml: -------------------------------------------------------------------------------- 1 | name: Check Set-Up & Build 2 | 3 | # Controls when the action will run. 4 | on: 5 | # Triggers the workflow on push or pull request events but only for the master branch 6 | push: 7 | branches: [main] 8 | pull_request: 9 | branches: [main] 10 | 11 | # Allows you to run this workflow manually from the Actions tab 12 | workflow_dispatch: 13 | 14 | # A workflow run is made up of one or more jobs that can run sequentially or in parallel 15 | jobs: 16 | check: 17 | # The type of runner that the job will run on 18 | runs-on: ubuntu-22.04 19 | 20 | # Steps represent a sequence of tasks that will be executed as part of the job 21 | steps: 22 | # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it 23 | - uses: actions/checkout@v2 24 | 25 | - name: Set-Up 26 | run: sudo apt install -y git clang curl libssl-dev llvm libudev-dev protobuf-compiler 27 | 28 | - name: Install Rustup 29 | run: | 30 | curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y 31 | source ~/.cargo/env 32 | rustup default stable 33 | rustup update nightly 34 | rustup update stable 35 | rustup target add wasm32-unknown-unknown --toolchain nightly 36 | 37 | - name: Check Build 38 | run: | 39 | SKIP_WASM_BUILD=1 cargo check --release 40 | 41 | - name: Check Build for Benchmarking 42 | run: > 43 | pushd node && 44 | cargo check --features=runtime-benchmarks --release 45 | -------------------------------------------------------------------------------- /pallets/template/src/mock.rs: -------------------------------------------------------------------------------- 1 | use crate as pallet_template; 2 | use frame_support::traits::{ConstU16, ConstU64}; 3 | use sp_core::H256; 4 | use sp_runtime::{ 5 | testing::Header, 6 | traits::{BlakeTwo256, IdentityLookup}, 7 | }; 8 | 9 | type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; 10 | type Block = frame_system::mocking::MockBlock; 11 | 12 | // Configure a mock runtime to test the pallet. 13 | frame_support::construct_runtime!( 14 | pub enum Test where 15 | Block = Block, 16 | NodeBlock = Block, 17 | UncheckedExtrinsic = UncheckedExtrinsic, 18 | { 19 | System: frame_system, 20 | TemplateModule: pallet_template, 21 | } 22 | ); 23 | 24 | impl frame_system::Config for Test { 25 | type BaseCallFilter = frame_support::traits::Everything; 26 | type BlockWeights = (); 27 | type BlockLength = (); 28 | type DbWeight = (); 29 | type RuntimeOrigin = RuntimeOrigin; 30 | type RuntimeCall = RuntimeCall; 31 | type Index = u64; 32 | type BlockNumber = u64; 33 | type Hash = H256; 34 | type Hashing = BlakeTwo256; 35 | type AccountId = u64; 36 | type Lookup = IdentityLookup; 37 | type Header = Header; 38 | type RuntimeEvent = RuntimeEvent; 39 | type BlockHashCount = ConstU64<250>; 40 | type Version = (); 41 | type PalletInfo = PalletInfo; 42 | type AccountData = (); 43 | type OnNewAccount = (); 44 | type OnKilledAccount = (); 45 | type SystemWeightInfo = (); 46 | type SS58Prefix = ConstU16<42>; 47 | type OnSetCode = (); 48 | type MaxConsumers = frame_support::traits::ConstU32<16>; 49 | } 50 | 51 | impl pallet_template::Config for Test { 52 | type RuntimeEvent = RuntimeEvent; 53 | } 54 | 55 | // Build genesis storage according to the mock runtime. 56 | pub fn new_test_ext() -> sp_io::TestExternalities { 57 | frame_system::GenesisConfig::default().build_storage::().unwrap().into() 58 | } 59 | -------------------------------------------------------------------------------- /pallets/template/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "pallet-template" 3 | version = "4.0.0-dev" 4 | description = "FRAME pallet template for defining custom runtime logic." 5 | authors = ["Substrate DevHub "] 6 | homepage = "https://substrate.io" 7 | edition = "2021" 8 | license = "Unlicense" 9 | publish = false 10 | repository = "https://github.com/substrate-developer-hub/substrate-node-template/" 11 | 12 | [package.metadata.docs.rs] 13 | targets = ["x86_64-unknown-linux-gnu"] 14 | 15 | [dependencies] 16 | codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false, features = [ 17 | "derive", 18 | ] } 19 | scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } 20 | frame-benchmarking = { version = "4.0.0-dev", default-features = false, optional = true, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.40" } 21 | frame-support = { version = "4.0.0-dev", default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.40" } 22 | frame-system = { version = "4.0.0-dev", default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.40" } 23 | 24 | [dev-dependencies] 25 | sp-core = { version = "7.0.0", git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.40" } 26 | sp-io = { version = "7.0.0", git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.40" } 27 | sp-runtime = { version = "7.0.0", git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.40" } 28 | 29 | [features] 30 | default = ["std"] 31 | std = [ 32 | "codec/std", 33 | "frame-benchmarking?/std", 34 | "frame-support/std", 35 | "frame-system/std", 36 | "scale-info/std", 37 | ] 38 | runtime-benchmarks = ["frame-benchmarking/runtime-benchmarks"] 39 | try-runtime = ["frame-support/try-runtime"] 40 | -------------------------------------------------------------------------------- /node/src/rpc.rs: -------------------------------------------------------------------------------- 1 | //! A collection of node-specific RPC methods. 2 | //! Substrate provides the `sc-rpc` crate, which defines the core RPC layer 3 | //! used by Substrate nodes. This file extends those RPC definitions with 4 | //! capabilities that are specific to this project's runtime configuration. 5 | 6 | #![warn(missing_docs)] 7 | 8 | use std::sync::Arc; 9 | 10 | use jsonrpsee::RpcModule; 11 | use node_template_runtime::{opaque::Block, AccountId, Balance, Index}; 12 | use sc_transaction_pool_api::TransactionPool; 13 | use sp_api::ProvideRuntimeApi; 14 | use sp_block_builder::BlockBuilder; 15 | use sp_blockchain::{Error as BlockChainError, HeaderBackend, HeaderMetadata}; 16 | 17 | pub use sc_rpc_api::DenyUnsafe; 18 | 19 | /// Full client dependencies. 20 | pub struct FullDeps { 21 | /// The client instance to use. 22 | pub client: Arc, 23 | /// Transaction pool instance. 24 | pub pool: Arc

, 25 | /// Whether to deny unsafe calls 26 | pub deny_unsafe: DenyUnsafe, 27 | } 28 | 29 | /// Instantiate all full RPC extensions. 30 | pub fn create_full( 31 | deps: FullDeps, 32 | ) -> Result, Box> 33 | where 34 | C: ProvideRuntimeApi, 35 | C: HeaderBackend + HeaderMetadata + 'static, 36 | C: Send + Sync + 'static, 37 | C::Api: substrate_frame_rpc_system::AccountNonceApi, 38 | C::Api: pallet_transaction_payment_rpc::TransactionPaymentRuntimeApi, 39 | C::Api: BlockBuilder, 40 | P: TransactionPool + 'static, 41 | { 42 | use pallet_transaction_payment_rpc::{TransactionPayment, TransactionPaymentApiServer}; 43 | use substrate_frame_rpc_system::{System, SystemApiServer}; 44 | 45 | let mut module = RpcModule::new(()); 46 | let FullDeps { client, pool, deny_unsafe } = deps; 47 | 48 | module.merge(System::new(client.clone(), pool.clone(), deny_unsafe).into_rpc())?; 49 | module.merge(TransactionPayment::new(client).into_rpc())?; 50 | 51 | // Extend this RPC with a custom API by using the following syntax. 52 | // `YourRpcStruct` should have a reference to a client, which is needed 53 | // to call into the runtime. 54 | // `module.merge(YourRpcTrait::into_rpc(YourRpcStruct::new(ReferenceToClient, ...)))?;` 55 | 56 | Ok(module) 57 | } 58 | -------------------------------------------------------------------------------- /.github/workflows/build-publish-image.yml: -------------------------------------------------------------------------------- 1 | # This is an example GitHub action that will build and publish a Docker image to DockerHub 2 | # You need to add the following secrets to your GitHub Repository or Organization to make this work 3 | # - DOCKER_USERNAME: The username of the DockerHub account. E.g. parity 4 | # - DOCKER_TOKEN: Access token for DockerHub, see https://docs.docker.com/docker-hub/access-tokens/. E.g. VVVVVVVV-WWWW-XXXXXX-YYYY-ZZZZZZZZZ 5 | # The following are setup as an environment variable below 6 | # - DOCKER_REPO: The unique name of the DockerHub repository. E.g. parity/polkadot 7 | 8 | name: Build & Publish Docker Image 9 | 10 | # Controls when the action will run. 11 | on: 12 | # Triggers the workflow on push events but only for the main branch 13 | # push: 14 | # branches: [ main ] 15 | 16 | # Allows you to run this workflow manually from the Actions tab 17 | workflow_dispatch: 18 | 19 | # Set an environment variable (that can be overriden) for the Docker Repo 20 | env: 21 | DOCKER_REPO: parity/polkadot 22 | 23 | # A workflow run is made up of one or more jobs that can run sequentially or in parallel 24 | jobs: 25 | build: 26 | # The type of runner that the job will run on 27 | runs-on: ubuntu-22.04 28 | 29 | # Steps represent a sequence of tasks that will be executed as part of the job 30 | steps: 31 | # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it 32 | - name: Check out the repo 33 | uses: actions/checkout@v2.5.0 34 | 35 | # Login to Docker hub using the credentials stored in the repository secrets 36 | - name: Log in to Docker Hub 37 | uses: docker/login-action@v2.1.0 38 | with: 39 | username: ${{ secrets.DOCKER_USERNAME }} 40 | password: ${{ secrets.DOCKER_TOKEN }} 41 | 42 | # Get the commit short hash, to use as the rev 43 | - name: Calculate rev hash 44 | id: rev 45 | run: echo "value=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT 46 | 47 | # Build and push 2 images, One with the version tag and the other with latest tag 48 | - name: Build and push Docker images 49 | uses: docker/build-push-action@v3.2.0 50 | with: 51 | context: . 52 | push: true 53 | tags: ${{ env.DOCKER_REPO }}:v${{ steps.rev.outputs.value }}, ${{ env.DOCKER_REPO }}:latest 54 | -------------------------------------------------------------------------------- /pallets/template/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![cfg_attr(not(feature = "std"), no_std)] 2 | 3 | /// Edit this file to define custom logic or remove it if it is not needed. 4 | /// Learn more about FRAME and the core library of Substrate FRAME pallets: 5 | /// 6 | pub use pallet::*; 7 | 8 | #[cfg(test)] 9 | mod mock; 10 | 11 | #[cfg(test)] 12 | mod tests; 13 | 14 | #[cfg(feature = "runtime-benchmarks")] 15 | mod benchmarking; 16 | 17 | #[frame_support::pallet] 18 | pub mod pallet { 19 | use frame_support::pallet_prelude::*; 20 | use frame_system::pallet_prelude::*; 21 | 22 | #[pallet::pallet] 23 | pub struct Pallet(_); 24 | 25 | /// Configure the pallet by specifying the parameters and types on which it depends. 26 | #[pallet::config] 27 | pub trait Config: frame_system::Config { 28 | /// Because this pallet emits events, it depends on the runtime's definition of an event. 29 | type RuntimeEvent: From> + IsType<::RuntimeEvent>; 30 | } 31 | 32 | // The pallet's runtime storage items. 33 | // https://docs.substrate.io/main-docs/build/runtime-storage/ 34 | #[pallet::storage] 35 | #[pallet::getter(fn something)] 36 | // Learn more about declaring storage items: 37 | // https://docs.substrate.io/main-docs/build/runtime-storage/#declaring-storage-items 38 | pub type Something = StorageValue<_, u32>; 39 | 40 | // Pallets use events to inform users when important changes are made. 41 | // https://docs.substrate.io/main-docs/build/events-errors/ 42 | #[pallet::event] 43 | #[pallet::generate_deposit(pub(super) fn deposit_event)] 44 | pub enum Event { 45 | /// Event documentation should end with an array that provides descriptive names for event 46 | /// parameters. [something, who] 47 | SomethingStored { something: u32, who: T::AccountId }, 48 | } 49 | 50 | // Errors inform users that something went wrong. 51 | #[pallet::error] 52 | pub enum Error { 53 | /// Error names should be descriptive. 54 | NoneValue, 55 | /// Errors should have helpful documentation associated with them. 56 | StorageOverflow, 57 | } 58 | 59 | // Dispatchable functions allows users to interact with the pallet and invoke state changes. 60 | // These functions materialize as "extrinsics", which are often compared to transactions. 61 | // Dispatchable functions must be annotated with a weight and must return a DispatchResult. 62 | #[pallet::call] 63 | impl Pallet { 64 | /// An example dispatchable that takes a singles value as a parameter, writes the value to 65 | /// storage and emits an event. This function must be dispatched by a signed extrinsic. 66 | #[pallet::call_index(0)] 67 | #[pallet::weight(10_000 + T::DbWeight::get().writes(1).ref_time())] 68 | pub fn do_something(origin: OriginFor, something: u32) -> DispatchResult { 69 | // Check that the extrinsic was signed and get the signer. 70 | // This function will return an error if the extrinsic is not signed. 71 | // https://docs.substrate.io/main-docs/build/origins/ 72 | let who = ensure_signed(origin)?; 73 | 74 | // Update storage. 75 | >::put(something); 76 | 77 | // Emit an event. 78 | Self::deposit_event(Event::SomethingStored { something, who }); 79 | // Return a successful DispatchResultWithPostInfo 80 | Ok(()) 81 | } 82 | 83 | /// An example dispatchable that may throw a custom error. 84 | #[pallet::call_index(1)] 85 | #[pallet::weight(10_000 + T::DbWeight::get().reads_writes(1,1).ref_time())] 86 | pub fn cause_error(origin: OriginFor) -> DispatchResult { 87 | let _who = ensure_signed(origin)?; 88 | 89 | // Read a value from storage. 90 | match >::get() { 91 | // Return an error if the value has not been set. 92 | None => return Err(Error::::NoneValue.into()), 93 | Some(old) => { 94 | // Increment the value read from storage; will error in the event of overflow. 95 | let new = old.checked_add(1).ok_or(Error::::StorageOverflow)?; 96 | // Update the value in storage with the incremented result. 97 | >::put(new); 98 | Ok(()) 99 | }, 100 | } 101 | } 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /node/src/benchmarking.rs: -------------------------------------------------------------------------------- 1 | //! Setup code for [`super::command`] which would otherwise bloat that module. 2 | //! 3 | //! Should only be used for benchmarking as it may break in other contexts. 4 | 5 | use crate::service::FullClient; 6 | 7 | use node_template_runtime as runtime; 8 | use runtime::{AccountId, Balance, BalancesCall, SystemCall}; 9 | use sc_cli::Result; 10 | use sc_client_api::BlockBackend; 11 | use sp_core::{Encode, Pair}; 12 | use sp_inherents::{InherentData, InherentDataProvider}; 13 | use sp_keyring::Sr25519Keyring; 14 | use sp_runtime::{OpaqueExtrinsic, SaturatedConversion}; 15 | 16 | use std::{sync::Arc, time::Duration}; 17 | 18 | /// Generates extrinsics for the `benchmark overhead` command. 19 | /// 20 | /// Note: Should only be used for benchmarking. 21 | pub struct RemarkBuilder { 22 | client: Arc, 23 | } 24 | 25 | impl RemarkBuilder { 26 | /// Creates a new [`Self`] from the given client. 27 | pub fn new(client: Arc) -> Self { 28 | Self { client } 29 | } 30 | } 31 | 32 | impl frame_benchmarking_cli::ExtrinsicBuilder for RemarkBuilder { 33 | fn pallet(&self) -> &str { 34 | "system" 35 | } 36 | 37 | fn extrinsic(&self) -> &str { 38 | "remark" 39 | } 40 | 41 | fn build(&self, nonce: u32) -> std::result::Result { 42 | let acc = Sr25519Keyring::Bob.pair(); 43 | let extrinsic: OpaqueExtrinsic = create_benchmark_extrinsic( 44 | self.client.as_ref(), 45 | acc, 46 | SystemCall::remark { remark: vec![] }.into(), 47 | nonce, 48 | ) 49 | .into(); 50 | 51 | Ok(extrinsic) 52 | } 53 | } 54 | 55 | /// Generates `Balances::TransferKeepAlive` extrinsics for the benchmarks. 56 | /// 57 | /// Note: Should only be used for benchmarking. 58 | pub struct TransferKeepAliveBuilder { 59 | client: Arc, 60 | dest: AccountId, 61 | value: Balance, 62 | } 63 | 64 | impl TransferKeepAliveBuilder { 65 | /// Creates a new [`Self`] from the given client. 66 | pub fn new(client: Arc, dest: AccountId, value: Balance) -> Self { 67 | Self { client, dest, value } 68 | } 69 | } 70 | 71 | impl frame_benchmarking_cli::ExtrinsicBuilder for TransferKeepAliveBuilder { 72 | fn pallet(&self) -> &str { 73 | "balances" 74 | } 75 | 76 | fn extrinsic(&self) -> &str { 77 | "transfer_keep_alive" 78 | } 79 | 80 | fn build(&self, nonce: u32) -> std::result::Result { 81 | let acc = Sr25519Keyring::Bob.pair(); 82 | let extrinsic: OpaqueExtrinsic = create_benchmark_extrinsic( 83 | self.client.as_ref(), 84 | acc, 85 | BalancesCall::transfer_keep_alive { 86 | dest: self.dest.clone().into(), 87 | value: self.value.into(), 88 | } 89 | .into(), 90 | nonce, 91 | ) 92 | .into(); 93 | 94 | Ok(extrinsic) 95 | } 96 | } 97 | 98 | /// Create a transaction using the given `call`. 99 | /// 100 | /// Note: Should only be used for benchmarking. 101 | pub fn create_benchmark_extrinsic( 102 | client: &FullClient, 103 | sender: sp_core::sr25519::Pair, 104 | call: runtime::RuntimeCall, 105 | nonce: u32, 106 | ) -> runtime::UncheckedExtrinsic { 107 | let genesis_hash = client.block_hash(0).ok().flatten().expect("Genesis block exists; qed"); 108 | let best_hash = client.chain_info().best_hash; 109 | let best_block = client.chain_info().best_number; 110 | 111 | let period = runtime::BlockHashCount::get() 112 | .checked_next_power_of_two() 113 | .map(|c| c / 2) 114 | .unwrap_or(2) as u64; 115 | let extra: runtime::SignedExtra = ( 116 | frame_system::CheckNonZeroSender::::new(), 117 | frame_system::CheckSpecVersion::::new(), 118 | frame_system::CheckTxVersion::::new(), 119 | frame_system::CheckGenesis::::new(), 120 | frame_system::CheckEra::::from(sp_runtime::generic::Era::mortal( 121 | period, 122 | best_block.saturated_into(), 123 | )), 124 | frame_system::CheckNonce::::from(nonce), 125 | frame_system::CheckWeight::::new(), 126 | pallet_transaction_payment::ChargeTransactionPayment::::from(0), 127 | ); 128 | 129 | let raw_payload = runtime::SignedPayload::from_raw( 130 | call.clone(), 131 | extra.clone(), 132 | ( 133 | (), 134 | runtime::VERSION.spec_version, 135 | runtime::VERSION.transaction_version, 136 | genesis_hash, 137 | best_hash, 138 | (), 139 | (), 140 | (), 141 | ), 142 | ); 143 | let signature = raw_payload.using_encoded(|e| sender.sign(e)); 144 | 145 | runtime::UncheckedExtrinsic::new_signed( 146 | call.clone(), 147 | sp_runtime::AccountId32::from(sender.public()).into(), 148 | runtime::Signature::Sr25519(signature.clone()), 149 | extra.clone(), 150 | ) 151 | } 152 | 153 | /// Generates inherent data for the `benchmark overhead` command. 154 | /// 155 | /// Note: Should only be used for benchmarking. 156 | pub fn inherent_benchmark_data() -> Result { 157 | let mut inherent_data = InherentData::new(); 158 | let d = Duration::from_millis(0); 159 | let timestamp = sp_timestamp::InherentDataProvider::new(d.into()); 160 | 161 | futures::executor::block_on(timestamp.provide_inherent_data(&mut inherent_data)) 162 | .map_err(|e| format!("creating inherent data: {:?}", e))?; 163 | Ok(inherent_data) 164 | } 165 | -------------------------------------------------------------------------------- /node/src/chain_spec.rs: -------------------------------------------------------------------------------- 1 | use node_template_runtime::{ 2 | AccountId, AuraConfig, BalancesConfig, GenesisConfig, GrandpaConfig, Signature, SudoConfig, 3 | SystemConfig, WASM_BINARY, 4 | }; 5 | use sc_service::ChainType; 6 | use sp_consensus_aura::sr25519::AuthorityId as AuraId; 7 | use sp_consensus_grandpa::AuthorityId as GrandpaId; 8 | use sp_core::{sr25519, Pair, Public}; 9 | use sp_runtime::traits::{IdentifyAccount, Verify}; 10 | 11 | // The URL for the telemetry server. 12 | // const STAGING_TELEMETRY_URL: &str = "wss://telemetry.polkadot.io/submit/"; 13 | 14 | /// Specialized `ChainSpec`. This is a specialization of the general Substrate ChainSpec type. 15 | pub type ChainSpec = sc_service::GenericChainSpec; 16 | 17 | /// Generate a crypto pair from seed. 18 | pub fn get_from_seed(seed: &str) -> ::Public { 19 | TPublic::Pair::from_string(&format!("//{}", seed), None) 20 | .expect("static values are valid; qed") 21 | .public() 22 | } 23 | 24 | type AccountPublic = ::Signer; 25 | 26 | /// Generate an account ID from seed. 27 | pub fn get_account_id_from_seed(seed: &str) -> AccountId 28 | where 29 | AccountPublic: From<::Public>, 30 | { 31 | AccountPublic::from(get_from_seed::(seed)).into_account() 32 | } 33 | 34 | /// Generate an Aura authority key. 35 | pub fn authority_keys_from_seed(s: &str) -> (AuraId, GrandpaId) { 36 | (get_from_seed::(s), get_from_seed::(s)) 37 | } 38 | 39 | pub fn development_config() -> Result { 40 | let wasm_binary = WASM_BINARY.ok_or_else(|| "Development wasm not available".to_string())?; 41 | 42 | Ok(ChainSpec::from_genesis( 43 | // Name 44 | "Development", 45 | // ID 46 | "dev", 47 | ChainType::Development, 48 | move || { 49 | testnet_genesis( 50 | wasm_binary, 51 | // Initial PoA authorities 52 | vec![authority_keys_from_seed("Alice")], 53 | // Sudo account 54 | get_account_id_from_seed::("Alice"), 55 | // Pre-funded accounts 56 | vec![ 57 | get_account_id_from_seed::("Alice"), 58 | get_account_id_from_seed::("Bob"), 59 | get_account_id_from_seed::("Alice//stash"), 60 | get_account_id_from_seed::("Bob//stash"), 61 | ], 62 | true, 63 | ) 64 | }, 65 | // Bootnodes 66 | vec![], 67 | // Telemetry 68 | None, 69 | // Protocol ID 70 | None, 71 | None, 72 | // Properties 73 | None, 74 | // Extensions 75 | None, 76 | )) 77 | } 78 | 79 | pub fn local_testnet_config() -> Result { 80 | let wasm_binary = WASM_BINARY.ok_or_else(|| "Development wasm not available".to_string())?; 81 | 82 | Ok(ChainSpec::from_genesis( 83 | // Name 84 | "Local Testnet", 85 | // ID 86 | "local_testnet", 87 | ChainType::Local, 88 | move || { 89 | testnet_genesis( 90 | wasm_binary, 91 | // Initial PoA authorities 92 | vec![authority_keys_from_seed("Alice"), authority_keys_from_seed("Bob")], 93 | // Sudo account 94 | get_account_id_from_seed::("Alice"), 95 | // Pre-funded accounts 96 | vec![ 97 | get_account_id_from_seed::("Alice"), 98 | get_account_id_from_seed::("Bob"), 99 | get_account_id_from_seed::("Charlie"), 100 | get_account_id_from_seed::("Dave"), 101 | get_account_id_from_seed::("Eve"), 102 | get_account_id_from_seed::("Ferdie"), 103 | get_account_id_from_seed::("Alice//stash"), 104 | get_account_id_from_seed::("Bob//stash"), 105 | get_account_id_from_seed::("Charlie//stash"), 106 | get_account_id_from_seed::("Dave//stash"), 107 | get_account_id_from_seed::("Eve//stash"), 108 | get_account_id_from_seed::("Ferdie//stash"), 109 | ], 110 | true, 111 | ) 112 | }, 113 | // Bootnodes 114 | vec![], 115 | // Telemetry 116 | None, 117 | // Protocol ID 118 | None, 119 | // Properties 120 | None, 121 | None, 122 | // Extensions 123 | None, 124 | )) 125 | } 126 | 127 | /// Configure initial storage state for FRAME modules. 128 | fn testnet_genesis( 129 | wasm_binary: &[u8], 130 | initial_authorities: Vec<(AuraId, GrandpaId)>, 131 | root_key: AccountId, 132 | endowed_accounts: Vec, 133 | _enable_println: bool, 134 | ) -> GenesisConfig { 135 | GenesisConfig { 136 | system: SystemConfig { 137 | // Add Wasm runtime to storage. 138 | code: wasm_binary.to_vec(), 139 | }, 140 | balances: BalancesConfig { 141 | // Configure endowed accounts with initial balance of 1 << 60. 142 | balances: endowed_accounts.iter().cloned().map(|k| (k, 1 << 60)).collect(), 143 | }, 144 | aura: AuraConfig { 145 | authorities: initial_authorities.iter().map(|x| (x.0.clone())).collect(), 146 | }, 147 | grandpa: GrandpaConfig { 148 | authorities: initial_authorities.iter().map(|x| (x.1.clone(), 1)).collect(), 149 | }, 150 | sudo: SudoConfig { 151 | // Assign network admin rights. 152 | key: Some(root_key), 153 | }, 154 | transaction_payment: Default::default(), 155 | } 156 | } 157 | -------------------------------------------------------------------------------- /node/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "node-template" 3 | version = "4.0.0-dev" 4 | description = "A fresh FRAME-based Substrate node, ready for hacking." 5 | authors = ["Substrate DevHub "] 6 | homepage = "https://substrate.io/" 7 | edition = "2021" 8 | license = "Unlicense" 9 | publish = false 10 | repository = "https://github.com/substrate-developer-hub/substrate-node-template/" 11 | build = "build.rs" 12 | 13 | [package.metadata.docs.rs] 14 | targets = ["x86_64-unknown-linux-gnu"] 15 | 16 | [[bin]] 17 | name = "node-template" 18 | 19 | [dependencies] 20 | clap = { version = "4.0.9", features = ["derive"] } 21 | futures = { version = "0.3.21", features = ["thread-pool"]} 22 | 23 | sc-cli = { version = "0.10.0-dev", git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.40" } 24 | sp-core = { version = "7.0.0", git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.40" } 25 | sc-executor = { version = "0.10.0-dev", git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.40" } 26 | sc-service = { version = "0.10.0-dev", git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.40" } 27 | sc-telemetry = { version = "4.0.0-dev", git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.40" } 28 | sc-keystore = { version = "4.0.0-dev", git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.40" } 29 | sc-transaction-pool = { version = "4.0.0-dev", git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.40" } 30 | sc-transaction-pool-api = { version = "4.0.0-dev", git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.40" } 31 | sc-consensus-aura = { version = "0.10.0-dev", git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.40" } 32 | sp-consensus-aura = { version = "0.10.0-dev", git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.40" } 33 | sp-consensus = { version = "0.10.0-dev", git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.40" } 34 | sc-consensus = { version = "0.10.0-dev", git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.40" } 35 | sc-consensus-grandpa = { version = "0.10.0-dev", git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.40" } 36 | sp-consensus-grandpa = { version = "4.0.0-dev", git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.40" } 37 | sc-client-api = { version = "4.0.0-dev", git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.40" } 38 | sp-runtime = { version = "7.0.0", git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.40" } 39 | sp-io = { version = "7.0.0", git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.40" } 40 | sp-timestamp = { version = "4.0.0-dev", git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.40" } 41 | sp-inherents = { version = "4.0.0-dev", git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.40" } 42 | sp-keyring = { version = "7.0.0", git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.40" } 43 | frame-system = { version = "4.0.0-dev", git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.40" } 44 | pallet-transaction-payment = { version = "4.0.0-dev", default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.40" } 45 | 46 | # These dependencies are used for the node template's RPCs 47 | jsonrpsee = { version = "0.16.2", features = ["server"] } 48 | sc-rpc = { version = "4.0.0-dev", git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.40" } 49 | sp-api = { version = "4.0.0-dev", git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.40" } 50 | sc-rpc-api = { version = "0.10.0-dev", git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.40" } 51 | sp-blockchain = { version = "4.0.0-dev", git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.40" } 52 | sp-block-builder = { version = "4.0.0-dev", git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.40" } 53 | sc-basic-authorship = { version = "0.10.0-dev", git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.40" } 54 | substrate-frame-rpc-system = { version = "4.0.0-dev", git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.40" } 55 | pallet-transaction-payment-rpc = { version = "4.0.0-dev", git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.40" } 56 | 57 | # These dependencies are used for runtime benchmarking 58 | frame-benchmarking = { version = "4.0.0-dev", git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.40" } 59 | frame-benchmarking-cli = { version = "4.0.0-dev", git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.40" } 60 | 61 | # Local Dependencies 62 | node-template-runtime = { version = "4.0.0-dev", path = "../runtime" } 63 | 64 | # CLI-specific dependencies 65 | try-runtime-cli = { version = "0.10.0-dev", optional = true, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.40" } 66 | 67 | [build-dependencies] 68 | substrate-build-script-utils = { version = "3.0.0", git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.40" } 69 | 70 | [features] 71 | default = [] 72 | # Dependencies that are only required if runtime benchmarking should be build. 73 | runtime-benchmarks = [ 74 | "node-template-runtime/runtime-benchmarks", 75 | "frame-benchmarking/runtime-benchmarks", 76 | "frame-benchmarking-cli/runtime-benchmarks", 77 | ] 78 | # Enable features that allow the runtime to be tried and debugged. Name might be subject to change 79 | # in the near future. 80 | try-runtime = ["node-template-runtime/try-runtime", "try-runtime-cli/try-runtime"] 81 | -------------------------------------------------------------------------------- /runtime/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "node-template-runtime" 3 | version = "4.0.0-dev" 4 | description = "A fresh FRAME-based Substrate node, ready for hacking." 5 | authors = ["Substrate DevHub "] 6 | homepage = "https://substrate.io/" 7 | edition = "2021" 8 | license = "Unlicense" 9 | publish = false 10 | repository = "https://github.com/substrate-developer-hub/substrate-node-template/" 11 | 12 | [package.metadata.docs.rs] 13 | targets = ["x86_64-unknown-linux-gnu"] 14 | 15 | [dependencies] 16 | codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false, features = ["derive"] } 17 | scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } 18 | 19 | pallet-aura = { version = "4.0.0-dev", default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.40" } 20 | pallet-balances = { version = "4.0.0-dev", default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.40" } 21 | frame-support = { version = "4.0.0-dev", default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.40" } 22 | pallet-grandpa = { version = "4.0.0-dev", default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.40" } 23 | pallet-sudo = { version = "4.0.0-dev", default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.40" } 24 | frame-system = { version = "4.0.0-dev", default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.40" } 25 | frame-try-runtime = { version = "0.10.0-dev", default-features = false, git = "https://github.com/paritytech/substrate.git", optional = true , branch = "polkadot-v0.9.40" } 26 | pallet-timestamp = { version = "4.0.0-dev", default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.40" } 27 | pallet-transaction-payment = { version = "4.0.0-dev", default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.40" } 28 | frame-executive = { version = "4.0.0-dev", default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.40" } 29 | sp-api = { version = "4.0.0-dev", default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.40" } 30 | sp-block-builder = { version = "4.0.0-dev", default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.40" } 31 | sp-consensus-aura = { version = "0.10.0-dev", default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.40" } 32 | sp-consensus-grandpa = { version = "4.0.0-dev", default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.40" } 33 | sp-core = { version = "7.0.0", default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.40" } 34 | sp-inherents = { version = "4.0.0-dev", default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.40" } 35 | sp-offchain = { version = "4.0.0-dev", default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.40" } 36 | sp-runtime = { version = "7.0.0", default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.40" } 37 | sp-session = { version = "4.0.0-dev", default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.40" } 38 | sp-std = { version = "5.0.0", default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.40" } 39 | sp-transaction-pool = { version = "4.0.0-dev", default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.40" } 40 | sp-version = { version = "5.0.0", default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.40" } 41 | 42 | # Used for the node template's RPCs 43 | frame-system-rpc-runtime-api = { version = "4.0.0-dev", default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.40" } 44 | pallet-transaction-payment-rpc-runtime-api = { version = "4.0.0-dev", default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.40" } 45 | 46 | # Used for runtime benchmarking 47 | frame-benchmarking = { version = "4.0.0-dev", default-features = false, git = "https://github.com/paritytech/substrate.git", optional = true , branch = "polkadot-v0.9.40" } 48 | frame-system-benchmarking = { version = "4.0.0-dev", default-features = false, git = "https://github.com/paritytech/substrate.git", optional = true , branch = "polkadot-v0.9.40" } 49 | 50 | # Local Dependencies 51 | pallet-template = { version = "4.0.0-dev", default-features = false, path = "../pallets/template" } 52 | 53 | [build-dependencies] 54 | substrate-wasm-builder = { version = "5.0.0-dev", git = "https://github.com/paritytech/substrate.git", optional = true , branch = "polkadot-v0.9.40" } 55 | 56 | [features] 57 | default = ["std"] 58 | std = [ 59 | "frame-try-runtime?/std", 60 | "frame-system-benchmarking?/std", 61 | "frame-benchmarking?/std", 62 | "codec/std", 63 | "scale-info/std", 64 | "frame-executive/std", 65 | "frame-support/std", 66 | "frame-system-rpc-runtime-api/std", 67 | "frame-system/std", 68 | "frame-try-runtime/std", 69 | "pallet-aura/std", 70 | "pallet-balances/std", 71 | "pallet-grandpa/std", 72 | "pallet-sudo/std", 73 | "pallet-template/std", 74 | "pallet-timestamp/std", 75 | "pallet-transaction-payment-rpc-runtime-api/std", 76 | "pallet-transaction-payment/std", 77 | "sp-api/std", 78 | "sp-block-builder/std", 79 | "sp-consensus-aura/std", 80 | "sp-consensus-grandpa/std", 81 | "sp-core/std", 82 | "sp-inherents/std", 83 | "sp-offchain/std", 84 | "sp-runtime/std", 85 | "sp-session/std", 86 | "sp-std/std", 87 | "sp-transaction-pool/std", 88 | "sp-version/std", 89 | "substrate-wasm-builder", 90 | ] 91 | runtime-benchmarks = [ 92 | "frame-benchmarking/runtime-benchmarks", 93 | "frame-support/runtime-benchmarks", 94 | "frame-system-benchmarking/runtime-benchmarks", 95 | "frame-system/runtime-benchmarks", 96 | "pallet-balances/runtime-benchmarks", 97 | "pallet-grandpa/runtime-benchmarks", 98 | "pallet-template/runtime-benchmarks", 99 | "pallet-timestamp/runtime-benchmarks", 100 | "sp-runtime/runtime-benchmarks", 101 | ] 102 | try-runtime = [ 103 | "frame-try-runtime/try-runtime", 104 | "frame-executive/try-runtime", 105 | "frame-system/try-runtime", 106 | "frame-support/try-runtime", 107 | "pallet-aura/try-runtime", 108 | "pallet-balances/try-runtime", 109 | "pallet-grandpa/try-runtime", 110 | "pallet-sudo/try-runtime", 111 | "pallet-template/try-runtime", 112 | "pallet-timestamp/try-runtime", 113 | "pallet-transaction-payment/try-runtime", 114 | ] 115 | -------------------------------------------------------------------------------- /node/src/command.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | benchmarking::{inherent_benchmark_data, RemarkBuilder, TransferKeepAliveBuilder}, 3 | chain_spec, 4 | cli::{Cli, Subcommand}, 5 | service, 6 | }; 7 | use frame_benchmarking_cli::{BenchmarkCmd, ExtrinsicFactory, SUBSTRATE_REFERENCE_HARDWARE}; 8 | use node_template_runtime::{Block, EXISTENTIAL_DEPOSIT}; 9 | use sc_cli::{ChainSpec, RuntimeVersion, SubstrateCli}; 10 | use sc_service::PartialComponents; 11 | use sp_keyring::Sr25519Keyring; 12 | 13 | #[cfg(feature = "try-runtime")] 14 | use try_runtime_cli::block_building_info::timestamp_with_aura_info; 15 | 16 | impl SubstrateCli for Cli { 17 | fn impl_name() -> String { 18 | "Substrate Node".into() 19 | } 20 | 21 | fn impl_version() -> String { 22 | env!("SUBSTRATE_CLI_IMPL_VERSION").into() 23 | } 24 | 25 | fn description() -> String { 26 | env!("CARGO_PKG_DESCRIPTION").into() 27 | } 28 | 29 | fn author() -> String { 30 | env!("CARGO_PKG_AUTHORS").into() 31 | } 32 | 33 | fn support_url() -> String { 34 | "support.anonymous.an".into() 35 | } 36 | 37 | fn copyright_start_year() -> i32 { 38 | 2017 39 | } 40 | 41 | fn load_spec(&self, id: &str) -> Result, String> { 42 | Ok(match id { 43 | "dev" => Box::new(chain_spec::development_config()?), 44 | "" | "local" => Box::new(chain_spec::local_testnet_config()?), 45 | path => 46 | Box::new(chain_spec::ChainSpec::from_json_file(std::path::PathBuf::from(path))?), 47 | }) 48 | } 49 | 50 | fn native_runtime_version(_: &Box) -> &'static RuntimeVersion { 51 | &node_template_runtime::VERSION 52 | } 53 | } 54 | 55 | /// Parse and run command line arguments 56 | pub fn run() -> sc_cli::Result<()> { 57 | let cli = Cli::from_args(); 58 | 59 | match &cli.subcommand { 60 | Some(Subcommand::Key(cmd)) => cmd.run(&cli), 61 | Some(Subcommand::BuildSpec(cmd)) => { 62 | let runner = cli.create_runner(cmd)?; 63 | runner.sync_run(|config| cmd.run(config.chain_spec, config.network)) 64 | }, 65 | Some(Subcommand::CheckBlock(cmd)) => { 66 | let runner = cli.create_runner(cmd)?; 67 | runner.async_run(|config| { 68 | let PartialComponents { client, task_manager, import_queue, .. } = 69 | service::new_partial(&config)?; 70 | Ok((cmd.run(client, import_queue), task_manager)) 71 | }) 72 | }, 73 | Some(Subcommand::ExportBlocks(cmd)) => { 74 | let runner = cli.create_runner(cmd)?; 75 | runner.async_run(|config| { 76 | let PartialComponents { client, task_manager, .. } = service::new_partial(&config)?; 77 | Ok((cmd.run(client, config.database), task_manager)) 78 | }) 79 | }, 80 | Some(Subcommand::ExportState(cmd)) => { 81 | let runner = cli.create_runner(cmd)?; 82 | runner.async_run(|config| { 83 | let PartialComponents { client, task_manager, .. } = service::new_partial(&config)?; 84 | Ok((cmd.run(client, config.chain_spec), task_manager)) 85 | }) 86 | }, 87 | Some(Subcommand::ImportBlocks(cmd)) => { 88 | let runner = cli.create_runner(cmd)?; 89 | runner.async_run(|config| { 90 | let PartialComponents { client, task_manager, import_queue, .. } = 91 | service::new_partial(&config)?; 92 | Ok((cmd.run(client, import_queue), task_manager)) 93 | }) 94 | }, 95 | Some(Subcommand::PurgeChain(cmd)) => { 96 | let runner = cli.create_runner(cmd)?; 97 | runner.sync_run(|config| cmd.run(config.database)) 98 | }, 99 | Some(Subcommand::Revert(cmd)) => { 100 | let runner = cli.create_runner(cmd)?; 101 | runner.async_run(|config| { 102 | let PartialComponents { client, task_manager, backend, .. } = 103 | service::new_partial(&config)?; 104 | let aux_revert = Box::new(|client, _, blocks| { 105 | sc_consensus_grandpa::revert(client, blocks)?; 106 | Ok(()) 107 | }); 108 | Ok((cmd.run(client, backend, Some(aux_revert)), task_manager)) 109 | }) 110 | }, 111 | Some(Subcommand::Benchmark(cmd)) => { 112 | let runner = cli.create_runner(cmd)?; 113 | 114 | runner.sync_run(|config| { 115 | // This switch needs to be in the client, since the client decides 116 | // which sub-commands it wants to support. 117 | match cmd { 118 | BenchmarkCmd::Pallet(cmd) => { 119 | if !cfg!(feature = "runtime-benchmarks") { 120 | return Err( 121 | "Runtime benchmarking wasn't enabled when building the node. \ 122 | You can enable it with `--features runtime-benchmarks`." 123 | .into(), 124 | ) 125 | } 126 | 127 | cmd.run::(config) 128 | }, 129 | BenchmarkCmd::Block(cmd) => { 130 | let PartialComponents { client, .. } = service::new_partial(&config)?; 131 | cmd.run(client) 132 | }, 133 | #[cfg(not(feature = "runtime-benchmarks"))] 134 | BenchmarkCmd::Storage(_) => Err( 135 | "Storage benchmarking can be enabled with `--features runtime-benchmarks`." 136 | .into(), 137 | ), 138 | #[cfg(feature = "runtime-benchmarks")] 139 | BenchmarkCmd::Storage(cmd) => { 140 | let PartialComponents { client, backend, .. } = 141 | service::new_partial(&config)?; 142 | let db = backend.expose_db(); 143 | let storage = backend.expose_storage(); 144 | 145 | cmd.run(config, client, db, storage) 146 | }, 147 | BenchmarkCmd::Overhead(cmd) => { 148 | let PartialComponents { client, .. } = service::new_partial(&config)?; 149 | let ext_builder = RemarkBuilder::new(client.clone()); 150 | 151 | cmd.run( 152 | config, 153 | client, 154 | inherent_benchmark_data()?, 155 | Vec::new(), 156 | &ext_builder, 157 | ) 158 | }, 159 | BenchmarkCmd::Extrinsic(cmd) => { 160 | let PartialComponents { client, .. } = service::new_partial(&config)?; 161 | // Register the *Remark* and *TKA* builders. 162 | let ext_factory = ExtrinsicFactory(vec![ 163 | Box::new(RemarkBuilder::new(client.clone())), 164 | Box::new(TransferKeepAliveBuilder::new( 165 | client.clone(), 166 | Sr25519Keyring::Alice.to_account_id(), 167 | EXISTENTIAL_DEPOSIT, 168 | )), 169 | ]); 170 | 171 | cmd.run(client, inherent_benchmark_data()?, Vec::new(), &ext_factory) 172 | }, 173 | BenchmarkCmd::Machine(cmd) => 174 | cmd.run(&config, SUBSTRATE_REFERENCE_HARDWARE.clone()), 175 | } 176 | }) 177 | }, 178 | #[cfg(feature = "try-runtime")] 179 | Some(Subcommand::TryRuntime(cmd)) => { 180 | use crate::service::ExecutorDispatch; 181 | use sc_executor::{sp_wasm_interface::ExtendedHostFunctions, NativeExecutionDispatch}; 182 | let runner = cli.create_runner(cmd)?; 183 | runner.async_run(|config| { 184 | // we don't need any of the components of new_partial, just a runtime, or a task 185 | // manager to do `async_run`. 186 | let registry = config.prometheus_config.as_ref().map(|cfg| &cfg.registry); 187 | let task_manager = 188 | sc_service::TaskManager::new(config.tokio_handle.clone(), registry) 189 | .map_err(|e| sc_cli::Error::Service(sc_service::Error::Prometheus(e)))?; 190 | let info_provider = timestamp_with_aura_info(6000); 191 | 192 | Ok(( 193 | cmd.run::::ExtendHostFunctions, 196 | >, _>(Some(info_provider)), 197 | task_manager, 198 | )) 199 | }) 200 | }, 201 | #[cfg(not(feature = "try-runtime"))] 202 | Some(Subcommand::TryRuntime) => Err("TryRuntime wasn't enabled when building the node. \ 203 | You can enable it with `--features try-runtime`." 204 | .into()), 205 | Some(Subcommand::ChainInfo(cmd)) => { 206 | let runner = cli.create_runner(cmd)?; 207 | runner.sync_run(|config| cmd.run::(&config)) 208 | }, 209 | None => { 210 | let runner = cli.create_runner(&cli.run)?; 211 | runner.run_node_until_exit(|config| async move { 212 | service::new_full(config).map_err(sc_cli::Error::Service) 213 | }) 214 | }, 215 | } 216 | } 217 | -------------------------------------------------------------------------------- /docs/rust-setup.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Installation 3 | --- 4 | 5 | This guide is for reference only, please check the latest information on getting starting with Substrate 6 | [here](https://docs.substrate.io/main-docs/install/). 7 | 8 | This page will guide you through the **2 steps** needed to prepare a computer for **Substrate** development. 9 | Since Substrate is built with [the Rust programming language](https://www.rust-lang.org/), the first 10 | thing you will need to do is prepare the computer for Rust development - these steps will vary based 11 | on the computer's operating system. Once Rust is configured, you will use its toolchains to interact 12 | with Rust projects; the commands for Rust's toolchains will be the same for all supported, 13 | Unix-based operating systems. 14 | 15 | ## Build dependencies 16 | 17 | Substrate development is easiest on Unix-based operating systems like macOS or Linux. The examples 18 | in the [Substrate Docs](https://docs.substrate.io) use Unix-style terminals to demonstrate how to 19 | interact with Substrate from the command line. 20 | 21 | ### Ubuntu/Debian 22 | 23 | Use a terminal shell to execute the following commands: 24 | 25 | ```bash 26 | sudo apt update 27 | # May prompt for location information 28 | sudo apt install -y git clang curl libssl-dev llvm libudev-dev 29 | ``` 30 | 31 | ### Arch Linux 32 | 33 | Run these commands from a terminal: 34 | 35 | ```bash 36 | pacman -Syu --needed --noconfirm curl git clang 37 | ``` 38 | 39 | ### Fedora 40 | 41 | Run these commands from a terminal: 42 | 43 | ```bash 44 | sudo dnf update 45 | sudo dnf install clang curl git openssl-devel 46 | ``` 47 | 48 | ### OpenSUSE 49 | 50 | Run these commands from a terminal: 51 | 52 | ```bash 53 | sudo zypper install clang curl git openssl-devel llvm-devel libudev-devel 54 | ``` 55 | 56 | ### macOS 57 | 58 | > **Apple M1 ARM** 59 | > If you have an Apple M1 ARM system on a chip, make sure that you have Apple Rosetta 2 60 | > installed through `softwareupdate --install-rosetta`. This is only needed to run the 61 | > `protoc` tool during the build. The build itself and the target binaries would remain native. 62 | 63 | Open the Terminal application and execute the following commands: 64 | 65 | ```bash 66 | # Install Homebrew if necessary https://brew.sh/ 67 | /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)" 68 | 69 | # Make sure Homebrew is up-to-date, install openssl 70 | brew update 71 | brew install openssl 72 | ``` 73 | 74 | ### Windows 75 | 76 | **_PLEASE NOTE:_** Native Windows development of Substrate is _not_ very well supported! It is _highly_ 77 | recommend to use [Windows Subsystem Linux](https://docs.microsoft.com/en-us/windows/wsl/install-win10) 78 | (WSL) and follow the instructions for [Ubuntu/Debian](#ubuntudebian). 79 | Please refer to the separate 80 | [guide for native Windows development](https://docs.substrate.io/main-docs/install/windows/). 81 | 82 | ## Rust developer environment 83 | 84 | This guide uses installer and the `rustup` tool to manage the Rust toolchain. 85 | First install and configure `rustup`: 86 | 87 | ```bash 88 | # Install 89 | curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh 90 | # Configure 91 | source ~/.cargo/env 92 | ``` 93 | 94 | Configure the Rust toolchain to default to the latest stable version, add nightly and the nightly wasm target: 95 | 96 | ```bash 97 | rustup default stable 98 | rustup update 99 | rustup update nightly 100 | rustup target add wasm32-unknown-unknown --toolchain nightly 101 | ``` 102 | 103 | ## Test your set-up 104 | 105 | Now the best way to ensure that you have successfully prepared a computer for Substrate 106 | development is to follow the steps in [our first Substrate tutorial](https://docs.substrate.io/tutorials/v3/create-your-first-substrate-chain/). 107 | 108 | ## Troubleshooting Substrate builds 109 | 110 | Sometimes you can't get the Substrate node template 111 | to compile out of the box. Here are some tips to help you work through that. 112 | 113 | ### Rust configuration check 114 | 115 | To see what Rust toolchain you are presently using, run: 116 | 117 | ```bash 118 | rustup show 119 | ``` 120 | 121 | This will show something like this (Ubuntu example) output: 122 | 123 | ```text 124 | Default host: x86_64-unknown-linux-gnu 125 | rustup home: /home/user/.rustup 126 | 127 | installed toolchains 128 | -------------------- 129 | 130 | stable-x86_64-unknown-linux-gnu (default) 131 | nightly-2020-10-06-x86_64-unknown-linux-gnu 132 | nightly-x86_64-unknown-linux-gnu 133 | 134 | installed targets for active toolchain 135 | -------------------------------------- 136 | 137 | wasm32-unknown-unknown 138 | x86_64-unknown-linux-gnu 139 | 140 | active toolchain 141 | ---------------- 142 | 143 | stable-x86_64-unknown-linux-gnu (default) 144 | rustc 1.50.0 (cb75ad5db 2021-02-10) 145 | ``` 146 | 147 | As you can see above, the default toolchain is stable, and the 148 | `nightly-x86_64-unknown-linux-gnu` toolchain as well as its `wasm32-unknown-unknown` target is installed. 149 | You also see that `nightly-2020-10-06-x86_64-unknown-linux-gnu` is installed, but is not used unless explicitly defined as illustrated in the [specify your nightly version](#specifying-nightly-version) 150 | section. 151 | 152 | ### WebAssembly compilation 153 | 154 | Substrate uses [WebAssembly](https://webassembly.org) (Wasm) to produce portable blockchain 155 | runtimes. You will need to configure your Rust compiler to use 156 | [`nightly` builds](https://doc.rust-lang.org/book/appendix-07-nightly-rust.html) to allow you to 157 | compile Substrate runtime code to the Wasm target. 158 | 159 | > There are upstream issues in Rust that need to be resolved before all of Substrate can use the stable Rust toolchain. 160 | > [This is our tracking issue](https://github.com/paritytech/substrate/issues/1252) if you're curious as to why and how this will be resolved. 161 | 162 | #### Latest nightly for Substrate `master` 163 | 164 | Developers who are building Substrate _itself_ should always use the latest bug-free versions of 165 | Rust stable and nightly. This is because the Substrate codebase follows the tip of Rust nightly, 166 | which means that changes in Substrate often depend on upstream changes in the Rust nightly compiler. 167 | To ensure your Rust compiler is always up to date, you should run: 168 | 169 | ```bash 170 | rustup update 171 | rustup update nightly 172 | rustup target add wasm32-unknown-unknown --toolchain nightly 173 | ``` 174 | 175 | > NOTE: It may be necessary to occasionally rerun `rustup update` if a change in the upstream Substrate 176 | > codebase depends on a new feature of the Rust compiler. When you do this, both your nightly 177 | > and stable toolchains will be pulled to the most recent release, and for nightly, it is 178 | > generally _not_ expected to compile WASM without error (although it very often does). 179 | > Be sure to [specify your nightly version](#specifying-nightly-version) if you get WASM build errors 180 | > from `rustup` and [downgrade nightly as needed](#downgrading-rust-nightly). 181 | 182 | #### Rust nightly toolchain 183 | 184 | If you want to guarantee that your build works on your computer as you update Rust and other 185 | dependencies, you should use a specific Rust nightly version that is known to be 186 | compatible with the version of Substrate they are using; this version will vary from project to 187 | project and different projects may use different mechanisms to communicate this version to 188 | developers. For instance, the Polkadot client specifies this information in its 189 | [release notes](https://github.com/paritytech/polkadot/releases). 190 | 191 | ```bash 192 | # Specify the specific nightly toolchain in the date below: 193 | rustup install nightly- 194 | ``` 195 | 196 | #### Wasm toolchain 197 | 198 | Now, configure the nightly version to work with the Wasm compilation target: 199 | 200 | ```bash 201 | rustup target add wasm32-unknown-unknown --toolchain nightly- 202 | ``` 203 | 204 | ### Specifying nightly version 205 | 206 | Use the `WASM_BUILD_TOOLCHAIN` environment variable to specify the Rust nightly version a Substrate 207 | project should use for Wasm compilation: 208 | 209 | ```bash 210 | WASM_BUILD_TOOLCHAIN=nightly- cargo build --release 211 | ``` 212 | 213 | > Note that this only builds _the runtime_ with the specified nightly. The rest of project will be 214 | > compiled with **your default toolchain**, i.e. the latest installed stable toolchain. 215 | 216 | ### Downgrading Rust nightly 217 | 218 | If your computer is configured to use the latest Rust nightly and you would like to downgrade to a 219 | specific nightly version, follow these steps: 220 | 221 | ```bash 222 | rustup uninstall nightly 223 | rustup install nightly- 224 | rustup target add wasm32-unknown-unknown --toolchain nightly- 225 | ``` 226 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Substrate Node Template 2 | 3 | A fresh [Substrate](https://substrate.io/) node, ready for hacking :rocket: 4 | 5 | A standalone version of this template is available for each release of Polkadot in the [Substrate Developer Hub Parachain Template](https://github.com/substrate-developer-hub/substrate-parachain-template/) repository. 6 | The parachain template is generated directly at each Polkadot release branch from the [Node Template in Substrate](https://github.com/paritytech/substrate/tree/master/bin/node-template) upstream 7 | 8 | It is usually best to use the stand-alone version to start a new project. 9 | All bugs, suggestions, and feature requests should be made upstream in the [Substrate](https://github.com/paritytech/substrate/tree/master/bin/node-template) repository. 10 | 11 | ## Getting Started 12 | 13 | Depending on your operating system and Rust version, there might be additional packages required to compile this template. 14 | Check the [Install](https://docs.substrate.io/install/) instructions for your platform for the most common dependencies. 15 | Alternatively, you can use one of the [alternative installation](#alternatives-installations) options. 16 | 17 | ### Build 18 | 19 | Use the following command to build the node without launching it: 20 | 21 | ```sh 22 | cargo build --release 23 | ``` 24 | 25 | ### Embedded Docs 26 | 27 | After you build the project, you can use the following command to explore its parameters and subcommands: 28 | 29 | ```sh 30 | ./target/release/node-template -h 31 | ``` 32 | 33 | You can generate and view the [Rust Docs](https://doc.rust-lang.org/cargo/commands/cargo-doc.html) for this template with this command: 34 | 35 | ```sh 36 | cargo +nightly doc --open 37 | ``` 38 | 39 | ### Single-Node Development Chain 40 | 41 | The following command starts a single-node development chain that doesn't persist state: 42 | 43 | ```sh 44 | ./target/release/node-template --dev 45 | ``` 46 | 47 | To purge the development chain's state, run the following command: 48 | 49 | ```sh 50 | ./target/release/node-template purge-chain --dev 51 | ``` 52 | 53 | To start the development chain with detailed logging, run the following command: 54 | 55 | ```sh 56 | RUST_BACKTRACE=1 ./target/release/node-template -ldebug --dev 57 | ``` 58 | 59 | Development chains: 60 | 61 | - Maintain state in a `tmp` folder while the node is running. 62 | - Use the **Alice** and **Bob** accounts as default validator authorities. 63 | - Use the **Alice** account as the default `sudo` account. 64 | - Are preconfigured with a genesis state (`/node/src/chain_spec.rs`) that includes several prefunded development accounts. 65 | 66 | 67 | To persist chain state between runs, specify a base path by running a command similar to the following: 68 | 69 | ```sh 70 | // Create a folder to use as the db base path 71 | $ mkdir my-chain-state 72 | 73 | // Use of that folder to store the chain state 74 | $ ./target/release/node-template --dev --base-path ./my-chain-state/ 75 | 76 | // Check the folder structure created inside the base path after running the chain 77 | $ ls ./my-chain-state 78 | chains 79 | $ ls ./my-chain-state/chains/ 80 | dev 81 | $ ls ./my-chain-state/chains/dev 82 | db keystore network 83 | ``` 84 | 85 | ### Connect with Polkadot-JS Apps Front-End 86 | 87 | After you start the node template locally, you can interact with it using the hosted version of the [Polkadot/Substrate Portal](https://polkadot.js.org/apps/#/explorer?rpc=ws://localhost:9944) front-end by connecting to the local node endpoint. 88 | A hosted version is also available on [IPFS (redirect) here](https://dotapps.io/) or [IPNS (direct) here](ipns://dotapps.io/?rpc=ws%3A%2F%2F127.0.0.1%3A9944#/explorer). 89 | You can also find the source code and instructions for hosting your own instance on the [polkadot-js/apps](https://github.com/polkadot-js/apps) repository. 90 | 91 | ### Multi-Node Local Testnet 92 | 93 | If you want to see the multi-node consensus algorithm in action, see [Simulate a network](https://docs.substrate.io/tutorials/get-started/simulate-network/). 94 | 95 | ## Template Structure 96 | 97 | A Substrate project such as this consists of a number of components that are spread across a few directories. 98 | 99 | ### Node 100 | 101 | A blockchain node is an application that allows users to participate in a blockchain network. 102 | Substrate-based blockchain nodes expose a number of capabilities: 103 | 104 | - Networking: Substrate nodes use the [`libp2p`](https://libp2p.io/) networking stack to allow the 105 | nodes in the network to communicate with one another. 106 | - Consensus: Blockchains must have a way to come to [consensus](https://docs.substrate.io/fundamentals/consensus/) on the state of the network. 107 | Substrate makes it possible to supply custom consensus engines and also ships with several consensus mechanisms that have been built on top of [Web3 Foundation research](https://research.web3.foundation/en/latest/polkadot/NPoS/index.html). 108 | - RPC Server: A remote procedure call (RPC) server is used to interact with Substrate nodes. 109 | 110 | There are several files in the `node` directory. 111 | Take special note of the following: 112 | 113 | - [`chain_spec.rs`](./node/src/chain_spec.rs): A [chain specification](https://docs.substrate.io/build/chain-spec/) is a source code file that defines a Substrate chain's initial (genesis) state. 114 | Chain specifications are useful for development and testing, and critical when architecting the launch of a production chain. 115 | Take note of the `development_config` and `testnet_genesis` functions,. 116 | These functions are used to define the genesis state for the local development chain configuration. 117 | These functions identify some [well-known accounts](https://docs.substrate.io/reference/command-line-tools/subkey/) and use them to configure the blockchain's initial state. 118 | - [`service.rs`](./node/src/service.rs): This file defines the node implementation. 119 | Take note of the libraries that this file imports and the names of the functions it invokes. 120 | In particular, there are references to consensus-related topics, such as the [block finalization and forks](https://docs.substrate.io/fundamentals/consensus/#finalization-and-forks) and other [consensus mechanisms](https://docs.substrate.io/fundamentals/consensus/#default-consensus-models) such as Aura for block authoring and GRANDPA for finality. 121 | 122 | 123 | 124 | ### Runtime 125 | 126 | In Substrate, the terms "runtime" and "state transition function" are analogous. 127 | Both terms refer to the core logic of the blockchain that is responsible for validating blocks and executing the state changes they define. 128 | The Substrate project in this repository uses [FRAME](https://docs.substrate.io/fundamentals/runtime-development/#frame) to construct a blockchain runtime. 129 | FRAME allows runtime developers to declare domain-specific logic in modules called "pallets". 130 | At the heart of FRAME is a helpful [macro language](https://docs.substrate.io/reference/frame-macros/) that makes it easy to create pallets and flexibly compose them to create blockchains that can address [a variety of needs](https://substrate.io/ecosystem/projects/). 131 | 132 | Review the [FRAME runtime implementation](./runtime/src/lib.rs) included in this template and note the following: 133 | 134 | - This file configures several pallets to include in the runtime. 135 | Each pallet configuration is defined by a code block that begins with `impl $PALLET_NAME::Config for Runtime`. 136 | - The pallets are composed into a single runtime by way of the [`construct_runtime!`](https://crates.parity.io/frame_support/macro.construct_runtime.html) macro, which is part of the core FRAME Support [system](https://docs.substrate.io/reference/frame-pallets/#system-pallets) library. 137 | 138 | ### Pallets 139 | 140 | The runtime in this project is constructed using many FRAME pallets that ship with the [core Substrate repository](https://github.com/paritytech/substrate/tree/master/frame) and a template pallet that is [defined in the `pallets`](./pallets/template/src/lib.rs) directory. 141 | 142 | A FRAME pallet is compromised of a number of blockchain primitives: 143 | 144 | - Storage: FRAME defines a rich set of powerful [storage abstractions](https://docs.substrate.io/build/runtime-storage/) that makes it easy to use Substrate's efficient key-value database to manage the evolving state of a blockchain. 145 | - Dispatchables: FRAME pallets define special types of functions that can be invoked (dispatched) from outside of the runtime in order to update its state. 146 | - Events: Substrate uses [events and errors](https://docs.substrate.io/build/events-and-errors/) to notify users of important changes in the runtime. 147 | - Errors: When a dispatchable fails, it returns an error. 148 | - Config: The `Config` configuration interface is used to define the types and parameters upon which a FRAME pallet depends. 149 | 150 | ## Alternatives Installations 151 | 152 | Instead of installing dependencies and building this source directly, consider the following alternatives. 153 | 154 | ### Nix 155 | 156 | Install [nix](https://nixos.org/), and optionally [direnv](https://github.com/direnv/direnv) and [lorri](https://github.com/nix-community/lorri) for a fully plug-and-play experience for setting up the development environment. 157 | To get all the correct dependencies, activate direnv `direnv allow` and lorri `lorri shell`. 158 | 159 | ### Docker 160 | 161 | Please follow the [Substrate Docker instructions here](https://github.com/paritytech/substrate/blob/master/docker/README.md) to build the Docker container with the Substrate Node Template binary. 162 | -------------------------------------------------------------------------------- /node/src/service.rs: -------------------------------------------------------------------------------- 1 | //! Service and ServiceFactory implementation. Specialized wrapper over substrate service. 2 | 3 | use node_template_runtime::{self, opaque::Block, RuntimeApi}; 4 | use sc_client_api::BlockBackend; 5 | use sc_consensus_aura::{ImportQueueParams, SlotProportion, StartAuraParams}; 6 | use sc_consensus_grandpa::SharedVoterState; 7 | pub use sc_executor::NativeElseWasmExecutor; 8 | use sc_keystore::LocalKeystore; 9 | use sc_service::{error::Error as ServiceError, Configuration, TaskManager, WarpSyncParams}; 10 | use sc_telemetry::{Telemetry, TelemetryWorker}; 11 | use sp_consensus_aura::sr25519::AuthorityPair as AuraPair; 12 | use std::{sync::Arc, time::Duration}; 13 | 14 | // Our native executor instance. 15 | pub struct ExecutorDispatch; 16 | 17 | impl sc_executor::NativeExecutionDispatch for ExecutorDispatch { 18 | /// Only enable the benchmarking host functions when we actually want to benchmark. 19 | #[cfg(feature = "runtime-benchmarks")] 20 | type ExtendHostFunctions = frame_benchmarking::benchmarking::HostFunctions; 21 | /// Otherwise we only use the default Substrate host functions. 22 | #[cfg(not(feature = "runtime-benchmarks"))] 23 | type ExtendHostFunctions = (); 24 | 25 | fn dispatch(method: &str, data: &[u8]) -> Option> { 26 | node_template_runtime::api::dispatch(method, data) 27 | } 28 | 29 | fn native_version() -> sc_executor::NativeVersion { 30 | node_template_runtime::native_version() 31 | } 32 | } 33 | 34 | pub(crate) type FullClient = 35 | sc_service::TFullClient>; 36 | type FullBackend = sc_service::TFullBackend; 37 | type FullSelectChain = sc_consensus::LongestChain; 38 | 39 | pub fn new_partial( 40 | config: &Configuration, 41 | ) -> Result< 42 | sc_service::PartialComponents< 43 | FullClient, 44 | FullBackend, 45 | FullSelectChain, 46 | sc_consensus::DefaultImportQueue, 47 | sc_transaction_pool::FullPool, 48 | ( 49 | sc_consensus_grandpa::GrandpaBlockImport< 50 | FullBackend, 51 | Block, 52 | FullClient, 53 | FullSelectChain, 54 | >, 55 | sc_consensus_grandpa::LinkHalf, 56 | Option, 57 | ), 58 | >, 59 | ServiceError, 60 | > { 61 | if config.keystore_remote.is_some() { 62 | return Err(ServiceError::Other("Remote Keystores are not supported.".into())) 63 | } 64 | 65 | let telemetry = config 66 | .telemetry_endpoints 67 | .clone() 68 | .filter(|x| !x.is_empty()) 69 | .map(|endpoints| -> Result<_, sc_telemetry::Error> { 70 | let worker = TelemetryWorker::new(16)?; 71 | let telemetry = worker.handle().new_telemetry(endpoints); 72 | Ok((worker, telemetry)) 73 | }) 74 | .transpose()?; 75 | 76 | let executor = NativeElseWasmExecutor::::new( 77 | config.wasm_method, 78 | config.default_heap_pages, 79 | config.max_runtime_instances, 80 | config.runtime_cache_size, 81 | ); 82 | 83 | let (client, backend, keystore_container, task_manager) = 84 | sc_service::new_full_parts::( 85 | config, 86 | telemetry.as_ref().map(|(_, telemetry)| telemetry.handle()), 87 | executor, 88 | )?; 89 | let client = Arc::new(client); 90 | 91 | let telemetry = telemetry.map(|(worker, telemetry)| { 92 | task_manager.spawn_handle().spawn("telemetry", None, worker.run()); 93 | telemetry 94 | }); 95 | 96 | let select_chain = sc_consensus::LongestChain::new(backend.clone()); 97 | 98 | let transaction_pool = sc_transaction_pool::BasicPool::new_full( 99 | config.transaction_pool.clone(), 100 | config.role.is_authority().into(), 101 | config.prometheus_registry(), 102 | task_manager.spawn_essential_handle(), 103 | client.clone(), 104 | ); 105 | 106 | let (grandpa_block_import, grandpa_link) = sc_consensus_grandpa::block_import( 107 | client.clone(), 108 | &(client.clone() as Arc<_>), 109 | select_chain.clone(), 110 | telemetry.as_ref().map(|x| x.handle()), 111 | )?; 112 | 113 | let slot_duration = sc_consensus_aura::slot_duration(&*client)?; 114 | 115 | let import_queue = 116 | sc_consensus_aura::import_queue::(ImportQueueParams { 117 | block_import: grandpa_block_import.clone(), 118 | justification_import: Some(Box::new(grandpa_block_import.clone())), 119 | client: client.clone(), 120 | create_inherent_data_providers: move |_, ()| async move { 121 | let timestamp = sp_timestamp::InherentDataProvider::from_system_time(); 122 | 123 | let slot = 124 | sp_consensus_aura::inherents::InherentDataProvider::from_timestamp_and_slot_duration( 125 | *timestamp, 126 | slot_duration, 127 | ); 128 | 129 | Ok((slot, timestamp)) 130 | }, 131 | spawner: &task_manager.spawn_essential_handle(), 132 | registry: config.prometheus_registry(), 133 | check_for_equivocation: Default::default(), 134 | telemetry: telemetry.as_ref().map(|x| x.handle()), 135 | compatibility_mode: Default::default(), 136 | })?; 137 | 138 | Ok(sc_service::PartialComponents { 139 | client, 140 | backend, 141 | task_manager, 142 | import_queue, 143 | keystore_container, 144 | select_chain, 145 | transaction_pool, 146 | other: (grandpa_block_import, grandpa_link, telemetry), 147 | }) 148 | } 149 | 150 | fn remote_keystore(_url: &String) -> Result, &'static str> { 151 | // FIXME: here would the concrete keystore be built, 152 | // must return a concrete type (NOT `LocalKeystore`) that 153 | // implements `CryptoStore` and `SyncCryptoStore` 154 | Err("Remote Keystore not supported.") 155 | } 156 | 157 | /// Builds a new service for a full client. 158 | pub fn new_full(mut config: Configuration) -> Result { 159 | let sc_service::PartialComponents { 160 | client, 161 | backend, 162 | mut task_manager, 163 | import_queue, 164 | mut keystore_container, 165 | select_chain, 166 | transaction_pool, 167 | other: (block_import, grandpa_link, mut telemetry), 168 | } = new_partial(&config)?; 169 | 170 | if let Some(url) = &config.keystore_remote { 171 | match remote_keystore(url) { 172 | Ok(k) => keystore_container.set_remote_keystore(k), 173 | Err(e) => 174 | return Err(ServiceError::Other(format!( 175 | "Error hooking up remote keystore for {}: {}", 176 | url, e 177 | ))), 178 | }; 179 | } 180 | let grandpa_protocol_name = sc_consensus_grandpa::protocol_standard_name( 181 | &client.block_hash(0).ok().flatten().expect("Genesis block exists; qed"), 182 | &config.chain_spec, 183 | ); 184 | 185 | config 186 | .network 187 | .extra_sets 188 | .push(sc_consensus_grandpa::grandpa_peers_set_config(grandpa_protocol_name.clone())); 189 | let warp_sync = Arc::new(sc_consensus_grandpa::warp_proof::NetworkProvider::new( 190 | backend.clone(), 191 | grandpa_link.shared_authority_set().clone(), 192 | Vec::default(), 193 | )); 194 | 195 | let (network, system_rpc_tx, tx_handler_controller, network_starter, sync_service) = 196 | sc_service::build_network(sc_service::BuildNetworkParams { 197 | config: &config, 198 | client: client.clone(), 199 | transaction_pool: transaction_pool.clone(), 200 | spawn_handle: task_manager.spawn_handle(), 201 | import_queue, 202 | block_announce_validator_builder: None, 203 | warp_sync_params: Some(WarpSyncParams::WithProvider(warp_sync)), 204 | })?; 205 | 206 | if config.offchain_worker.enabled { 207 | sc_service::build_offchain_workers( 208 | &config, 209 | task_manager.spawn_handle(), 210 | client.clone(), 211 | network.clone(), 212 | ); 213 | } 214 | 215 | let role = config.role.clone(); 216 | let force_authoring = config.force_authoring; 217 | let backoff_authoring_blocks: Option<()> = None; 218 | let name = config.network.node_name.clone(); 219 | let enable_grandpa = !config.disable_grandpa; 220 | let prometheus_registry = config.prometheus_registry().cloned(); 221 | 222 | let rpc_extensions_builder = { 223 | let client = client.clone(); 224 | let pool = transaction_pool.clone(); 225 | 226 | Box::new(move |deny_unsafe, _| { 227 | let deps = 228 | crate::rpc::FullDeps { client: client.clone(), pool: pool.clone(), deny_unsafe }; 229 | crate::rpc::create_full(deps).map_err(Into::into) 230 | }) 231 | }; 232 | 233 | let _rpc_handlers = sc_service::spawn_tasks(sc_service::SpawnTasksParams { 234 | network: network.clone(), 235 | client: client.clone(), 236 | keystore: keystore_container.sync_keystore(), 237 | task_manager: &mut task_manager, 238 | transaction_pool: transaction_pool.clone(), 239 | rpc_builder: rpc_extensions_builder, 240 | backend, 241 | system_rpc_tx, 242 | tx_handler_controller, 243 | sync_service: sync_service.clone(), 244 | config, 245 | telemetry: telemetry.as_mut(), 246 | })?; 247 | 248 | if role.is_authority() { 249 | let proposer_factory = sc_basic_authorship::ProposerFactory::new( 250 | task_manager.spawn_handle(), 251 | client.clone(), 252 | transaction_pool, 253 | prometheus_registry.as_ref(), 254 | telemetry.as_ref().map(|x| x.handle()), 255 | ); 256 | 257 | let slot_duration = sc_consensus_aura::slot_duration(&*client)?; 258 | 259 | let aura = sc_consensus_aura::start_aura::( 260 | StartAuraParams { 261 | slot_duration, 262 | client, 263 | select_chain, 264 | block_import, 265 | proposer_factory, 266 | create_inherent_data_providers: move |_, ()| async move { 267 | let timestamp = sp_timestamp::InherentDataProvider::from_system_time(); 268 | 269 | let slot = 270 | sp_consensus_aura::inherents::InherentDataProvider::from_timestamp_and_slot_duration( 271 | *timestamp, 272 | slot_duration, 273 | ); 274 | 275 | Ok((slot, timestamp)) 276 | }, 277 | force_authoring, 278 | backoff_authoring_blocks, 279 | keystore: keystore_container.sync_keystore(), 280 | sync_oracle: sync_service.clone(), 281 | justification_sync_link: sync_service.clone(), 282 | block_proposal_slot_portion: SlotProportion::new(2f32 / 3f32), 283 | max_block_proposal_slot_portion: None, 284 | telemetry: telemetry.as_ref().map(|x| x.handle()), 285 | compatibility_mode: Default::default(), 286 | }, 287 | )?; 288 | 289 | // the AURA authoring task is considered essential, i.e. if it 290 | // fails we take down the service with it. 291 | task_manager 292 | .spawn_essential_handle() 293 | .spawn_blocking("aura", Some("block-authoring"), aura); 294 | } 295 | 296 | if enable_grandpa { 297 | // if the node isn't actively participating in consensus then it doesn't 298 | // need a keystore, regardless of which protocol we use below. 299 | let keystore = 300 | if role.is_authority() { Some(keystore_container.sync_keystore()) } else { None }; 301 | 302 | let grandpa_config = sc_consensus_grandpa::Config { 303 | // FIXME #1578 make this available through chainspec 304 | gossip_duration: Duration::from_millis(333), 305 | justification_period: 512, 306 | name: Some(name), 307 | observer_enabled: false, 308 | keystore, 309 | local_role: role, 310 | telemetry: telemetry.as_ref().map(|x| x.handle()), 311 | protocol_name: grandpa_protocol_name, 312 | }; 313 | 314 | // start the full GRANDPA voter 315 | // NOTE: non-authorities could run the GRANDPA observer protocol, but at 316 | // this point the full voter should provide better guarantees of block 317 | // and vote data availability than the observer. The observer has not 318 | // been tested extensively yet and having most nodes in a network run it 319 | // could lead to finality stalls. 320 | let grandpa_config = sc_consensus_grandpa::GrandpaParams { 321 | config: grandpa_config, 322 | link: grandpa_link, 323 | network, 324 | sync: Arc::new(sync_service), 325 | voting_rule: sc_consensus_grandpa::VotingRulesBuilder::default().build(), 326 | prometheus_registry, 327 | shared_voter_state: SharedVoterState::empty(), 328 | telemetry: telemetry.as_ref().map(|x| x.handle()), 329 | }; 330 | 331 | // the GRANDPA voter task is considered infallible, i.e. 332 | // if it fails we take down the service with it. 333 | task_manager.spawn_essential_handle().spawn_blocking( 334 | "grandpa-voter", 335 | None, 336 | sc_consensus_grandpa::run_grandpa_voter(grandpa_config)?, 337 | ); 338 | } 339 | 340 | network_starter.start_network(); 341 | Ok(task_manager) 342 | } 343 | -------------------------------------------------------------------------------- /runtime/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![cfg_attr(not(feature = "std"), no_std)] 2 | // `construct_runtime!` does a lot of recursion and requires us to increase the limit to 256. 3 | #![recursion_limit = "256"] 4 | 5 | // Make the WASM binary available. 6 | #[cfg(feature = "std")] 7 | include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); 8 | 9 | use pallet_grandpa::AuthorityId as GrandpaId; 10 | use sp_api::impl_runtime_apis; 11 | use sp_consensus_aura::sr25519::AuthorityId as AuraId; 12 | use sp_core::{crypto::KeyTypeId, OpaqueMetadata}; 13 | use sp_runtime::{ 14 | create_runtime_str, generic, impl_opaque_keys, 15 | traits::{ 16 | AccountIdLookup, BlakeTwo256, Block as BlockT, IdentifyAccount, NumberFor, One, Verify, 17 | }, 18 | transaction_validity::{TransactionSource, TransactionValidity}, 19 | ApplyExtrinsicResult, MultiSignature, 20 | }; 21 | use sp_std::prelude::*; 22 | #[cfg(feature = "std")] 23 | use sp_version::NativeVersion; 24 | use sp_version::RuntimeVersion; 25 | 26 | // A few exports that help ease life for downstream crates. 27 | pub use frame_support::{ 28 | construct_runtime, parameter_types, 29 | traits::{ 30 | ConstU128, ConstU32, ConstU64, ConstU8, KeyOwnerProofSystem, Randomness, StorageInfo, 31 | }, 32 | weights::{ 33 | constants::{ 34 | BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight, WEIGHT_REF_TIME_PER_SECOND, 35 | }, 36 | IdentityFee, Weight, 37 | }, 38 | StorageValue, 39 | }; 40 | pub use frame_system::Call as SystemCall; 41 | pub use pallet_balances::Call as BalancesCall; 42 | pub use pallet_timestamp::Call as TimestampCall; 43 | use pallet_transaction_payment::{ConstFeeMultiplier, CurrencyAdapter, Multiplier}; 44 | #[cfg(any(feature = "std", test))] 45 | pub use sp_runtime::BuildStorage; 46 | pub use sp_runtime::{Perbill, Permill}; 47 | 48 | /// Import the template pallet. 49 | pub use pallet_template; 50 | 51 | /// An index to a block. 52 | pub type BlockNumber = u32; 53 | 54 | /// Alias to 512-bit hash when used in the context of a transaction signature on the chain. 55 | pub type Signature = MultiSignature; 56 | 57 | /// Some way of identifying an account on the chain. We intentionally make it equivalent 58 | /// to the public key of our transaction signing scheme. 59 | pub type AccountId = <::Signer as IdentifyAccount>::AccountId; 60 | 61 | /// Balance of an account. 62 | pub type Balance = u128; 63 | 64 | /// Index of a transaction in the chain. 65 | pub type Index = u32; 66 | 67 | /// A hash of some data used by the chain. 68 | pub type Hash = sp_core::H256; 69 | 70 | /// Opaque types. These are used by the CLI to instantiate machinery that don't need to know 71 | /// the specifics of the runtime. They can then be made to be agnostic over specific formats 72 | /// of data like extrinsics, allowing for them to continue syncing the network through upgrades 73 | /// to even the core data structures. 74 | pub mod opaque { 75 | use super::*; 76 | 77 | pub use sp_runtime::OpaqueExtrinsic as UncheckedExtrinsic; 78 | 79 | /// Opaque block header type. 80 | pub type Header = generic::Header; 81 | /// Opaque block type. 82 | pub type Block = generic::Block; 83 | /// Opaque block identifier type. 84 | pub type BlockId = generic::BlockId; 85 | 86 | impl_opaque_keys! { 87 | pub struct SessionKeys { 88 | pub aura: Aura, 89 | pub grandpa: Grandpa, 90 | } 91 | } 92 | } 93 | 94 | // To learn more about runtime versioning, see: 95 | // https://docs.substrate.io/main-docs/build/upgrade#runtime-versioning 96 | #[sp_version::runtime_version] 97 | pub const VERSION: RuntimeVersion = RuntimeVersion { 98 | spec_name: create_runtime_str!("node-template"), 99 | impl_name: create_runtime_str!("node-template"), 100 | authoring_version: 1, 101 | // The version of the runtime specification. A full node will not attempt to use its native 102 | // runtime in substitute for the on-chain Wasm runtime unless all of `spec_name`, 103 | // `spec_version`, and `authoring_version` are the same between Wasm and native. 104 | // This value is set to 100 to notify Polkadot-JS App (https://polkadot.js.org/apps) to use 105 | // the compatible custom types. 106 | spec_version: 100, 107 | impl_version: 1, 108 | apis: RUNTIME_API_VERSIONS, 109 | transaction_version: 1, 110 | state_version: 1, 111 | }; 112 | 113 | /// This determines the average expected block time that we are targeting. 114 | /// Blocks will be produced at a minimum duration defined by `SLOT_DURATION`. 115 | /// `SLOT_DURATION` is picked up by `pallet_timestamp` which is in turn picked 116 | /// up by `pallet_aura` to implement `fn slot_duration()`. 117 | /// 118 | /// Change this to adjust the block time. 119 | pub const MILLISECS_PER_BLOCK: u64 = 6000; 120 | 121 | // NOTE: Currently it is not possible to change the slot duration after the chain has started. 122 | // Attempting to do so will brick block production. 123 | pub const SLOT_DURATION: u64 = MILLISECS_PER_BLOCK; 124 | 125 | // Time is measured by number of blocks. 126 | pub const MINUTES: BlockNumber = 60_000 / (MILLISECS_PER_BLOCK as BlockNumber); 127 | pub const HOURS: BlockNumber = MINUTES * 60; 128 | pub const DAYS: BlockNumber = HOURS * 24; 129 | 130 | /// The version information used to identify this runtime when compiled natively. 131 | #[cfg(feature = "std")] 132 | pub fn native_version() -> NativeVersion { 133 | NativeVersion { runtime_version: VERSION, can_author_with: Default::default() } 134 | } 135 | 136 | const NORMAL_DISPATCH_RATIO: Perbill = Perbill::from_percent(75); 137 | 138 | parameter_types! { 139 | pub const BlockHashCount: BlockNumber = 2400; 140 | pub const Version: RuntimeVersion = VERSION; 141 | /// We allow for 2 seconds of compute with a 6 second average block time. 142 | pub BlockWeights: frame_system::limits::BlockWeights = 143 | frame_system::limits::BlockWeights::with_sensible_defaults( 144 | Weight::from_parts(2u64 * WEIGHT_REF_TIME_PER_SECOND, u64::MAX), 145 | NORMAL_DISPATCH_RATIO, 146 | ); 147 | pub BlockLength: frame_system::limits::BlockLength = frame_system::limits::BlockLength 148 | ::max_with_normal_ratio(5 * 1024 * 1024, NORMAL_DISPATCH_RATIO); 149 | pub const SS58Prefix: u8 = 42; 150 | } 151 | 152 | // Configure FRAME pallets to include in runtime. 153 | 154 | impl frame_system::Config for Runtime { 155 | /// The basic call filter to use in dispatchable. 156 | type BaseCallFilter = frame_support::traits::Everything; 157 | /// Block & extrinsics weights: base values and limits. 158 | type BlockWeights = BlockWeights; 159 | /// The maximum length of a block (in bytes). 160 | type BlockLength = BlockLength; 161 | /// The identifier used to distinguish between accounts. 162 | type AccountId = AccountId; 163 | /// The aggregated dispatch type that is available for extrinsics. 164 | type RuntimeCall = RuntimeCall; 165 | /// The lookup mechanism to get account ID from whatever is passed in dispatchers. 166 | type Lookup = AccountIdLookup; 167 | /// The index type for storing how many extrinsics an account has signed. 168 | type Index = Index; 169 | /// The index type for blocks. 170 | type BlockNumber = BlockNumber; 171 | /// The type for hashing blocks and tries. 172 | type Hash = Hash; 173 | /// The hashing algorithm used. 174 | type Hashing = BlakeTwo256; 175 | /// The header type. 176 | type Header = generic::Header; 177 | /// The ubiquitous event type. 178 | type RuntimeEvent = RuntimeEvent; 179 | /// The ubiquitous origin type. 180 | type RuntimeOrigin = RuntimeOrigin; 181 | /// Maximum number of block number to block hash mappings to keep (oldest pruned first). 182 | type BlockHashCount = BlockHashCount; 183 | /// The weight of database operations that the runtime can invoke. 184 | type DbWeight = RocksDbWeight; 185 | /// Version of the runtime. 186 | type Version = Version; 187 | /// Converts a module to the index of the module in `construct_runtime!`. 188 | /// 189 | /// This type is being generated by `construct_runtime!`. 190 | type PalletInfo = PalletInfo; 191 | /// What to do if a new account is created. 192 | type OnNewAccount = (); 193 | /// What to do if an account is fully reaped from the system. 194 | type OnKilledAccount = (); 195 | /// The data to be stored in an account. 196 | type AccountData = pallet_balances::AccountData; 197 | /// Weight information for the extrinsics of this pallet. 198 | type SystemWeightInfo = (); 199 | /// This is used as an identifier of the chain. 42 is the generic substrate prefix. 200 | type SS58Prefix = SS58Prefix; 201 | /// The set code logic, just the default since we're not a parachain. 202 | type OnSetCode = (); 203 | type MaxConsumers = frame_support::traits::ConstU32<16>; 204 | } 205 | 206 | impl pallet_aura::Config for Runtime { 207 | type AuthorityId = AuraId; 208 | type DisabledValidators = (); 209 | type MaxAuthorities = ConstU32<32>; 210 | } 211 | 212 | impl pallet_grandpa::Config for Runtime { 213 | type RuntimeEvent = RuntimeEvent; 214 | 215 | type WeightInfo = (); 216 | type MaxAuthorities = ConstU32<32>; 217 | type MaxSetIdSessionEntries = ConstU64<0>; 218 | 219 | type KeyOwnerProof = sp_core::Void; 220 | type EquivocationReportSystem = (); 221 | } 222 | 223 | impl pallet_timestamp::Config for Runtime { 224 | /// A timestamp: milliseconds since the unix epoch. 225 | type Moment = u64; 226 | type OnTimestampSet = Aura; 227 | type MinimumPeriod = ConstU64<{ SLOT_DURATION / 2 }>; 228 | type WeightInfo = (); 229 | } 230 | 231 | /// Existential deposit. 232 | pub const EXISTENTIAL_DEPOSIT: u128 = 500; 233 | 234 | impl pallet_balances::Config for Runtime { 235 | type MaxLocks = ConstU32<50>; 236 | type MaxReserves = (); 237 | type ReserveIdentifier = [u8; 8]; 238 | /// The type for recording an account's balance. 239 | type Balance = Balance; 240 | /// The ubiquitous event type. 241 | type RuntimeEvent = RuntimeEvent; 242 | type DustRemoval = (); 243 | type ExistentialDeposit = ConstU128; 244 | type AccountStore = System; 245 | type WeightInfo = pallet_balances::weights::SubstrateWeight; 246 | } 247 | 248 | parameter_types! { 249 | pub FeeMultiplier: Multiplier = Multiplier::one(); 250 | } 251 | 252 | impl pallet_transaction_payment::Config for Runtime { 253 | type RuntimeEvent = RuntimeEvent; 254 | type OnChargeTransaction = CurrencyAdapter; 255 | type OperationalFeeMultiplier = ConstU8<5>; 256 | type WeightToFee = IdentityFee; 257 | type LengthToFee = IdentityFee; 258 | type FeeMultiplierUpdate = ConstFeeMultiplier; 259 | } 260 | 261 | impl pallet_sudo::Config for Runtime { 262 | type RuntimeEvent = RuntimeEvent; 263 | type RuntimeCall = RuntimeCall; 264 | } 265 | 266 | /// Configure the pallet-template in pallets/template. 267 | impl pallet_template::Config for Runtime { 268 | type RuntimeEvent = RuntimeEvent; 269 | } 270 | 271 | // Create the runtime by composing the FRAME pallets that were previously configured. 272 | construct_runtime!( 273 | pub struct Runtime 274 | where 275 | Block = Block, 276 | NodeBlock = opaque::Block, 277 | UncheckedExtrinsic = UncheckedExtrinsic, 278 | { 279 | System: frame_system, 280 | Timestamp: pallet_timestamp, 281 | Aura: pallet_aura, 282 | Grandpa: pallet_grandpa, 283 | Balances: pallet_balances, 284 | TransactionPayment: pallet_transaction_payment, 285 | Sudo: pallet_sudo, 286 | // Include the custom logic from the pallet-template in the runtime. 287 | TemplateModule: pallet_template, 288 | } 289 | ); 290 | 291 | /// The address format for describing accounts. 292 | pub type Address = sp_runtime::MultiAddress; 293 | /// Block header type as expected by this runtime. 294 | pub type Header = generic::Header; 295 | /// Block type as expected by this runtime. 296 | pub type Block = generic::Block; 297 | /// The SignedExtension to the basic transaction logic. 298 | pub type SignedExtra = ( 299 | frame_system::CheckNonZeroSender, 300 | frame_system::CheckSpecVersion, 301 | frame_system::CheckTxVersion, 302 | frame_system::CheckGenesis, 303 | frame_system::CheckEra, 304 | frame_system::CheckNonce, 305 | frame_system::CheckWeight, 306 | pallet_transaction_payment::ChargeTransactionPayment, 307 | ); 308 | 309 | /// Unchecked extrinsic type as expected by this runtime. 310 | pub type UncheckedExtrinsic = 311 | generic::UncheckedExtrinsic; 312 | /// The payload being signed in transactions. 313 | pub type SignedPayload = generic::SignedPayload; 314 | /// Executive: handles dispatch to the various modules. 315 | pub type Executive = frame_executive::Executive< 316 | Runtime, 317 | Block, 318 | frame_system::ChainContext, 319 | Runtime, 320 | AllPalletsWithSystem, 321 | >; 322 | 323 | #[cfg(feature = "runtime-benchmarks")] 324 | #[macro_use] 325 | extern crate frame_benchmarking; 326 | 327 | #[cfg(feature = "runtime-benchmarks")] 328 | mod benches { 329 | define_benchmarks!( 330 | [frame_benchmarking, BaselineBench::] 331 | [frame_system, SystemBench::] 332 | [pallet_balances, Balances] 333 | [pallet_timestamp, Timestamp] 334 | [pallet_template, TemplateModule] 335 | ); 336 | } 337 | 338 | impl_runtime_apis! { 339 | impl sp_api::Core for Runtime { 340 | fn version() -> RuntimeVersion { 341 | VERSION 342 | } 343 | 344 | fn execute_block(block: Block) { 345 | Executive::execute_block(block); 346 | } 347 | 348 | fn initialize_block(header: &::Header) { 349 | Executive::initialize_block(header) 350 | } 351 | } 352 | 353 | impl sp_api::Metadata for Runtime { 354 | fn metadata() -> OpaqueMetadata { 355 | OpaqueMetadata::new(Runtime::metadata().into()) 356 | } 357 | } 358 | 359 | impl sp_block_builder::BlockBuilder for Runtime { 360 | fn apply_extrinsic(extrinsic: ::Extrinsic) -> ApplyExtrinsicResult { 361 | Executive::apply_extrinsic(extrinsic) 362 | } 363 | 364 | fn finalize_block() -> ::Header { 365 | Executive::finalize_block() 366 | } 367 | 368 | fn inherent_extrinsics(data: sp_inherents::InherentData) -> Vec<::Extrinsic> { 369 | data.create_extrinsics() 370 | } 371 | 372 | fn check_inherents( 373 | block: Block, 374 | data: sp_inherents::InherentData, 375 | ) -> sp_inherents::CheckInherentsResult { 376 | data.check_extrinsics(&block) 377 | } 378 | } 379 | 380 | impl sp_transaction_pool::runtime_api::TaggedTransactionQueue for Runtime { 381 | fn validate_transaction( 382 | source: TransactionSource, 383 | tx: ::Extrinsic, 384 | block_hash: ::Hash, 385 | ) -> TransactionValidity { 386 | Executive::validate_transaction(source, tx, block_hash) 387 | } 388 | } 389 | 390 | impl sp_offchain::OffchainWorkerApi for Runtime { 391 | fn offchain_worker(header: &::Header) { 392 | Executive::offchain_worker(header) 393 | } 394 | } 395 | 396 | impl sp_consensus_aura::AuraApi for Runtime { 397 | fn slot_duration() -> sp_consensus_aura::SlotDuration { 398 | sp_consensus_aura::SlotDuration::from_millis(Aura::slot_duration()) 399 | } 400 | 401 | fn authorities() -> Vec { 402 | Aura::authorities().into_inner() 403 | } 404 | } 405 | 406 | impl sp_session::SessionKeys for Runtime { 407 | fn generate_session_keys(seed: Option>) -> Vec { 408 | opaque::SessionKeys::generate(seed) 409 | } 410 | 411 | fn decode_session_keys( 412 | encoded: Vec, 413 | ) -> Option, KeyTypeId)>> { 414 | opaque::SessionKeys::decode_into_raw_public_keys(&encoded) 415 | } 416 | } 417 | 418 | impl sp_consensus_grandpa::GrandpaApi for Runtime { 419 | fn grandpa_authorities() -> sp_consensus_grandpa::AuthorityList { 420 | Grandpa::grandpa_authorities() 421 | } 422 | 423 | fn current_set_id() -> sp_consensus_grandpa::SetId { 424 | Grandpa::current_set_id() 425 | } 426 | 427 | fn submit_report_equivocation_unsigned_extrinsic( 428 | _equivocation_proof: sp_consensus_grandpa::EquivocationProof< 429 | ::Hash, 430 | NumberFor, 431 | >, 432 | _key_owner_proof: sp_consensus_grandpa::OpaqueKeyOwnershipProof, 433 | ) -> Option<()> { 434 | None 435 | } 436 | 437 | fn generate_key_ownership_proof( 438 | _set_id: sp_consensus_grandpa::SetId, 439 | _authority_id: GrandpaId, 440 | ) -> Option { 441 | // NOTE: this is the only implementation possible since we've 442 | // defined our key owner proof type as a bottom type (i.e. a type 443 | // with no values). 444 | None 445 | } 446 | } 447 | 448 | impl frame_system_rpc_runtime_api::AccountNonceApi for Runtime { 449 | fn account_nonce(account: AccountId) -> Index { 450 | System::account_nonce(account) 451 | } 452 | } 453 | 454 | impl pallet_transaction_payment_rpc_runtime_api::TransactionPaymentApi for Runtime { 455 | fn query_info( 456 | uxt: ::Extrinsic, 457 | len: u32, 458 | ) -> pallet_transaction_payment_rpc_runtime_api::RuntimeDispatchInfo { 459 | TransactionPayment::query_info(uxt, len) 460 | } 461 | fn query_fee_details( 462 | uxt: ::Extrinsic, 463 | len: u32, 464 | ) -> pallet_transaction_payment::FeeDetails { 465 | TransactionPayment::query_fee_details(uxt, len) 466 | } 467 | fn query_weight_to_fee(weight: Weight) -> Balance { 468 | TransactionPayment::weight_to_fee(weight) 469 | } 470 | fn query_length_to_fee(length: u32) -> Balance { 471 | TransactionPayment::length_to_fee(length) 472 | } 473 | } 474 | 475 | impl pallet_transaction_payment_rpc_runtime_api::TransactionPaymentCallApi 476 | for Runtime 477 | { 478 | fn query_call_info( 479 | call: RuntimeCall, 480 | len: u32, 481 | ) -> pallet_transaction_payment::RuntimeDispatchInfo { 482 | TransactionPayment::query_call_info(call, len) 483 | } 484 | fn query_call_fee_details( 485 | call: RuntimeCall, 486 | len: u32, 487 | ) -> pallet_transaction_payment::FeeDetails { 488 | TransactionPayment::query_call_fee_details(call, len) 489 | } 490 | fn query_weight_to_fee(weight: Weight) -> Balance { 491 | TransactionPayment::weight_to_fee(weight) 492 | } 493 | fn query_length_to_fee(length: u32) -> Balance { 494 | TransactionPayment::length_to_fee(length) 495 | } 496 | } 497 | 498 | #[cfg(feature = "runtime-benchmarks")] 499 | impl frame_benchmarking::Benchmark for Runtime { 500 | fn benchmark_metadata(extra: bool) -> ( 501 | Vec, 502 | Vec, 503 | ) { 504 | use frame_benchmarking::{baseline, Benchmarking, BenchmarkList}; 505 | use frame_support::traits::StorageInfoTrait; 506 | use frame_system_benchmarking::Pallet as SystemBench; 507 | use baseline::Pallet as BaselineBench; 508 | 509 | let mut list = Vec::::new(); 510 | list_benchmarks!(list, extra); 511 | 512 | let storage_info = AllPalletsWithSystem::storage_info(); 513 | 514 | (list, storage_info) 515 | } 516 | 517 | fn dispatch_benchmark( 518 | config: frame_benchmarking::BenchmarkConfig 519 | ) -> Result, sp_runtime::RuntimeString> { 520 | use frame_benchmarking::{baseline, Benchmarking, BenchmarkBatch, TrackedStorageKey}; 521 | 522 | use frame_system_benchmarking::Pallet as SystemBench; 523 | use baseline::Pallet as BaselineBench; 524 | 525 | impl frame_system_benchmarking::Config for Runtime {} 526 | impl baseline::Config for Runtime {} 527 | 528 | use frame_support::traits::WhitelistedStorageKeys; 529 | let whitelist: Vec = AllPalletsWithSystem::whitelisted_storage_keys(); 530 | 531 | let mut batches = Vec::::new(); 532 | let params = (&config, &whitelist); 533 | add_benchmarks!(params, batches); 534 | 535 | Ok(batches) 536 | } 537 | } 538 | 539 | #[cfg(feature = "try-runtime")] 540 | impl frame_try_runtime::TryRuntime for Runtime { 541 | fn on_runtime_upgrade(checks: frame_try_runtime::UpgradeCheckSelect) -> (Weight, Weight) { 542 | // NOTE: intentional unwrap: we don't want to propagate the error backwards, and want to 543 | // have a backtrace here. If any of the pre/post migration checks fail, we shall stop 544 | // right here and right now. 545 | let weight = Executive::try_runtime_upgrade(checks).unwrap(); 546 | (weight, BlockWeights::get().max_block) 547 | } 548 | 549 | fn execute_block( 550 | block: Block, 551 | state_root_check: bool, 552 | signature_check: bool, 553 | select: frame_try_runtime::TryStateSelect 554 | ) -> Weight { 555 | // NOTE: intentional unwrap: we don't want to propagate the error backwards, and want to 556 | // have a backtrace here. 557 | Executive::try_execute_block(block, state_root_check, signature_check, select).expect("execute-block failed") 558 | } 559 | } 560 | } 561 | 562 | #[cfg(test)] 563 | mod tests { 564 | use super::*; 565 | use frame_support::traits::WhitelistedStorageKeys; 566 | use sp_core::hexdisplay::HexDisplay; 567 | use std::collections::HashSet; 568 | 569 | #[test] 570 | fn check_whitelist() { 571 | let whitelist: HashSet = AllPalletsWithSystem::whitelisted_storage_keys() 572 | .iter() 573 | .map(|e| HexDisplay::from(&e.key).to_string()) 574 | .collect(); 575 | 576 | // Block Number 577 | assert!( 578 | whitelist.contains("26aa394eea5630e07c48ae0c9558cef702a5c1b19ab7a04f536c519aca4983ac") 579 | ); 580 | // Total Issuance 581 | assert!( 582 | whitelist.contains("c2261276cc9d1f8598ea4b6a74b15c2f57c875e4cff74148e4628f264b974c80") 583 | ); 584 | // Execution Phase 585 | assert!( 586 | whitelist.contains("26aa394eea5630e07c48ae0c9558cef7ff553b5a9862a516939d82b3d3d8661a") 587 | ); 588 | // Event Count 589 | assert!( 590 | whitelist.contains("26aa394eea5630e07c48ae0c9558cef70a98fdbe9ce6c55837576c60c7af3850") 591 | ); 592 | // System Events 593 | assert!( 594 | whitelist.contains("26aa394eea5630e07c48ae0c9558cef780d41e5e16056765bc8461851072c9d7") 595 | ); 596 | } 597 | } 598 | --------------------------------------------------------------------------------