├── 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 │ ├── command.rs │ ├── chain_spec.rs │ └── service.rs ├── build.rs └── Cargo.toml ├── Cargo.toml ├── runtime ├── build.rs ├── Cargo.toml └── src │ └── lib.rs ├── .gitignore ├── .editorconfig ├── scripts ├── docker_run.sh └── init.sh ├── .github ├── ISSUE_TEMPLATE │ ├── ask-a-question.md │ ├── suggest-a-feature.md │ └── report-a-bug.md └── workflows │ ├── build-push-template.yml │ └── check.yml ├── docker-compose.yml ├── .devcontainer └── devcontainer.json ├── .vscode └── tasks.json ├── LICENSE ├── docs └── rust-setup.md └── README.md /pallets/template/README.md: -------------------------------------------------------------------------------- 1 | License: Unlicense -------------------------------------------------------------------------------- /node/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub mod chain_spec; 2 | pub mod service; 3 | pub mod rpc; 4 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = [ 3 | 'node', 4 | 'pallets/*', 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 | -------------------------------------------------------------------------------- /runtime/build.rs: -------------------------------------------------------------------------------- 1 | use substrate_wasm_builder::WasmBuilder; 2 | 3 | fn main() { 4 | WasmBuilder::new() 5 | .with_current_project() 6 | .export_heap_base() 7 | .import_memory() 8 | .build() 9 | } 10 | -------------------------------------------------------------------------------- /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 cli; 8 | mod command; 9 | mod rpc; 10 | 11 | fn main() -> sc_cli::Result<()> { 12 | command::run() 13 | } 14 | -------------------------------------------------------------------------------- /.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 | # The cache for docker container dependency 10 | .cargo 11 | 12 | # The cache for chain data in container 13 | .local -------------------------------------------------------------------------------- /.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/docker_run.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # This script meant to be run on Unix/Linux based systems 3 | set -e 4 | 5 | echo "*** Start Substrate node template ***" 6 | 7 | cd $(dirname ${BASH_SOURCE[0]})/.. 8 | 9 | docker-compose down --remove-orphans 10 | docker-compose run --rm --service-ports dev $@ 11 | -------------------------------------------------------------------------------- /scripts/init.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # This script 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 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/ask-a-question.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Ask a Question 3 | about: Ask a question about this template. 4 | title: "" 5 | labels: question 6 | assignees: "" 7 | --- 8 | 9 | **Question** 10 | 11 | _Please include information such as the following: is your question to clarify an existing resource 12 | or are you asking about something new? what are you trying to accomplish? where have you looked for 13 | answers?_ 14 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "3.2" 2 | 3 | services: 4 | dev: 5 | container_name: node-template 6 | image: paritytech/ci-linux:974ba3ac-20201006 7 | working_dir: /var/www/node-template 8 | ports: 9 | - "9944:9944" 10 | environment: 11 | - CARGO_HOME=/var/www/node-template/.cargo 12 | volumes: 13 | - .:/var/www/node-template 14 | - type: bind 15 | source: ./.local 16 | target: /root/.local 17 | command: bash -c "cargo build --release && ./target/release/node-template --dev --ws-external" 18 | -------------------------------------------------------------------------------- /.github/workflows/build-push-template.yml: -------------------------------------------------------------------------------- 1 | name: Build and Push template 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | 8 | jobs: 9 | build-push-template: 10 | if: ${{ github.repository == 'substrate-developer-hub/substrate-node-template' }} 11 | runs-on: ubuntu-18.04 12 | steps: 13 | - name: Trigger playground inclusion 14 | uses: peter-evans/repository-dispatch@v1 15 | with: 16 | token: ${{ secrets.REPO_ACCESS_TOKEN }} 17 | repository: paritytech/substrate-playground 18 | event-type: template-updated 19 | client-payload: '{"id": "node-template"}' 20 | -------------------------------------------------------------------------------- /pallets/template/src/benchmarking.rs: -------------------------------------------------------------------------------- 1 | //! Benchmarking setup for pallet-template 2 | 3 | use super::*; 4 | 5 | use frame_system::RawOrigin; 6 | use frame_benchmarking::{benchmarks, whitelisted_caller, impl_benchmark_test_suite}; 7 | #[allow(unused)] 8 | use crate::Module as Template; 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 | 20 | impl_benchmark_test_suite!( 21 | Template, 22 | crate::mock::new_test_ext(), 23 | crate::mock::Test, 24 | ); 25 | -------------------------------------------------------------------------------- /pallets/template/src/tests.rs: -------------------------------------------------------------------------------- 1 | use crate::{Error, mock::*}; 2 | use frame_support::{assert_ok, assert_noop}; 3 | 4 | #[test] 5 | fn it_works_for_default_value() { 6 | new_test_ext().execute_with(|| { 7 | // Dispatch a signed extrinsic. 8 | assert_ok!(TemplateModule::do_something(Origin::signed(1), 42)); 9 | // Read pallet storage and assert an expected result. 10 | assert_eq!(TemplateModule::something(), Some(42)); 11 | }); 12 | } 13 | 14 | #[test] 15 | fn correct_error_for_none_value() { 16 | new_test_ext().execute_with(|| { 17 | // Ensure the expected error is thrown when no value is present. 18 | assert_noop!( 19 | TemplateModule::cause_error(Origin::signed(1)), 20 | Error::::NoneValue 21 | ); 22 | }); 23 | } 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 | "preCreateCommand": ["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/suggest-a-feature.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Suggest a Feature 3 | about: Suggest a new feature or an improvement to an existing feature for this template. 4 | title: "" 5 | labels: enhancement 6 | assignees: "" 7 | --- 8 | 9 | **Motivation** 10 | 11 | _Describe the need or frustration that motivated you to make this suggestion. Please note that the 12 | goal of this project is to provide a general-purpose template project, so please take care when 13 | suggesting features that may be specific to a particular use case._ 14 | 15 | **Suggested Solution** 16 | 17 | _Describe your suggested solution to the need or frustration that you are experiencing._ 18 | 19 | **Alternatives** 20 | 21 | _Describe any alternative solutions or features you considered and why you believe your suggested 22 | solution is preferable._ 23 | 24 | **Additional Information** 25 | 26 | _Provide any additional information that you believe may help us evaluate your suggestion._ 27 | -------------------------------------------------------------------------------- /node/src/cli.rs: -------------------------------------------------------------------------------- 1 | use structopt::StructOpt; 2 | use sc_cli::RunCmd; 3 | 4 | #[derive(Debug, StructOpt)] 5 | pub struct Cli { 6 | #[structopt(subcommand)] 7 | pub subcommand: Option, 8 | 9 | #[structopt(flatten)] 10 | pub run: RunCmd, 11 | } 12 | 13 | #[derive(Debug, StructOpt)] 14 | pub enum Subcommand { 15 | /// Key management cli utilities 16 | Key(sc_cli::KeySubcommand), 17 | /// Build a chain specification. 18 | BuildSpec(sc_cli::BuildSpecCmd), 19 | 20 | /// Validate blocks. 21 | CheckBlock(sc_cli::CheckBlockCmd), 22 | 23 | /// Export blocks. 24 | ExportBlocks(sc_cli::ExportBlocksCmd), 25 | 26 | /// Export the state of a given block into a chain spec. 27 | ExportState(sc_cli::ExportStateCmd), 28 | 29 | /// Import blocks. 30 | ImportBlocks(sc_cli::ImportBlocksCmd), 31 | 32 | /// Remove the whole chain. 33 | PurgeChain(sc_cli::PurgeChainCmd), 34 | 35 | /// Revert the chain to a previous state. 36 | Revert(sc_cli::RevertCmd), 37 | 38 | /// The custom benchmark subcommmand benchmarking runtime pallets. 39 | #[structopt(name = "benchmark", about = "Benchmark runtime pallets.")] 40 | Benchmark(frame_benchmarking_cli::BenchmarkCmd), 41 | } 42 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /.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: [ master ] 8 | pull_request: 9 | branches: [ master ] 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-20.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 cmake pkg-config libssl-dev git build-essential clang libclang-dev curl 27 | 28 | - name: Install Rustup 29 | run: | 30 | curl https://sh.rustup.rs -sSf | 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 | -------------------------------------------------------------------------------- /pallets/template/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | authors = ['Substrate DevHub '] 3 | description = 'FRAME pallet template for defining custom runtime logic.' 4 | edition = '2018' 5 | homepage = 'https://substrate.dev' 6 | license = 'Unlicense' 7 | name = 'pallet-template' 8 | readme = 'README.md' 9 | repository = 'https://github.com/substrate-developer-hub/substrate-node-template/' 10 | version = '3.0.0' 11 | 12 | [package.metadata.docs.rs] 13 | targets = ['x86_64-unknown-linux-gnu'] 14 | 15 | [dependencies] 16 | codec = { default-features = false, features = ['derive'], package = 'parity-scale-codec', version = '2.0.0' } 17 | frame-system = { default-features = false, version = '3.0.0' } 18 | frame-support = { default-features = false, version = '3.0.0' } 19 | frame-benchmarking = { default-features = false, optional = true, version = '3.1.0' } 20 | 21 | [dev-dependencies] 22 | serde = { version = "1.0.119" } 23 | sp-core = { default-features = false, version = '3.0.0' } 24 | sp-io = { default-features = false, version = '3.0.0' } 25 | sp-runtime = { default-features = false, version = '3.0.0' } 26 | 27 | [features] 28 | default = ['std'] 29 | std = [ 30 | 'codec/std', 31 | 'frame-support/std', 32 | 'frame-system/std', 33 | 'frame-benchmarking/std', 34 | ] 35 | runtime-benchmarks = ['frame-benchmarking'] 36 | # Note: frame-support `try-runtime` feature is released after v3. 37 | # Uncomment the following line when `frame-support` version > `3.0.0`. 38 | # try-runtime = ['frame-support/try-runtime'] 39 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/report-a-bug.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Report a Bug 3 | about: Report a problem with this template. 4 | title: "" 5 | labels: bug 6 | assignees: "" 7 | --- 8 | 9 | **Description** 10 | 11 | _Tell us what happened. In particular, be specific about any changes you made to this template. 12 | Ideally, provide a link to your project's GitHub repository. Please note that we are not able to 13 | support all conceivable changes to this template project, but the more information you are able to 14 | provide the more equipped we will be to help._ 15 | 16 | **Steps to Reproduce** 17 | 18 | _Replace the example steps below with actual steps to reproduce the bug you're reporting._ 19 | 20 | 1. Go to '...' 21 | 2. Click on '....' 22 | 3. Scroll down to '....' 23 | 4. See error 24 | 25 | **Expected vs. Actual Behavior** 26 | 27 | _What did you expect to happen after you followed the steps you described in the last section? What 28 | actually happened?_ 29 | 30 | **Environment** 31 | 32 | _Describe the environment in which you encountered this bug. Use the list below as a starting point 33 | and add additional information if you think it's relevant._ 34 | 35 | - Operating system: 36 | - Template version/tag: 37 | - Rust version (run `rustup show`): 38 | 39 | **Logs, Errors or Screenshots** 40 | 41 | _Please provide the text of any logs or errors that you experienced; if 42 | applicable, provide screenshots to help illustrate the problem._ 43 | 44 | **Additional Information** 45 | 46 | _Please add any other details that you think may help us solve your problem._ 47 | -------------------------------------------------------------------------------- /node/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | authors = ['Substrate DevHub '] 3 | build = 'build.rs' 4 | description = 'A fresh FRAME-based Substrate node, ready for hacking.' 5 | edition = '2018' 6 | homepage = 'https://substrate.dev' 7 | license = 'Unlicense' 8 | name = 'node-template' 9 | repository = 'https://github.com/substrate-developer-hub/substrate-node-template/' 10 | version = '3.0.0' 11 | 12 | [[bin]] 13 | name = 'node-template' 14 | 15 | [package.metadata.docs.rs] 16 | targets = ['x86_64-unknown-linux-gnu'] 17 | 18 | [build-dependencies] 19 | substrate-build-script-utils = '3.0.0' 20 | 21 | [dependencies] 22 | jsonrpc-core = '15.1.0' 23 | structopt = '0.3.8' 24 | 25 | # Substrate dependencies 26 | frame-benchmarking = '3.1.0' 27 | frame-benchmarking-cli = '3.0.0' 28 | pallet-transaction-payment-rpc = '3.0.0' 29 | sc-basic-authorship = '0.9.0' 30 | sc-cli = { features = ['wasmtime'], version = '0.9.0' } 31 | sc-client-api = '3.0.0' 32 | sc-consensus = '0.9.0' 33 | sc-consensus-aura = '0.9.0' 34 | sc-executor = { features = ['wasmtime'], version = '0.9.0' } 35 | sc-finality-grandpa = '0.9.0' 36 | sc-keystore = '3.0.0' 37 | sc-rpc = '3.0.0' 38 | sc-rpc-api = '0.9.0' 39 | sc-service = { features = ['wasmtime'], version = '0.9.0' } 40 | sc-telemetry = '3.0.0' 41 | sc-transaction-pool = '3.0.0' 42 | sp-api = '3.0.0' 43 | sp-block-builder = '3.0.0' 44 | sp-blockchain = '3.0.0' 45 | sp-consensus = '0.9.0' 46 | sp-consensus-aura = '0.9.0' 47 | sp-core = '3.0.0' 48 | sp-finality-grandpa = '3.0.0' 49 | sp-inherents = '3.0.0' 50 | sp-runtime = '3.0.0' 51 | sp-transaction-pool = '3.0.0' 52 | substrate-frame-rpc-system = '3.0.0' 53 | 54 | # local dependencies 55 | node-template-runtime = { path = '../runtime', version = '3.0.0' } 56 | 57 | [features] 58 | default = [] 59 | runtime-benchmarks = ['node-template-runtime/runtime-benchmarks'] 60 | -------------------------------------------------------------------------------- /pallets/template/src/mock.rs: -------------------------------------------------------------------------------- 1 | use crate as pallet_template; 2 | use sp_core::H256; 3 | use frame_support::parameter_types; 4 | use sp_runtime::{ 5 | traits::{BlakeTwo256, IdentityLookup}, testing::Header, 6 | }; 7 | use frame_system as system; 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::{Module, Call, Config, Storage, Event}, 20 | TemplateModule: pallet_template::{Module, Call, Storage, Event}, 21 | } 22 | ); 23 | 24 | parameter_types! { 25 | pub const BlockHashCount: u64 = 250; 26 | pub const SS58Prefix: u8 = 42; 27 | } 28 | 29 | impl system::Config for Test { 30 | type BaseCallFilter = (); 31 | type BlockWeights = (); 32 | type BlockLength = (); 33 | type DbWeight = (); 34 | type Origin = Origin; 35 | type Call = Call; 36 | type Index = u64; 37 | type BlockNumber = u64; 38 | type Hash = H256; 39 | type Hashing = BlakeTwo256; 40 | type AccountId = u64; 41 | type Lookup = IdentityLookup; 42 | type Header = Header; 43 | type Event = Event; 44 | type BlockHashCount = BlockHashCount; 45 | type Version = (); 46 | type PalletInfo = PalletInfo; 47 | type AccountData = (); 48 | type OnNewAccount = (); 49 | type OnKilledAccount = (); 50 | type SystemWeightInfo = (); 51 | type SS58Prefix = SS58Prefix; 52 | } 53 | 54 | impl pallet_template::Config for Test { 55 | type Event = Event; 56 | } 57 | 58 | // Build genesis storage according to the mock runtime. 59 | pub fn new_test_ext() -> sp_io::TestExternalities { 60 | system::GenesisConfig::default().build_storage::().unwrap().into() 61 | } 62 | -------------------------------------------------------------------------------- /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 node_template_runtime::{opaque::Block, AccountId, Balance, Index}; 11 | use sp_api::ProvideRuntimeApi; 12 | use sp_blockchain::{Error as BlockChainError, HeaderMetadata, HeaderBackend}; 13 | use sp_block_builder::BlockBuilder; 14 | pub use sc_rpc_api::DenyUnsafe; 15 | use sp_transaction_pool::TransactionPool; 16 | 17 | 18 | /// Full client dependencies. 19 | pub struct FullDeps { 20 | /// The client instance to use. 21 | pub client: Arc, 22 | /// Transaction pool instance. 23 | pub pool: Arc

, 24 | /// Whether to deny unsafe calls 25 | pub deny_unsafe: DenyUnsafe, 26 | } 27 | 28 | /// Instantiate all full RPC extensions. 29 | pub fn create_full( 30 | deps: FullDeps, 31 | ) -> jsonrpc_core::IoHandler where 32 | C: ProvideRuntimeApi, 33 | C: HeaderBackend + HeaderMetadata + 'static, 34 | C: Send + Sync + 'static, 35 | C::Api: substrate_frame_rpc_system::AccountNonceApi, 36 | C::Api: pallet_transaction_payment_rpc::TransactionPaymentRuntimeApi, 37 | C::Api: BlockBuilder, 38 | P: TransactionPool + 'static, 39 | { 40 | use substrate_frame_rpc_system::{FullSystem, SystemApi}; 41 | use pallet_transaction_payment_rpc::{TransactionPayment, TransactionPaymentApi}; 42 | 43 | let mut io = jsonrpc_core::IoHandler::default(); 44 | let FullDeps { 45 | client, 46 | pool, 47 | deny_unsafe, 48 | } = deps; 49 | 50 | io.extend_with( 51 | SystemApi::to_delegate(FullSystem::new(client.clone(), pool, deny_unsafe)) 52 | ); 53 | 54 | io.extend_with( 55 | TransactionPaymentApi::to_delegate(TransactionPayment::new(client.clone())) 56 | ); 57 | 58 | // Extend this RPC with a custom API by using the following syntax. 59 | // `YourRpcStruct` should have a reference to a client, which is needed 60 | // to call into the runtime. 61 | // `io.extend_with(YourRpcTrait::to_delegate(YourRpcStruct::new(ReferenceToClient, ...)));` 62 | 63 | io 64 | } 65 | -------------------------------------------------------------------------------- /docs/rust-setup.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Installation 3 | --- 4 | 5 | This page will guide you through the steps needed to prepare a computer for development with the 6 | Substrate Node Template. Since Substrate is built with 7 | [the Rust programming language](https://www.rust-lang.org/), the first thing you will need to do is 8 | prepare the computer for Rust development - these steps will vary based on the computer's operating 9 | system. Once Rust is configured, you will use its toolchains to interact with Rust projects; the 10 | commands for Rust's toolchains will be the same for all supported, Unix-based operating systems. 11 | 12 | ## Unix-Based Operating Systems 13 | 14 | Substrate development is easiest on Unix-based operating systems like macOS or Linux. The examples 15 | in the Substrate [Tutorials](https://substrate.dev/tutorials) and [Recipes](https://substrate.dev/recipes/) 16 | use Unix-style terminals to demonstrate how to interact with Substrate from the command line. 17 | 18 | ### macOS 19 | 20 | Open the Terminal application and execute the following commands: 21 | 22 | ```bash 23 | # Install Homebrew if necessary https://brew.sh/ 24 | /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)" 25 | 26 | # Make sure Homebrew is up-to-date, install openssl and cmake 27 | brew update 28 | brew install openssl cmake 29 | ``` 30 | 31 | ### Ubuntu/Debian 32 | 33 | Use a terminal shell to execute the following commands: 34 | 35 | ```bash 36 | sudo apt update 37 | # May prompt for location information 38 | sudo apt install -y cmake pkg-config libssl-dev git build-essential clang libclang-dev curl 39 | ``` 40 | 41 | ### Arch Linux 42 | 43 | Run these commands from a terminal: 44 | 45 | ```bash 46 | pacman -Syu --needed --noconfirm cmake gcc openssl-1.0 pkgconf git clang 47 | export OPENSSL_LIB_DIR="/usr/lib/openssl-1.0" 48 | export OPENSSL_INCLUDE_DIR="/usr/include/openssl-1.0" 49 | ``` 50 | 51 | ### Fedora/RHEL/CentOS 52 | 53 | Use a terminal to run the following commands: 54 | 55 | ```bash 56 | # Update 57 | sudo dnf update 58 | # Install packages 59 | sudo dnf install cmake pkgconfig rocksdb rocksdb-devel llvm git libcurl libcurl-devel curl-devel clang 60 | ``` 61 | 62 | ## Rust Developer Environment 63 | 64 | This project uses [`rustup`](https://rustup.rs/) to help manage the Rust toolchain. First install 65 | and configure `rustup`: 66 | 67 | ```bash 68 | # Install 69 | curl https://sh.rustup.rs -sSf | sh 70 | # Configure 71 | source ~/.cargo/env 72 | ``` 73 | 74 | Finally, configure the Rust toolchain: 75 | 76 | ```bash 77 | rustup default stable 78 | rustup update nightly 79 | rustup update stable 80 | rustup target add wasm32-unknown-unknown --toolchain nightly 81 | ``` 82 | -------------------------------------------------------------------------------- /runtime/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | authors = ['Substrate DevHub '] 3 | edition = '2018' 4 | homepage = 'https://substrate.dev' 5 | license = 'Unlicense' 6 | name = 'node-template-runtime' 7 | repository = 'https://github.com/substrate-developer-hub/substrate-node-template/' 8 | version = '3.0.0' 9 | 10 | [package.metadata.docs.rs] 11 | targets = ['x86_64-unknown-linux-gnu'] 12 | 13 | [build-dependencies] 14 | substrate-wasm-builder = '4.0.0' 15 | 16 | [dependencies] 17 | codec = { default-features = false, features = ['derive'], package = 'parity-scale-codec', version = '2.0.0' } 18 | hex-literal = { optional = true, version = '0.3.1' } 19 | serde = { version = "1.0.119", optional = true, features = ["derive"] } 20 | 21 | # Substrate dependencies 22 | frame-benchmarking = { default-features = false, optional = true, version = '3.0.0' } 23 | frame-executive = { default-features = false, version = '3.0.0' } 24 | frame-support = { default-features = false, version = '3.0.0' } 25 | frame-system = { default-features = false, version = '3.0.0' } 26 | frame-system-benchmarking = { default-features = false, optional = true, version = '3.0.0' } 27 | frame-system-rpc-runtime-api = { default-features = false, version = '3.0.0' } 28 | pallet-aura = { default-features = false, version = '3.0.0' } 29 | pallet-balances = { default-features = false, version = '3.0.0' } 30 | pallet-grandpa = { default-features = false, version = '3.0.0' } 31 | pallet-randomness-collective-flip = { default-features = false, version = '3.0.0' } 32 | pallet-sudo = { default-features = false, version = '3.0.0' } 33 | pallet-timestamp = { default-features = false, version = '3.0.0' } 34 | pallet-transaction-payment = { default-features = false, version = '3.0.0' } 35 | pallet-transaction-payment-rpc-runtime-api = { default-features = false, version = '3.0.0' } 36 | sp-api = { default-features = false, version = '3.0.0' } 37 | sp-block-builder = { default-features = false, version = '3.0.0' } 38 | sp-consensus-aura = { default-features = false, version = '0.9.0' } 39 | sp-core = { default-features = false, version = '3.0.0' } 40 | sp-inherents = { default-features = false, version = '3.0.0' } 41 | sp-offchain = { default-features = false, version = '3.0.0' } 42 | sp-runtime = { default-features = false, version = '3.0.0' } 43 | sp-session = { default-features = false, version = '3.0.0' } 44 | sp-std = { default-features = false, version = '3.0.0' } 45 | sp-transaction-pool = { default-features = false, version = '3.0.0' } 46 | sp-version = { default-features = false, version = '3.0.0' } 47 | 48 | # local dependencies 49 | pallet-template = { default-features = false, path = '../pallets/template', version = '3.0.0' } 50 | 51 | [features] 52 | default = ['std'] 53 | runtime-benchmarks = [ 54 | 'frame-benchmarking', 55 | 'frame-support/runtime-benchmarks', 56 | 'frame-system-benchmarking', 57 | 'frame-system/runtime-benchmarks', 58 | 'hex-literal', 59 | 'pallet-balances/runtime-benchmarks', 60 | 'pallet-template/runtime-benchmarks', 61 | 'pallet-timestamp/runtime-benchmarks', 62 | 'sp-runtime/runtime-benchmarks', 63 | ] 64 | std = [ 65 | 'codec/std', 66 | 'frame-executive/std', 67 | 'frame-support/std', 68 | 'frame-system-rpc-runtime-api/std', 69 | 'frame-system/std', 70 | 'pallet-aura/std', 71 | 'pallet-balances/std', 72 | 'pallet-grandpa/std', 73 | 'pallet-randomness-collective-flip/std', 74 | 'pallet-sudo/std', 75 | 'pallet-template/std', 76 | 'pallet-timestamp/std', 77 | 'pallet-transaction-payment-rpc-runtime-api/std', 78 | 'pallet-transaction-payment/std', 79 | 'serde', 80 | 'sp-api/std', 81 | 'sp-block-builder/std', 82 | 'sp-consensus-aura/std', 83 | 'sp-core/std', 84 | 'sp-inherents/std', 85 | 'sp-offchain/std', 86 | 'sp-runtime/std', 87 | 'sp-session/std', 88 | 'sp-std/std', 89 | 'sp-transaction-pool/std', 90 | 'sp-version/std', 91 | ] 92 | -------------------------------------------------------------------------------- /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 | 7 | pub use pallet::*; 8 | 9 | #[cfg(test)] 10 | mod mock; 11 | 12 | #[cfg(test)] 13 | mod tests; 14 | 15 | #[cfg(feature = "runtime-benchmarks")] 16 | mod benchmarking; 17 | 18 | #[frame_support::pallet] 19 | pub mod pallet { 20 | use frame_support::{dispatch::DispatchResultWithPostInfo, pallet_prelude::*}; 21 | use frame_system::pallet_prelude::*; 22 | 23 | /// Configure the pallet by specifying the parameters and types on which it depends. 24 | #[pallet::config] 25 | pub trait Config: frame_system::Config { 26 | /// Because this pallet emits events, it depends on the runtime's definition of an event. 27 | type Event: From> + IsType<::Event>; 28 | } 29 | 30 | #[pallet::pallet] 31 | #[pallet::generate_store(pub(super) trait Store)] 32 | pub struct Pallet(_); 33 | 34 | // The pallet's runtime storage items. 35 | // https://substrate.dev/docs/en/knowledgebase/runtime/storage 36 | #[pallet::storage] 37 | #[pallet::getter(fn something)] 38 | // Learn more about declaring storage items: 39 | // https://substrate.dev/docs/en/knowledgebase/runtime/storage#declaring-storage-items 40 | pub type Something = StorageValue<_, u32>; 41 | 42 | // Pallets use events to inform users when important changes are made. 43 | // https://substrate.dev/docs/en/knowledgebase/runtime/events 44 | #[pallet::event] 45 | #[pallet::metadata(T::AccountId = "AccountId")] 46 | #[pallet::generate_deposit(pub(super) fn deposit_event)] 47 | pub enum Event { 48 | /// Event documentation should end with an array that provides descriptive names for event 49 | /// parameters. [something, who] 50 | SomethingStored(u32, T::AccountId), 51 | } 52 | 53 | // Errors inform users that something went wrong. 54 | #[pallet::error] 55 | pub enum Error { 56 | /// Error names should be descriptive. 57 | NoneValue, 58 | /// Errors should have helpful documentation associated with them. 59 | StorageOverflow, 60 | } 61 | 62 | #[pallet::hooks] 63 | impl Hooks> for Pallet {} 64 | 65 | // Dispatchable functions allows users to interact with the pallet and invoke state changes. 66 | // These functions materialize as "extrinsics", which are often compared to transactions. 67 | // Dispatchable functions must be annotated with a weight and must return a DispatchResult. 68 | #[pallet::call] 69 | impl Pallet { 70 | /// An example dispatchable that takes a singles value as a parameter, writes the value to 71 | /// storage and emits an event. This function must be dispatched by a signed extrinsic. 72 | #[pallet::weight(10_000 + T::DbWeight::get().writes(1))] 73 | pub fn do_something(origin: OriginFor, something: u32) -> DispatchResultWithPostInfo { 74 | // Check that the extrinsic was signed and get the signer. 75 | // This function will return an error if the extrinsic is not signed. 76 | // https://substrate.dev/docs/en/knowledgebase/runtime/origin 77 | let who = ensure_signed(origin)?; 78 | 79 | // Update storage. 80 | >::put(something); 81 | 82 | // Emit an event. 83 | Self::deposit_event(Event::SomethingStored(something, who)); 84 | // Return a successful DispatchResultWithPostInfo 85 | Ok(().into()) 86 | } 87 | 88 | /// An example dispatchable that may throw a custom error. 89 | #[pallet::weight(10_000 + T::DbWeight::get().reads_writes(1,1))] 90 | pub fn cause_error(origin: OriginFor) -> DispatchResultWithPostInfo { 91 | let _who = ensure_signed(origin)?; 92 | 93 | // Read a value from storage. 94 | match >::get() { 95 | // Return an error if the value has not been set. 96 | None => Err(Error::::NoneValue)?, 97 | Some(old) => { 98 | // Increment the value read from storage; will error in the event of overflow. 99 | let new = old.checked_add(1).ok_or(Error::::StorageOverflow)?; 100 | // Update the value in storage with the incremented result. 101 | >::put(new); 102 | Ok(().into()) 103 | }, 104 | } 105 | } 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /node/src/command.rs: -------------------------------------------------------------------------------- 1 | // This file is part of Substrate. 2 | 3 | // Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. 4 | // SPDX-License-Identifier: Apache-2.0 5 | 6 | // Licensed under the Apache License, Version 2.0 (the "License"); 7 | // you may not use this file except in compliance with the License. 8 | // You may obtain a copy of the License at 9 | // 10 | // http://www.apache.org/licenses/LICENSE-2.0 11 | // 12 | // Unless required by applicable law or agreed to in writing, software 13 | // distributed under the License is distributed on an "AS IS" BASIS, 14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | 18 | use crate::{chain_spec, service}; 19 | use crate::cli::{Cli, Subcommand}; 20 | use sc_cli::{SubstrateCli, RuntimeVersion, Role, ChainSpec}; 21 | use sc_service::PartialComponents; 22 | use node_template_runtime::Block; 23 | 24 | impl SubstrateCli for Cli { 25 | fn impl_name() -> String { 26 | "Substrate Node".into() 27 | } 28 | 29 | fn impl_version() -> String { 30 | env!("SUBSTRATE_CLI_IMPL_VERSION").into() 31 | } 32 | 33 | fn description() -> String { 34 | env!("CARGO_PKG_DESCRIPTION").into() 35 | } 36 | 37 | fn author() -> String { 38 | env!("CARGO_PKG_AUTHORS").into() 39 | } 40 | 41 | fn support_url() -> String { 42 | "support.anonymous.an".into() 43 | } 44 | 45 | fn copyright_start_year() -> i32 { 46 | 2017 47 | } 48 | 49 | fn load_spec(&self, id: &str) -> Result, String> { 50 | Ok(match id { 51 | "dev" => Box::new(chain_spec::development_config()?), 52 | "" | "local" => Box::new(chain_spec::local_testnet_config()?), 53 | path => Box::new(chain_spec::ChainSpec::from_json_file( 54 | std::path::PathBuf::from(path), 55 | )?), 56 | }) 57 | } 58 | 59 | fn native_runtime_version(_: &Box) -> &'static RuntimeVersion { 60 | &node_template_runtime::VERSION 61 | } 62 | } 63 | 64 | /// Parse and run command line arguments 65 | pub fn run() -> sc_cli::Result<()> { 66 | let cli = Cli::from_args(); 67 | 68 | match &cli.subcommand { 69 | Some(Subcommand::Key(cmd)) => cmd.run(&cli), 70 | Some(Subcommand::BuildSpec(cmd)) => { 71 | let runner = cli.create_runner(cmd)?; 72 | runner.sync_run(|config| cmd.run(config.chain_spec, config.network)) 73 | }, 74 | Some(Subcommand::CheckBlock(cmd)) => { 75 | let runner = cli.create_runner(cmd)?; 76 | runner.async_run(|config| { 77 | let PartialComponents { client, task_manager, import_queue, ..} 78 | = service::new_partial(&config)?; 79 | Ok((cmd.run(client, import_queue), task_manager)) 80 | }) 81 | }, 82 | Some(Subcommand::ExportBlocks(cmd)) => { 83 | let runner = cli.create_runner(cmd)?; 84 | runner.async_run(|config| { 85 | let PartialComponents { client, task_manager, ..} 86 | = service::new_partial(&config)?; 87 | Ok((cmd.run(client, config.database), task_manager)) 88 | }) 89 | }, 90 | Some(Subcommand::ExportState(cmd)) => { 91 | let runner = cli.create_runner(cmd)?; 92 | runner.async_run(|config| { 93 | let PartialComponents { client, task_manager, ..} 94 | = service::new_partial(&config)?; 95 | Ok((cmd.run(client, config.chain_spec), task_manager)) 96 | }) 97 | }, 98 | Some(Subcommand::ImportBlocks(cmd)) => { 99 | let runner = cli.create_runner(cmd)?; 100 | runner.async_run(|config| { 101 | let PartialComponents { client, task_manager, import_queue, ..} 102 | = service::new_partial(&config)?; 103 | Ok((cmd.run(client, import_queue), task_manager)) 104 | }) 105 | }, 106 | Some(Subcommand::PurgeChain(cmd)) => { 107 | let runner = cli.create_runner(cmd)?; 108 | runner.sync_run(|config| cmd.run(config.database)) 109 | }, 110 | Some(Subcommand::Revert(cmd)) => { 111 | let runner = cli.create_runner(cmd)?; 112 | runner.async_run(|config| { 113 | let PartialComponents { client, task_manager, backend, ..} 114 | = service::new_partial(&config)?; 115 | Ok((cmd.run(client, backend), task_manager)) 116 | }) 117 | }, 118 | Some(Subcommand::Benchmark(cmd)) => { 119 | if cfg!(feature = "runtime-benchmarks") { 120 | let runner = cli.create_runner(cmd)?; 121 | 122 | runner.sync_run(|config| cmd.run::(config)) 123 | } else { 124 | Err("Benchmarking wasn't enabled when building the node. \ 125 | You can enable it with `--features runtime-benchmarks`.".into()) 126 | } 127 | }, 128 | None => { 129 | let runner = cli.create_runner(&cli.run)?; 130 | runner.run_node_until_exit(|config| async move { 131 | match config.role { 132 | Role::Light => service::new_light(config), 133 | _ => service::new_full(config), 134 | }.map_err(sc_cli::Error::Service) 135 | }) 136 | } 137 | } 138 | } 139 | -------------------------------------------------------------------------------- /node/src/chain_spec.rs: -------------------------------------------------------------------------------- 1 | use sp_core::{Pair, Public, sr25519}; 2 | use node_template_runtime::{ 3 | AccountId, AuraConfig, BalancesConfig, GenesisConfig, GrandpaConfig, 4 | SudoConfig, SystemConfig, WASM_BINARY, Signature 5 | }; 6 | use sp_consensus_aura::sr25519::AuthorityId as AuraId; 7 | use sp_finality_grandpa::AuthorityId as GrandpaId; 8 | use sp_runtime::traits::{Verify, IdentifyAccount}; 9 | use sc_service::ChainType; 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 where 28 | AccountPublic: From<::Public> 29 | { 30 | AccountPublic::from(get_from_seed::(seed)).into_account() 31 | } 32 | 33 | /// Generate an Aura authority key. 34 | pub fn authority_keys_from_seed(s: &str) -> (AuraId, GrandpaId) { 35 | ( 36 | get_from_seed::(s), 37 | get_from_seed::(s), 38 | ) 39 | } 40 | 41 | pub fn development_config() -> Result { 42 | let wasm_binary = WASM_BINARY.ok_or_else(|| "Development wasm not available".to_string())?; 43 | 44 | Ok(ChainSpec::from_genesis( 45 | // Name 46 | "Development", 47 | // ID 48 | "dev", 49 | ChainType::Development, 50 | move || testnet_genesis( 51 | wasm_binary, 52 | // Initial PoA authorities 53 | vec![ 54 | authority_keys_from_seed("Alice"), 55 | ], 56 | // Sudo account 57 | get_account_id_from_seed::("Alice"), 58 | // Pre-funded accounts 59 | vec![ 60 | get_account_id_from_seed::("Alice"), 61 | get_account_id_from_seed::("Bob"), 62 | get_account_id_from_seed::("Alice//stash"), 63 | get_account_id_from_seed::("Bob//stash"), 64 | ], 65 | true, 66 | ), 67 | // Bootnodes 68 | vec![], 69 | // Telemetry 70 | None, 71 | // Protocol ID 72 | None, 73 | // Properties 74 | None, 75 | // Extensions 76 | None, 77 | )) 78 | } 79 | 80 | pub fn local_testnet_config() -> Result { 81 | let wasm_binary = WASM_BINARY.ok_or_else(|| "Development wasm not available".to_string())?; 82 | 83 | Ok(ChainSpec::from_genesis( 84 | // Name 85 | "Local Testnet", 86 | // ID 87 | "local_testnet", 88 | ChainType::Local, 89 | move || testnet_genesis( 90 | wasm_binary, 91 | // Initial PoA authorities 92 | vec![ 93 | authority_keys_from_seed("Alice"), 94 | authority_keys_from_seed("Bob"), 95 | ], 96 | // Sudo account 97 | get_account_id_from_seed::("Alice"), 98 | // Pre-funded accounts 99 | vec![ 100 | get_account_id_from_seed::("Alice"), 101 | get_account_id_from_seed::("Bob"), 102 | get_account_id_from_seed::("Charlie"), 103 | get_account_id_from_seed::("Dave"), 104 | get_account_id_from_seed::("Eve"), 105 | get_account_id_from_seed::("Ferdie"), 106 | get_account_id_from_seed::("Alice//stash"), 107 | get_account_id_from_seed::("Bob//stash"), 108 | get_account_id_from_seed::("Charlie//stash"), 109 | get_account_id_from_seed::("Dave//stash"), 110 | get_account_id_from_seed::("Eve//stash"), 111 | get_account_id_from_seed::("Ferdie//stash"), 112 | ], 113 | true, 114 | ), 115 | // Bootnodes 116 | vec![], 117 | // Telemetry 118 | None, 119 | // Protocol ID 120 | None, 121 | // Properties 122 | None, 123 | // Extensions 124 | None, 125 | )) 126 | } 127 | 128 | /// Configure initial storage state for FRAME modules. 129 | fn testnet_genesis( 130 | wasm_binary: &[u8], 131 | initial_authorities: Vec<(AuraId, GrandpaId)>, 132 | root_key: AccountId, 133 | endowed_accounts: Vec, 134 | _enable_println: bool, 135 | ) -> GenesisConfig { 136 | GenesisConfig { 137 | frame_system: Some(SystemConfig { 138 | // Add Wasm runtime to storage. 139 | code: wasm_binary.to_vec(), 140 | changes_trie_config: Default::default(), 141 | }), 142 | pallet_balances: Some(BalancesConfig { 143 | // Configure endowed accounts with initial balance of 1 << 60. 144 | balances: endowed_accounts.iter().cloned().map(|k|(k, 1 << 60)).collect(), 145 | }), 146 | pallet_aura: Some(AuraConfig { 147 | authorities: initial_authorities.iter().map(|x| (x.0.clone())).collect(), 148 | }), 149 | pallet_grandpa: Some(GrandpaConfig { 150 | authorities: initial_authorities.iter().map(|x| (x.1.clone(), 1)).collect(), 151 | }), 152 | pallet_sudo: Some(SudoConfig { 153 | // Assign network admin rights. 154 | key: root_key, 155 | }), 156 | } 157 | } 158 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Substrate Node Template 2 | 3 | A fresh FRAME-based [Substrate](https://www.substrate.io/) node, ready for hacking :rocket: 4 | 5 | ## Getting Started 6 | 7 | Follow these steps to get started with the Node Template :hammer_and_wrench: 8 | 9 | ### Rust Setup 10 | 11 | First, complete the [basic Rust setup instructions](./doc/rust-setup.md). 12 | 13 | ### Run 14 | 15 | Use Rust's native `cargo` command to build and launch the template node: 16 | 17 | ```sh 18 | cargo run --release -- --dev --tmp 19 | ``` 20 | 21 | ### Build 22 | 23 | The `cargo run` command will perform an initial build. Use the following command to build the node 24 | without launching it: 25 | 26 | ```sh 27 | cargo build --release 28 | ``` 29 | 30 | ### Embedded Docs 31 | 32 | Once the project has been built, the following command can be used to explore all parameters and 33 | subcommands: 34 | 35 | ```sh 36 | ./target/release/node-template -h 37 | ``` 38 | 39 | ## Run 40 | 41 | The provided `cargo run` command will launch a temporary node and its state will be discarded after 42 | you terminate the process. After the project has been built, there are other ways to launch the 43 | node. 44 | 45 | ### Single-Node Development Chain 46 | 47 | This command will start the single-node development chain with persistent state: 48 | 49 | ```bash 50 | ./target/release/node-template --dev 51 | ``` 52 | 53 | Purge the development chain's state: 54 | 55 | ```bash 56 | ./target/release/node-template purge-chain --dev 57 | ``` 58 | 59 | Start the development chain with detailed logging: 60 | 61 | ```bash 62 | RUST_LOG=debug RUST_BACKTRACE=1 ./target/release/node-template -lruntime=debug --dev 63 | ``` 64 | 65 | ### Multi-Node Local Testnet 66 | 67 | If you want to see the multi-node consensus algorithm in action, refer to 68 | [our Start a Private Network tutorial](https://substrate.dev/docs/en/tutorials/start-a-private-network/). 69 | 70 | ## Template Structure 71 | 72 | A Substrate project such as this consists of a number of components that are spread across a few 73 | directories. 74 | 75 | ### Node 76 | 77 | A blockchain node is an application that allows users to participate in a blockchain network. 78 | Substrate-based blockchain nodes expose a number of capabilities: 79 | 80 | - Networking: Substrate nodes use the [`libp2p`](https://libp2p.io/) networking stack to allow the 81 | nodes in the network to communicate with one another. 82 | - Consensus: Blockchains must have a way to come to 83 | [consensus](https://substrate.dev/docs/en/knowledgebase/advanced/consensus) on the state of the 84 | network. Substrate makes it possible to supply custom consensus engines and also ships with 85 | several consensus mechanisms that have been built on top of 86 | [Web3 Foundation research](https://research.web3.foundation/en/latest/polkadot/NPoS/index.html). 87 | - RPC Server: A remote procedure call (RPC) server is used to interact with Substrate nodes. 88 | 89 | There are several files in the `node` directory - take special note of the following: 90 | 91 | - [`chain_spec.rs`](./node/src/chain_spec.rs): A 92 | [chain specification](https://substrate.dev/docs/en/knowledgebase/integrate/chain-spec) is a 93 | source code file that defines a Substrate chain's initial (genesis) state. Chain specifications 94 | are useful for development and testing, and critical when architecting the launch of a 95 | production chain. Take note of the `development_config` and `testnet_genesis` functions, which 96 | are used to define the genesis state for the local development chain configuration. These 97 | functions identify some 98 | [well-known accounts](https://substrate.dev/docs/en/knowledgebase/integrate/subkey#well-known-keys) 99 | and use them to configure the blockchain's initial state. 100 | - [`service.rs`](./node/src/service.rs): This file defines the node implementation. Take note of 101 | the libraries that this file imports and the names of the functions it invokes. In particular, 102 | there are references to consensus-related topics, such as the 103 | [longest chain rule](https://substrate.dev/docs/en/knowledgebase/advanced/consensus#longest-chain-rule), 104 | the [Aura](https://substrate.dev/docs/en/knowledgebase/advanced/consensus#aura) block authoring 105 | mechanism and the 106 | [GRANDPA](https://substrate.dev/docs/en/knowledgebase/advanced/consensus#grandpa) finality 107 | gadget. 108 | 109 | After the node has been [built](#build), refer to the embedded documentation to learn more about the 110 | capabilities and configuration parameters that it exposes: 111 | 112 | ```shell 113 | ./target/release/node-template --help 114 | ``` 115 | 116 | ### Runtime 117 | 118 | In Substrate, the terms 119 | "[runtime](https://substrate.dev/docs/en/knowledgebase/getting-started/glossary#runtime)" and 120 | "[state transition function](https://substrate.dev/docs/en/knowledgebase/getting-started/glossary#stf-state-transition-function)" 121 | are analogous - they refer to the core logic of the blockchain that is responsible for validating 122 | blocks and executing the state changes they define. The Substrate project in this repository uses 123 | the [FRAME](https://substrate.dev/docs/en/knowledgebase/runtime/frame) framework to construct a 124 | blockchain runtime. FRAME allows runtime developers to declare domain-specific logic in modules 125 | called "pallets". At the heart of FRAME is a helpful 126 | [macro language](https://substrate.dev/docs/en/knowledgebase/runtime/macros) that makes it easy to 127 | create pallets and flexibly compose them to create blockchains that can address 128 | [a variety of needs](https://www.substrate.io/substrate-users/). 129 | 130 | Review the [FRAME runtime implementation](./runtime/src/lib.rs) included in this template and note 131 | the following: 132 | 133 | - This file configures several pallets to include in the runtime. Each pallet configuration is 134 | defined by a code block that begins with `impl $PALLET_NAME::Config for Runtime`. 135 | - The pallets are composed into a single runtime by way of the 136 | [`construct_runtime!`](https://crates.parity.io/frame_support/macro.construct_runtime.html) 137 | macro, which is part of the core 138 | [FRAME Support](https://substrate.dev/docs/en/knowledgebase/runtime/frame#support-library) 139 | library. 140 | 141 | ### Pallets 142 | 143 | The runtime in this project is constructed using many FRAME pallets that ship with the 144 | [core Substrate repository](https://github.com/paritytech/substrate/tree/master/frame) and a 145 | template pallet that is [defined in the `pallets`](./pallets/template/src/lib.rs) directory. 146 | 147 | A FRAME pallet is compromised of a number of blockchain primitives: 148 | 149 | - Storage: FRAME defines a rich set of powerful 150 | [storage abstractions](https://substrate.dev/docs/en/knowledgebase/runtime/storage) that makes 151 | it easy to use Substrate's efficient key-value database to manage the evolving state of a 152 | blockchain. 153 | - Dispatchables: FRAME pallets define special types of functions that can be invoked (dispatched) 154 | from outside of the runtime in order to update its state. 155 | - Events: Substrate uses [events](https://substrate.dev/docs/en/knowledgebase/runtime/events) to 156 | notify users of important changes in the runtime. 157 | - Errors: When a dispatchable fails, it returns an error. 158 | - Config: The `Config` configuration interface is used to define the types and parameters upon 159 | which a FRAME pallet depends. 160 | 161 | ### Run in Docker 162 | 163 | First, install [Docker](https://docs.docker.com/get-docker/) and 164 | [Docker Compose](https://docs.docker.com/compose/install/). 165 | 166 | Then run the following command to start a single node development chain. 167 | 168 | ```bash 169 | ./scripts/docker_run.sh 170 | ``` 171 | 172 | This command will firstly compile your code, and then start a local development network. You can 173 | also replace the default command (`cargo build --release && ./target/release/node-template --dev --ws-external`) 174 | by appending your own. A few useful ones are as follow. 175 | 176 | ```bash 177 | # Run Substrate node without re-compiling 178 | ./scripts/docker_run.sh ./target/release/node-template --dev --ws-external 179 | 180 | # Purge the local dev chain 181 | ./scripts/docker_run.sh ./target/release/node-template purge-chain --dev 182 | 183 | # Check whether the code is compilable 184 | ./scripts/docker_run.sh cargo check 185 | ``` 186 | -------------------------------------------------------------------------------- /node/src/service.rs: -------------------------------------------------------------------------------- 1 | //! Service and ServiceFactory implementation. Specialized wrapper over substrate service. 2 | 3 | use std::sync::Arc; 4 | use std::time::Duration; 5 | use sc_client_api::{ExecutorProvider, RemoteBackend}; 6 | use node_template_runtime::{self, opaque::Block, RuntimeApi}; 7 | use sc_service::{error::Error as ServiceError, Configuration, TaskManager}; 8 | use sp_inherents::InherentDataProviders; 9 | use sc_executor::native_executor_instance; 10 | pub use sc_executor::NativeExecutor; 11 | use sp_consensus_aura::sr25519::AuthorityPair as AuraPair; 12 | use sc_finality_grandpa::SharedVoterState; 13 | use sc_keystore::LocalKeystore; 14 | 15 | // Our native executor instance. 16 | native_executor_instance!( 17 | pub Executor, 18 | node_template_runtime::api::dispatch, 19 | node_template_runtime::native_version, 20 | frame_benchmarking::benchmarking::HostFunctions, 21 | ); 22 | 23 | type FullClient = sc_service::TFullClient; 24 | type FullBackend = sc_service::TFullBackend; 25 | type FullSelectChain = sc_consensus::LongestChain; 26 | 27 | pub fn new_partial(config: &Configuration) -> Result, 30 | sc_transaction_pool::FullPool, 31 | ( 32 | sc_consensus_aura::AuraBlockImport< 33 | Block, 34 | FullClient, 35 | sc_finality_grandpa::GrandpaBlockImport, 36 | AuraPair 37 | >, 38 | sc_finality_grandpa::LinkHalf, 39 | ) 40 | >, ServiceError> { 41 | if config.keystore_remote.is_some() { 42 | return Err(ServiceError::Other( 43 | format!("Remote Keystores are not supported."))) 44 | } 45 | let inherent_data_providers = InherentDataProviders::new(); 46 | 47 | let (client, backend, keystore_container, task_manager) = 48 | sc_service::new_full_parts::(&config)?; 49 | let client = Arc::new(client); 50 | 51 | let select_chain = sc_consensus::LongestChain::new(backend.clone()); 52 | 53 | let transaction_pool = sc_transaction_pool::BasicPool::new_full( 54 | config.transaction_pool.clone(), 55 | config.role.is_authority().into(), 56 | config.prometheus_registry(), 57 | task_manager.spawn_handle(), 58 | client.clone(), 59 | ); 60 | 61 | let (grandpa_block_import, grandpa_link) = sc_finality_grandpa::block_import( 62 | client.clone(), 63 | &(client.clone() as Arc<_>), 64 | select_chain.clone(), 65 | )?; 66 | 67 | let aura_block_import = sc_consensus_aura::AuraBlockImport::<_, _, _, AuraPair>::new( 68 | grandpa_block_import.clone(), client.clone(), 69 | ); 70 | 71 | let import_queue = sc_consensus_aura::import_queue::<_, _, _, AuraPair, _, _>( 72 | sc_consensus_aura::slot_duration(&*client)?, 73 | aura_block_import.clone(), 74 | Some(Box::new(grandpa_block_import.clone())), 75 | client.clone(), 76 | inherent_data_providers.clone(), 77 | &task_manager.spawn_handle(), 78 | config.prometheus_registry(), 79 | sp_consensus::CanAuthorWithNativeVersion::new(client.executor().clone()), 80 | )?; 81 | 82 | Ok(sc_service::PartialComponents { 83 | client, 84 | backend, 85 | task_manager, 86 | import_queue, 87 | keystore_container, 88 | select_chain, 89 | transaction_pool, 90 | inherent_data_providers, 91 | other: (aura_block_import, grandpa_link), 92 | }) 93 | } 94 | 95 | fn remote_keystore(_url: &String) -> Result, &'static str> { 96 | // FIXME: here would the concrete keystore be built, 97 | // must return a concrete type (NOT `LocalKeystore`) that 98 | // implements `CryptoStore` and `SyncCryptoStore` 99 | Err("Remote Keystore not supported.") 100 | } 101 | 102 | /// Builds a new service for a full client. 103 | pub fn new_full(mut config: Configuration) -> Result { 104 | let sc_service::PartialComponents { 105 | client, 106 | backend, 107 | mut task_manager, 108 | import_queue, 109 | mut keystore_container, 110 | select_chain, 111 | transaction_pool, 112 | inherent_data_providers, 113 | other: (block_import, grandpa_link), 114 | } = new_partial(&config)?; 115 | 116 | if let Some(url) = &config.keystore_remote { 117 | match remote_keystore(url) { 118 | Ok(k) => keystore_container.set_remote_keystore(k), 119 | Err(e) => { 120 | return Err(ServiceError::Other( 121 | format!("Error hooking up remote keystore for {}: {}", url, e))) 122 | } 123 | }; 124 | } 125 | 126 | config.network.extra_sets.push(sc_finality_grandpa::grandpa_peers_set_config()); 127 | 128 | let (network, network_status_sinks, system_rpc_tx, network_starter) = 129 | sc_service::build_network(sc_service::BuildNetworkParams { 130 | config: &config, 131 | client: client.clone(), 132 | transaction_pool: transaction_pool.clone(), 133 | spawn_handle: task_manager.spawn_handle(), 134 | import_queue, 135 | on_demand: None, 136 | block_announce_validator_builder: None, 137 | })?; 138 | 139 | if config.offchain_worker.enabled { 140 | sc_service::build_offchain_workers( 141 | &config, backend.clone(), task_manager.spawn_handle(), client.clone(), network.clone(), 142 | ); 143 | } 144 | 145 | let role = config.role.clone(); 146 | let force_authoring = config.force_authoring; 147 | let backoff_authoring_blocks: Option<()> = None; 148 | let name = config.network.node_name.clone(); 149 | let enable_grandpa = !config.disable_grandpa; 150 | let prometheus_registry = config.prometheus_registry().cloned(); 151 | 152 | let rpc_extensions_builder = { 153 | let client = client.clone(); 154 | let pool = transaction_pool.clone(); 155 | 156 | Box::new(move |deny_unsafe, _| { 157 | let deps = crate::rpc::FullDeps { 158 | client: client.clone(), 159 | pool: pool.clone(), 160 | deny_unsafe, 161 | }; 162 | 163 | crate::rpc::create_full(deps) 164 | }) 165 | }; 166 | 167 | let (_rpc_handlers, telemetry_connection_notifier) = sc_service::spawn_tasks( 168 | sc_service::SpawnTasksParams { 169 | network: network.clone(), 170 | client: client.clone(), 171 | keystore: keystore_container.sync_keystore(), 172 | task_manager: &mut task_manager, 173 | transaction_pool: transaction_pool.clone(), 174 | rpc_extensions_builder, 175 | on_demand: None, 176 | remote_blockchain: None, 177 | backend, 178 | network_status_sinks, 179 | system_rpc_tx, 180 | config, 181 | }, 182 | )?; 183 | 184 | if role.is_authority() { 185 | let proposer_factory = sc_basic_authorship::ProposerFactory::new( 186 | task_manager.spawn_handle(), 187 | client.clone(), 188 | transaction_pool, 189 | prometheus_registry.as_ref(), 190 | ); 191 | 192 | let can_author_with = 193 | sp_consensus::CanAuthorWithNativeVersion::new(client.executor().clone()); 194 | 195 | let aura = sc_consensus_aura::start_aura::<_, _, _, _, _, AuraPair, _, _, _,_>( 196 | sc_consensus_aura::slot_duration(&*client)?, 197 | client.clone(), 198 | select_chain, 199 | block_import, 200 | proposer_factory, 201 | network.clone(), 202 | inherent_data_providers.clone(), 203 | force_authoring, 204 | backoff_authoring_blocks, 205 | keystore_container.sync_keystore(), 206 | can_author_with, 207 | )?; 208 | 209 | // the AURA authoring task is considered essential, i.e. if it 210 | // fails we take down the service with it. 211 | task_manager.spawn_essential_handle().spawn_blocking("aura", aura); 212 | } 213 | 214 | // if the node isn't actively participating in consensus then it doesn't 215 | // need a keystore, regardless of which protocol we use below. 216 | let keystore = if role.is_authority() { 217 | Some(keystore_container.sync_keystore()) 218 | } else { 219 | None 220 | }; 221 | 222 | let grandpa_config = sc_finality_grandpa::Config { 223 | // FIXME #1578 make this available through chainspec 224 | gossip_duration: Duration::from_millis(333), 225 | justification_period: 512, 226 | name: Some(name), 227 | observer_enabled: false, 228 | keystore, 229 | is_authority: role.is_network_authority(), 230 | }; 231 | 232 | if enable_grandpa { 233 | // start the full GRANDPA voter 234 | // NOTE: non-authorities could run the GRANDPA observer protocol, but at 235 | // this point the full voter should provide better guarantees of block 236 | // and vote data availability than the observer. The observer has not 237 | // been tested extensively yet and having most nodes in a network run it 238 | // could lead to finality stalls. 239 | let grandpa_config = sc_finality_grandpa::GrandpaParams { 240 | config: grandpa_config, 241 | link: grandpa_link, 242 | network, 243 | voting_rule: sc_finality_grandpa::VotingRulesBuilder::default().build(), 244 | prometheus_registry, 245 | shared_voter_state: SharedVoterState::empty(), 246 | telemetry_on_connect: telemetry_connection_notifier.map(|x| x.on_connect_stream()), 247 | }; 248 | 249 | // the GRANDPA voter task is considered infallible, i.e. 250 | // if it fails we take down the service with it. 251 | task_manager.spawn_essential_handle().spawn_blocking( 252 | "grandpa-voter", 253 | sc_finality_grandpa::run_grandpa_voter(grandpa_config)? 254 | ); 255 | } 256 | 257 | network_starter.start_network(); 258 | Ok(task_manager) 259 | } 260 | 261 | /// Builds a new service for a light client. 262 | pub fn new_light(mut config: Configuration) -> Result { 263 | let (client, backend, keystore_container, mut task_manager, on_demand) = 264 | sc_service::new_light_parts::(&config)?; 265 | 266 | config.network.extra_sets.push(sc_finality_grandpa::grandpa_peers_set_config()); 267 | 268 | let select_chain = sc_consensus::LongestChain::new(backend.clone()); 269 | 270 | let transaction_pool = Arc::new(sc_transaction_pool::BasicPool::new_light( 271 | config.transaction_pool.clone(), 272 | config.prometheus_registry(), 273 | task_manager.spawn_handle(), 274 | client.clone(), 275 | on_demand.clone(), 276 | )); 277 | 278 | let (grandpa_block_import, _) = sc_finality_grandpa::block_import( 279 | client.clone(), 280 | &(client.clone() as Arc<_>), 281 | select_chain.clone(), 282 | )?; 283 | 284 | let aura_block_import = sc_consensus_aura::AuraBlockImport::<_, _, _, AuraPair>::new( 285 | grandpa_block_import.clone(), 286 | client.clone(), 287 | ); 288 | 289 | let import_queue = sc_consensus_aura::import_queue::<_, _, _, AuraPair, _, _>( 290 | sc_consensus_aura::slot_duration(&*client)?, 291 | aura_block_import, 292 | Some(Box::new(grandpa_block_import)), 293 | client.clone(), 294 | InherentDataProviders::new(), 295 | &task_manager.spawn_handle(), 296 | config.prometheus_registry(), 297 | sp_consensus::NeverCanAuthor, 298 | )?; 299 | 300 | let (network, network_status_sinks, system_rpc_tx, network_starter) = 301 | sc_service::build_network(sc_service::BuildNetworkParams { 302 | config: &config, 303 | client: client.clone(), 304 | transaction_pool: transaction_pool.clone(), 305 | spawn_handle: task_manager.spawn_handle(), 306 | import_queue, 307 | on_demand: Some(on_demand.clone()), 308 | block_announce_validator_builder: None, 309 | })?; 310 | 311 | if config.offchain_worker.enabled { 312 | sc_service::build_offchain_workers( 313 | &config, backend.clone(), task_manager.spawn_handle(), client.clone(), network.clone(), 314 | ); 315 | } 316 | 317 | sc_service::spawn_tasks(sc_service::SpawnTasksParams { 318 | remote_blockchain: Some(backend.remote_blockchain()), 319 | transaction_pool, 320 | task_manager: &mut task_manager, 321 | on_demand: Some(on_demand), 322 | rpc_extensions_builder: Box::new(|_, _| ()), 323 | config, 324 | client, 325 | keystore: keystore_container.sync_keystore(), 326 | backend, 327 | network, 328 | network_status_sinks, 329 | system_rpc_tx, 330 | })?; 331 | 332 | network_starter.start_network(); 333 | 334 | Ok(task_manager) 335 | } 336 | -------------------------------------------------------------------------------- /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 sp_std::prelude::*; 10 | use sp_core::{crypto::KeyTypeId, OpaqueMetadata}; 11 | use sp_runtime::{ 12 | ApplyExtrinsicResult, generic, create_runtime_str, impl_opaque_keys, MultiSignature, 13 | transaction_validity::{TransactionValidity, TransactionSource}, 14 | }; 15 | use sp_runtime::traits::{ 16 | BlakeTwo256, Block as BlockT, AccountIdLookup, Verify, IdentifyAccount, NumberFor, 17 | }; 18 | use sp_api::impl_runtime_apis; 19 | use sp_consensus_aura::sr25519::AuthorityId as AuraId; 20 | use pallet_grandpa::{AuthorityId as GrandpaId, AuthorityList as GrandpaAuthorityList}; 21 | use pallet_grandpa::fg_primitives; 22 | use sp_version::RuntimeVersion; 23 | #[cfg(feature = "std")] 24 | use sp_version::NativeVersion; 25 | 26 | // A few exports that help ease life for downstream crates. 27 | #[cfg(any(feature = "std", test))] 28 | pub use sp_runtime::BuildStorage; 29 | pub use pallet_timestamp::Call as TimestampCall; 30 | pub use pallet_balances::Call as BalancesCall; 31 | pub use sp_runtime::{Permill, Perbill}; 32 | pub use frame_support::{ 33 | construct_runtime, parameter_types, StorageValue, 34 | traits::{KeyOwnerProofSystem, Randomness}, 35 | weights::{ 36 | Weight, IdentityFee, 37 | constants::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight, WEIGHT_PER_SECOND}, 38 | }, 39 | }; 40 | use pallet_transaction_payment::CurrencyAdapter; 41 | 42 | /// Import the template pallet. 43 | pub use pallet_template; 44 | 45 | /// An index to a block. 46 | pub type BlockNumber = u32; 47 | 48 | /// Alias to 512-bit hash when used in the context of a transaction signature on the chain. 49 | pub type Signature = MultiSignature; 50 | 51 | /// Some way of identifying an account on the chain. We intentionally make it equivalent 52 | /// to the public key of our transaction signing scheme. 53 | pub type AccountId = <::Signer as IdentifyAccount>::AccountId; 54 | 55 | /// The type for looking up accounts. We don't expect more than 4 billion of them, but you 56 | /// never know... 57 | pub type AccountIndex = u32; 58 | 59 | /// Balance of an account. 60 | pub type Balance = u128; 61 | 62 | /// Index of a transaction in the chain. 63 | pub type Index = u32; 64 | 65 | /// A hash of some data used by the chain. 66 | pub type Hash = sp_core::H256; 67 | 68 | /// Digest item type. 69 | pub type DigestItem = generic::DigestItem; 70 | 71 | /// Opaque types. These are used by the CLI to instantiate machinery that don't need to know 72 | /// the specifics of the runtime. They can then be made to be agnostic over specific formats 73 | /// of data like extrinsics, allowing for them to continue syncing the network through upgrades 74 | /// to even the core data structures. 75 | pub mod opaque { 76 | use super::*; 77 | 78 | pub use sp_runtime::OpaqueExtrinsic as UncheckedExtrinsic; 79 | 80 | /// Opaque block header type. 81 | pub type Header = generic::Header; 82 | /// Opaque block type. 83 | pub type Block = generic::Block; 84 | /// Opaque block identifier type. 85 | pub type BlockId = generic::BlockId; 86 | 87 | impl_opaque_keys! { 88 | pub struct SessionKeys { 89 | pub aura: Aura, 90 | pub grandpa: Grandpa, 91 | } 92 | } 93 | } 94 | 95 | // To learn more about runtime versioning and what each of the following value means: 96 | // https://substrate.dev/docs/en/knowledgebase/runtime/upgrades#runtime-versioning 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 | }; 111 | 112 | /// This determines the average expected block time that we are targeting. 113 | /// Blocks will be produced at a minimum duration defined by `SLOT_DURATION`. 114 | /// `SLOT_DURATION` is picked up by `pallet_timestamp` which is in turn picked 115 | /// up by `pallet_aura` to implement `fn slot_duration()`. 116 | /// 117 | /// Change this to adjust the block time. 118 | pub const MILLISECS_PER_BLOCK: u64 = 6000; 119 | 120 | pub const SLOT_DURATION: u64 = MILLISECS_PER_BLOCK; 121 | 122 | // Time is measured by number of blocks. 123 | pub const MINUTES: BlockNumber = 60_000 / (MILLISECS_PER_BLOCK as BlockNumber); 124 | pub const HOURS: BlockNumber = MINUTES * 60; 125 | pub const DAYS: BlockNumber = HOURS * 24; 126 | 127 | /// The version information used to identify this runtime when compiled natively. 128 | #[cfg(feature = "std")] 129 | pub fn native_version() -> NativeVersion { 130 | NativeVersion { 131 | runtime_version: VERSION, 132 | can_author_with: Default::default(), 133 | } 134 | } 135 | 136 | const NORMAL_DISPATCH_RATIO: Perbill = Perbill::from_percent(75); 137 | 138 | parameter_types! { 139 | pub const Version: RuntimeVersion = VERSION; 140 | pub const BlockHashCount: BlockNumber = 2400; 141 | /// We allow for 2 seconds of compute with a 6 second average block time. 142 | pub BlockWeights: frame_system::limits::BlockWeights = frame_system::limits::BlockWeights 143 | ::with_sensible_defaults(2 * WEIGHT_PER_SECOND, NORMAL_DISPATCH_RATIO); 144 | pub BlockLength: frame_system::limits::BlockLength = frame_system::limits::BlockLength 145 | ::max_with_normal_ratio(5 * 1024 * 1024, NORMAL_DISPATCH_RATIO); 146 | pub const SS58Prefix: u8 = 42; 147 | } 148 | 149 | // Configure FRAME pallets to include in runtime. 150 | 151 | impl frame_system::Config for Runtime { 152 | /// The basic call filter to use in dispatchable. 153 | type BaseCallFilter = (); 154 | /// Block & extrinsics weights: base values and limits. 155 | type BlockWeights = BlockWeights; 156 | /// The maximum length of a block (in bytes). 157 | type BlockLength = BlockLength; 158 | /// The identifier used to distinguish between accounts. 159 | type AccountId = AccountId; 160 | /// The aggregated dispatch type that is available for extrinsics. 161 | type Call = Call; 162 | /// The lookup mechanism to get account ID from whatever is passed in dispatchers. 163 | type Lookup = AccountIdLookup; 164 | /// The index type for storing how many extrinsics an account has signed. 165 | type Index = Index; 166 | /// The index type for blocks. 167 | type BlockNumber = BlockNumber; 168 | /// The type for hashing blocks and tries. 169 | type Hash = Hash; 170 | /// The hashing algorithm used. 171 | type Hashing = BlakeTwo256; 172 | /// The header type. 173 | type Header = generic::Header; 174 | /// The ubiquitous event type. 175 | type Event = Event; 176 | /// The ubiquitous origin type. 177 | type Origin = Origin; 178 | /// Maximum number of block number to block hash mappings to keep (oldest pruned first). 179 | type BlockHashCount = BlockHashCount; 180 | /// The weight of database operations that the runtime can invoke. 181 | type DbWeight = RocksDbWeight; 182 | /// Version of the runtime. 183 | type Version = Version; 184 | /// Converts a module to the index of the module in `construct_runtime!`. 185 | /// 186 | /// This type is being generated by `construct_runtime!`. 187 | type PalletInfo = PalletInfo; 188 | /// What to do if a new account is created. 189 | type OnNewAccount = (); 190 | /// What to do if an account is fully reaped from the system. 191 | type OnKilledAccount = (); 192 | /// The data to be stored in an account. 193 | type AccountData = pallet_balances::AccountData; 194 | /// Weight information for the extrinsics of this pallet. 195 | type SystemWeightInfo = (); 196 | /// This is used as an identifier of the chain. 42 is the generic substrate prefix. 197 | type SS58Prefix = SS58Prefix; 198 | } 199 | 200 | impl pallet_aura::Config for Runtime { 201 | type AuthorityId = AuraId; 202 | } 203 | 204 | impl pallet_grandpa::Config for Runtime { 205 | type Event = Event; 206 | type Call = Call; 207 | 208 | type KeyOwnerProofSystem = (); 209 | 210 | type KeyOwnerProof = 211 | >::Proof; 212 | 213 | type KeyOwnerIdentification = >::IdentificationTuple; 217 | 218 | type HandleEquivocation = (); 219 | 220 | type WeightInfo = (); 221 | } 222 | 223 | parameter_types! { 224 | pub const MinimumPeriod: u64 = SLOT_DURATION / 2; 225 | } 226 | 227 | impl pallet_timestamp::Config for Runtime { 228 | /// A timestamp: milliseconds since the unix epoch. 229 | type Moment = u64; 230 | type OnTimestampSet = Aura; 231 | type MinimumPeriod = MinimumPeriod; 232 | type WeightInfo = (); 233 | } 234 | 235 | parameter_types! { 236 | pub const ExistentialDeposit: u128 = 500; 237 | pub const MaxLocks: u32 = 50; 238 | } 239 | 240 | impl pallet_balances::Config for Runtime { 241 | type MaxLocks = MaxLocks; 242 | /// The type for recording an account's balance. 243 | type Balance = Balance; 244 | /// The ubiquitous event type. 245 | type Event = Event; 246 | type DustRemoval = (); 247 | type ExistentialDeposit = ExistentialDeposit; 248 | type AccountStore = System; 249 | type WeightInfo = pallet_balances::weights::SubstrateWeight; 250 | } 251 | 252 | parameter_types! { 253 | pub const TransactionByteFee: Balance = 1; 254 | } 255 | 256 | impl pallet_transaction_payment::Config for Runtime { 257 | type OnChargeTransaction = CurrencyAdapter; 258 | type TransactionByteFee = TransactionByteFee; 259 | type WeightToFee = IdentityFee; 260 | type FeeMultiplierUpdate = (); 261 | } 262 | 263 | impl pallet_sudo::Config for Runtime { 264 | type Event = Event; 265 | type Call = Call; 266 | } 267 | 268 | /// Configure the pallet-template in pallets/template. 269 | impl pallet_template::Config for Runtime { 270 | type Event = Event; 271 | } 272 | 273 | // Create the runtime by composing the FRAME pallets that were previously configured. 274 | construct_runtime!( 275 | pub enum Runtime where 276 | Block = Block, 277 | NodeBlock = opaque::Block, 278 | UncheckedExtrinsic = UncheckedExtrinsic 279 | { 280 | System: frame_system::{Module, Call, Config, Storage, Event}, 281 | RandomnessCollectiveFlip: pallet_randomness_collective_flip::{Module, Call, Storage}, 282 | Timestamp: pallet_timestamp::{Module, Call, Storage, Inherent}, 283 | Aura: pallet_aura::{Module, Config}, 284 | Grandpa: pallet_grandpa::{Module, Call, Storage, Config, Event}, 285 | Balances: pallet_balances::{Module, Call, Storage, Config, Event}, 286 | TransactionPayment: pallet_transaction_payment::{Module, Storage}, 287 | Sudo: pallet_sudo::{Module, Call, Config, Storage, Event}, 288 | // Include the custom logic from the pallet-template in the runtime. 289 | TemplateModule: pallet_template::{Module, Call, Storage, Event}, 290 | } 291 | ); 292 | 293 | /// The address format for describing accounts. 294 | pub type Address = sp_runtime::MultiAddress; 295 | /// Block header type as expected by this runtime. 296 | pub type Header = generic::Header; 297 | /// Block type as expected by this runtime. 298 | pub type Block = generic::Block; 299 | /// A Block signed with a Justification 300 | pub type SignedBlock = generic::SignedBlock; 301 | /// BlockId type as expected by this runtime. 302 | pub type BlockId = generic::BlockId; 303 | /// The SignedExtension to the basic transaction logic. 304 | pub type SignedExtra = ( 305 | frame_system::CheckSpecVersion, 306 | frame_system::CheckTxVersion, 307 | frame_system::CheckGenesis, 308 | frame_system::CheckEra, 309 | frame_system::CheckNonce, 310 | frame_system::CheckWeight, 311 | pallet_transaction_payment::ChargeTransactionPayment 312 | ); 313 | /// Unchecked extrinsic type as expected by this runtime. 314 | pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; 315 | /// Extrinsic type that has already been checked. 316 | pub type CheckedExtrinsic = generic::CheckedExtrinsic; 317 | /// Executive: handles dispatch to the various modules. 318 | pub type Executive = frame_executive::Executive< 319 | Runtime, 320 | Block, 321 | frame_system::ChainContext, 322 | Runtime, 323 | AllModules, 324 | >; 325 | 326 | impl_runtime_apis! { 327 | impl sp_api::Core for Runtime { 328 | fn version() -> RuntimeVersion { 329 | VERSION 330 | } 331 | 332 | fn execute_block(block: Block) { 333 | Executive::execute_block(block); 334 | } 335 | 336 | fn initialize_block(header: &::Header) { 337 | Executive::initialize_block(header) 338 | } 339 | } 340 | 341 | impl sp_api::Metadata for Runtime { 342 | fn metadata() -> OpaqueMetadata { 343 | Runtime::metadata().into() 344 | } 345 | } 346 | 347 | impl sp_block_builder::BlockBuilder for Runtime { 348 | fn apply_extrinsic(extrinsic: ::Extrinsic) -> ApplyExtrinsicResult { 349 | Executive::apply_extrinsic(extrinsic) 350 | } 351 | 352 | fn finalize_block() -> ::Header { 353 | Executive::finalize_block() 354 | } 355 | 356 | fn inherent_extrinsics(data: sp_inherents::InherentData) -> Vec<::Extrinsic> { 357 | data.create_extrinsics() 358 | } 359 | 360 | fn check_inherents( 361 | block: Block, 362 | data: sp_inherents::InherentData, 363 | ) -> sp_inherents::CheckInherentsResult { 364 | data.check_extrinsics(&block) 365 | } 366 | 367 | fn random_seed() -> ::Hash { 368 | RandomnessCollectiveFlip::random_seed() 369 | } 370 | } 371 | 372 | impl sp_transaction_pool::runtime_api::TaggedTransactionQueue for Runtime { 373 | fn validate_transaction( 374 | source: TransactionSource, 375 | tx: ::Extrinsic, 376 | ) -> TransactionValidity { 377 | Executive::validate_transaction(source, tx) 378 | } 379 | } 380 | 381 | impl sp_offchain::OffchainWorkerApi for Runtime { 382 | fn offchain_worker(header: &::Header) { 383 | Executive::offchain_worker(header) 384 | } 385 | } 386 | 387 | impl sp_consensus_aura::AuraApi for Runtime { 388 | fn slot_duration() -> u64 { 389 | Aura::slot_duration() 390 | } 391 | 392 | fn authorities() -> Vec { 393 | Aura::authorities() 394 | } 395 | } 396 | 397 | impl sp_session::SessionKeys for Runtime { 398 | fn generate_session_keys(seed: Option>) -> Vec { 399 | opaque::SessionKeys::generate(seed) 400 | } 401 | 402 | fn decode_session_keys( 403 | encoded: Vec, 404 | ) -> Option, KeyTypeId)>> { 405 | opaque::SessionKeys::decode_into_raw_public_keys(&encoded) 406 | } 407 | } 408 | 409 | impl fg_primitives::GrandpaApi for Runtime { 410 | fn grandpa_authorities() -> GrandpaAuthorityList { 411 | Grandpa::grandpa_authorities() 412 | } 413 | 414 | fn submit_report_equivocation_unsigned_extrinsic( 415 | _equivocation_proof: fg_primitives::EquivocationProof< 416 | ::Hash, 417 | NumberFor, 418 | >, 419 | _key_owner_proof: fg_primitives::OpaqueKeyOwnershipProof, 420 | ) -> Option<()> { 421 | None 422 | } 423 | 424 | fn generate_key_ownership_proof( 425 | _set_id: fg_primitives::SetId, 426 | _authority_id: GrandpaId, 427 | ) -> Option { 428 | // NOTE: this is the only implementation possible since we've 429 | // defined our key owner proof type as a bottom type (i.e. a type 430 | // with no values). 431 | None 432 | } 433 | } 434 | 435 | impl frame_system_rpc_runtime_api::AccountNonceApi for Runtime { 436 | fn account_nonce(account: AccountId) -> Index { 437 | System::account_nonce(account) 438 | } 439 | } 440 | 441 | impl pallet_transaction_payment_rpc_runtime_api::TransactionPaymentApi for Runtime { 442 | fn query_info( 443 | uxt: ::Extrinsic, 444 | len: u32, 445 | ) -> pallet_transaction_payment_rpc_runtime_api::RuntimeDispatchInfo { 446 | TransactionPayment::query_info(uxt, len) 447 | } 448 | fn query_fee_details( 449 | uxt: ::Extrinsic, 450 | len: u32, 451 | ) -> pallet_transaction_payment::FeeDetails { 452 | TransactionPayment::query_fee_details(uxt, len) 453 | } 454 | } 455 | 456 | #[cfg(feature = "runtime-benchmarks")] 457 | impl frame_benchmarking::Benchmark for Runtime { 458 | fn dispatch_benchmark( 459 | config: frame_benchmarking::BenchmarkConfig 460 | ) -> Result, sp_runtime::RuntimeString> { 461 | use frame_benchmarking::{Benchmarking, BenchmarkBatch, add_benchmark, TrackedStorageKey}; 462 | 463 | use frame_system_benchmarking::Pallet as SystemBench; 464 | impl frame_system_benchmarking::Config for Runtime {} 465 | 466 | let whitelist: Vec = vec![ 467 | // Block Number 468 | hex_literal::hex!("26aa394eea5630e07c48ae0c9558cef702a5c1b19ab7a04f536c519aca4983ac").to_vec().into(), 469 | // Total Issuance 470 | hex_literal::hex!("c2261276cc9d1f8598ea4b6a74b15c2f57c875e4cff74148e4628f264b974c80").to_vec().into(), 471 | // Execution Phase 472 | hex_literal::hex!("26aa394eea5630e07c48ae0c9558cef7ff553b5a9862a516939d82b3d3d8661a").to_vec().into(), 473 | // Event Count 474 | hex_literal::hex!("26aa394eea5630e07c48ae0c9558cef70a98fdbe9ce6c55837576c60c7af3850").to_vec().into(), 475 | // System Events 476 | hex_literal::hex!("26aa394eea5630e07c48ae0c9558cef780d41e5e16056765bc8461851072c9d7").to_vec().into(), 477 | ]; 478 | 479 | let mut batches = Vec::::new(); 480 | let params = (&config, &whitelist); 481 | 482 | add_benchmark!(params, batches, frame_system, SystemBench::); 483 | add_benchmark!(params, batches, pallet_balances, Balances); 484 | add_benchmark!(params, batches, pallet_timestamp, Timestamp); 485 | add_benchmark!(params, batches, pallet_template, TemplateModule); 486 | 487 | if batches.is_empty() { return Err("Benchmark not found for this pallet.".into()) } 488 | Ok(batches) 489 | } 490 | } 491 | } 492 | --------------------------------------------------------------------------------