├── .devcontainer └── devcontainer.json ├── .editorconfig ├── .github └── workflows │ ├── build-book.yml │ ├── build-deploy-book.yml │ ├── docker-images.yml │ ├── link-check.yml │ ├── mlc_config.json │ ├── playground.yml │ └── test-code.yml ├── .gitignore ├── .prettierrc.json ├── CONTRIBUTING.md ├── Cargo.lock ├── Cargo.toml ├── LICENSE ├── README.md ├── book.toml ├── consensus └── sha3pow │ ├── Cargo.toml │ └── src │ └── lib.rs ├── nodes ├── basic-pow │ ├── Cargo.toml │ ├── Dockerfile │ ├── build.rs │ └── src │ │ ├── chain_spec.rs │ │ ├── cli.rs │ │ ├── command.rs │ │ ├── main.rs │ │ └── service.rs ├── hybrid-consensus │ ├── Cargo.toml │ ├── Dockerfile │ ├── build.rs │ └── src │ │ ├── chain_spec.rs │ │ ├── cli.rs │ │ ├── command.rs │ │ ├── main.rs │ │ └── service.rs ├── kitchen-node │ ├── Cargo.toml │ ├── Dockerfile │ ├── build.rs │ └── src │ │ ├── chain_spec.rs │ │ ├── cli.rs │ │ ├── command.rs │ │ ├── main.rs │ │ └── service.rs ├── manual-seal │ └── Dockerfile └── rpc-node │ ├── Cargo.toml │ ├── Dockerfile │ ├── build.rs │ ├── js │ ├── index.js │ ├── package.json │ └── yarn.lock │ └── src │ ├── chain_spec.rs │ ├── cli.rs │ ├── command.rs │ ├── main.rs │ ├── rpc.rs │ ├── service.rs │ └── silly_rpc.rs ├── pallets ├── basic-token │ ├── Cargo.toml │ ├── src │ │ ├── lib.rs │ │ └── tests.rs │ └── types.json ├── charity │ ├── Cargo.toml │ ├── src │ │ ├── lib.rs │ │ └── tests.rs │ └── types.json ├── check-membership │ ├── Cargo.toml │ ├── src │ │ ├── lib.rs │ │ ├── loose │ │ │ ├── mod.rs │ │ │ └── tests.rs │ │ └── tight │ │ │ ├── mod.rs │ │ │ └── tests.rs │ └── types.json ├── compounding-interest │ ├── Cargo.toml │ ├── src │ │ ├── lib.rs │ │ └── tests.rs │ └── types.json ├── constant-config │ ├── Cargo.toml │ ├── src │ │ ├── lib.rs │ │ └── tests.rs │ └── types.json ├── currency-imbalances │ ├── Cargo.toml │ ├── src │ │ └── lib.rs │ └── types.json ├── default-instance │ ├── Cargo.toml │ ├── src │ │ └── lib.rs │ └── types.json ├── double-map │ ├── Cargo.toml │ ├── src │ │ ├── lib.rs │ │ └── tests.rs │ └── types.json ├── fixed-point │ ├── Cargo.toml │ ├── src │ │ ├── lib.rs │ │ └── tests.rs │ └── types.json ├── generic-event │ ├── Cargo.toml │ ├── src │ │ ├── lib.rs │ │ └── tests.rs │ └── types.json ├── hello-substrate │ ├── Cargo.toml │ ├── src │ │ ├── lib.rs │ │ └── tests.rs │ └── types.json ├── last-caller │ ├── Cargo.toml │ ├── src │ │ └── lib.rs │ └── types.json ├── lockable-currency │ ├── Cargo.toml │ ├── src │ │ └── lib.rs │ └── types.json ├── map-set │ ├── Cargo.toml │ ├── src │ │ ├── lib.rs │ │ └── tests.rs │ └── types.json ├── ocw-demo │ ├── Cargo.toml │ ├── src │ │ ├── lib.rs │ │ └── tests.rs │ └── types.json ├── randomness │ ├── Cargo.toml │ ├── src │ │ ├── lib.rs │ │ └── tests.rs │ └── types.json ├── reservable-currency │ ├── Cargo.toml │ ├── src │ │ ├── lib.rs │ │ └── tests.rs │ └── types.json ├── ringbuffer-queue │ ├── Cargo.toml │ ├── src │ │ ├── lib.rs │ │ ├── ringbuffer.rs │ │ └── tests.rs │ └── types.json ├── simple-crowdfund │ ├── Cargo.toml │ ├── src │ │ ├── lib.rs │ │ └── tests.rs │ └── types.json ├── simple-event │ ├── Cargo.toml │ ├── src │ │ ├── lib.rs │ │ └── tests.rs │ └── types.json ├── simple-map │ ├── Cargo.toml │ ├── src │ │ ├── lib.rs │ │ └── tests.rs │ └── types.json ├── storage-cache │ ├── Cargo.toml │ ├── src │ │ ├── lib.rs │ │ └── tests.rs │ └── types.json ├── struct-storage │ ├── Cargo.toml │ ├── src │ │ ├── lib.rs │ │ └── tests.rs │ └── types.json ├── sum-storage │ ├── Cargo.toml │ ├── rpc │ │ ├── Cargo.toml │ │ └── src │ │ │ └── lib.rs │ ├── runtime-api │ │ ├── Cargo.toml │ │ └── src │ │ │ └── lib.rs │ ├── src │ │ ├── lib.rs │ │ └── tests.rs │ └── types.json ├── vec-set │ ├── Cargo.toml │ ├── src │ │ ├── lib.rs │ │ └── tests.rs │ └── types.json └── weights │ ├── Cargo.toml │ ├── src │ └── lib.rs │ └── types.json ├── runtimes ├── api-runtime │ ├── Cargo.toml │ ├── aggregate_types.js │ ├── build.rs │ ├── src │ │ ├── genesis.rs │ │ └── lib.rs │ └── types.json ├── minimal-grandpa-runtime │ ├── Cargo.toml │ ├── aggregate_types.js │ ├── build.rs │ ├── src │ │ ├── genesis.rs │ │ └── lib.rs │ └── types.json ├── ocw-runtime │ ├── Cargo.toml │ ├── aggregate_types.js │ ├── build.rs │ ├── src │ │ ├── genesis.rs │ │ └── lib.rs │ └── types.json ├── super-runtime │ ├── Cargo.toml │ ├── aggregate_types.js │ ├── build.rs │ ├── src │ │ ├── genesis.rs │ │ └── lib.rs │ └── types.json └── weight-fee-runtime │ ├── Cargo.toml │ ├── aggregate_types.js │ ├── build.rs │ ├── src │ ├── genesis.rs │ └── lib.rs │ └── types.json ├── rustfmt.toml ├── text ├── SUMMARY.md ├── basic-pow.md ├── basic-token.md ├── cache.md ├── charity.md ├── consensus-intro.md ├── constants.md ├── crowdfund.md ├── currency-imbalances.md ├── currency.md ├── custom-rpc.md ├── double.md ├── events.md ├── fees.md ├── fixed-point.md ├── hybrid-consensus.md ├── img │ ├── apps-manual-seal-create-block.png │ ├── apps-select-network.png │ ├── apps-types.png │ ├── multiple-ocws.png │ └── substrate-architecture.png ├── instantiable.md ├── introduction.md ├── kitchen-node.md ├── map-set.md ├── nodes-intro.md ├── off-chain-workers │ ├── http-json.md │ ├── index.md │ ├── indexing.md │ ├── storage.md │ └── transactions.md ├── pallet-coupling.md ├── pallets-intro.md ├── randomness.md ├── ringbuffer.md ├── runtime-api.md ├── runtime-printing.md ├── runtimes-intro.md ├── sha3-pow-consensus.md ├── storage-maps.md ├── structs.md ├── using-events.md ├── vec-set.md └── weights.md └── traits └── account-set ├── Cargo.toml └── src └── lib.rs /.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Substrate Recipes", 3 | "dockerFile": "Dockerfile", 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 | } 18 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | # default 4 | [*] 5 | charset=utf-8 6 | indent_style=space 7 | indent_size=2 8 | tab_width=2 9 | end_of_line=lf 10 | trim_trailing_whitespace=true 11 | max_line_length=100 12 | insert_final_newline=true 13 | 14 | [*.{toml,rs}] 15 | indent_style=tab 16 | indent_size=tab 17 | -------------------------------------------------------------------------------- /.github/workflows/build-book.yml: -------------------------------------------------------------------------------- 1 | name: Build Book 2 | 3 | on: 4 | pull_request: 5 | branches: 6 | - master 7 | push: 8 | branches: 9 | - test-ci # always want to including test-ci for testing gh-action 10 | 11 | jobs: 12 | build-book: 13 | runs-on: ubuntu-latest 14 | steps: 15 | - uses: actions/checkout@v2 16 | 17 | - name: Setup mdBook 18 | uses: peaceiris/actions-mdbook@v1 19 | with: 20 | mdbook-version: 'latest' 21 | 22 | - name: Build Book 23 | run: mdbook build 24 | -------------------------------------------------------------------------------- /.github/workflows/build-deploy-book.yml: -------------------------------------------------------------------------------- 1 | name: Build and Deploy Book 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | # Do not include test-ci, as it deploy mdbook to production 8 | 9 | jobs: 10 | build-deploy-book: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: actions/checkout@v2 14 | 15 | - name: Setup mdBook 16 | uses: peaceiris/actions-mdbook@v1 17 | with: 18 | mdbook-version: 'latest' 19 | 20 | - name: Build Book 21 | run: mdbook build 22 | 23 | - name: Deploy 24 | uses: peaceiris/actions-gh-pages@v3 25 | with: 26 | personal_token: ${{ secrets.PERSONAL_TOKEN }} 27 | publish_dir: ./book 28 | -------------------------------------------------------------------------------- /.github/workflows/docker-images.yml: -------------------------------------------------------------------------------- 1 | name: Build and Publish Docker Images 2 | 3 | on: 4 | # TODO consider doing this only when a tag is pushed. 5 | push: 6 | branches: 7 | - master 8 | #TODO Remove this, it's just for testing 9 | pull_request: 10 | branches: 11 | - master 12 | 13 | jobs: 14 | build-publish: 15 | if: ${{ github.repository == 'substrate-developer-hub/recipes' }} 16 | runs-on: ubuntu-18.04 17 | steps: 18 | - uses: actions/checkout@v2 19 | 20 | - name: Install toolchain 21 | uses: actions-rs/toolchain@v1 22 | with: 23 | profile: minimal 24 | toolchain: nightly-2021-08-31 25 | target: wasm32-unknown-unknown 26 | override: true 27 | default: true 28 | 29 | - name: Build it all 30 | run: cargo build --release 31 | 32 | - name: Clean huge target directory 33 | run: rm -r target/release/deps target/release/wbuild 34 | 35 | - uses: docker/build-push-action@v1 36 | with: 37 | username: ${{ secrets.DOCKER_USERNAME_1 }} 38 | password: ${{ secrets.DOCKER_PASSWORD_1 }} 39 | dockerfile: nodes/basic-pow/Dockerfile 40 | repository: joshyorndorff/recipes-basic-pow 41 | tags: latest 42 | add_git_labels: true 43 | tag_with_ref: true 44 | tag_with_sha: true 45 | 46 | - uses: docker/build-push-action@v1 47 | with: 48 | username: ${{ secrets.DOCKER_USERNAME_1 }} 49 | password: ${{ secrets.DOCKER_PASSWORD_1 }} 50 | dockerfile: nodes/hybrid-consensus/Dockerfile 51 | repository: joshyorndorff/recipes-hybrid-consensus 52 | tags: latest 53 | add_git_labels: true 54 | tag_with_ref: true 55 | tag_with_sha: true 56 | 57 | - uses: docker/build-push-action@v1 58 | with: 59 | username: ${{ secrets.DOCKER_USERNAME_1 }} 60 | password: ${{ secrets.DOCKER_PASSWORD_1 }} 61 | dockerfile: nodes/kitchen-node/Dockerfile 62 | repository: joshyorndorff/recipes-kitchen-node 63 | tags: latest 64 | add_git_labels: true 65 | tag_with_ref: true 66 | tag_with_sha: true 67 | 68 | - uses: docker/build-push-action@v1 69 | with: 70 | username: ${{ secrets.DOCKER_USERNAME_1 }} 71 | password: ${{ secrets.DOCKER_PASSWORD_1 }} 72 | dockerfile: nodes/rpc-node/Dockerfile 73 | repository: joshyorndorff/recipes-rpc-node 74 | tags: latest 75 | add_git_labels: true 76 | tag_with_ref: true 77 | tag_with_sha: true 78 | -------------------------------------------------------------------------------- /.github/workflows/link-check.yml: -------------------------------------------------------------------------------- 1 | name: Check Links 2 | 3 | on: 4 | pull_request: 5 | branches: 6 | - master 7 | push: 8 | branches: 9 | - master 10 | - test-ci # always want to including test-ci for testing gh-action 11 | 12 | jobs: 13 | markdown-link-check: 14 | runs-on: ubuntu-latest 15 | steps: 16 | - uses: actions/checkout@v2 17 | - uses: gaurav-nelson/github-action-markdown-link-check@v1 18 | with: 19 | # links that are okay (http status returns 200) will not be shown 20 | use-quiet-mode: 'yes' 21 | # showing the details on links returning error 22 | use-verbose-mode: 'yes' 23 | config-file: '.github/workflows/mlc_config.json' 24 | -------------------------------------------------------------------------------- /.github/workflows/mlc_config.json: -------------------------------------------------------------------------------- 1 | { 2 | "ignorePatterns": [ 3 | { 4 | "pattern": "^https://crates.io" 5 | }, 6 | { 7 | "pattern": "^https://github.com/substrate-developer-hub/recipes/tree/master" 8 | }, 9 | { 10 | "pattern": "^http://localhost" 11 | } 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /.github/workflows/playground.yml: -------------------------------------------------------------------------------- 1 | name: Build and Push Playground Image 2 | 3 | on: 4 | push: 5 | branches: 6 | # Temporarily disabled, to be fix. 7 | # - master 8 | - test-ci # always want to including test-ci for testing gh-action 9 | 10 | jobs: 11 | build-push-template: 12 | if: ${{ github.repository == 'substrate-developer-hub/recipes' }} 13 | runs-on: ubuntu-latest 14 | steps: 15 | - name: Trigger playground inclusion 16 | uses: peter-evans/repository-dispatch@v1 17 | with: 18 | token: ${{ secrets.PLAYGROUND_ACCESS_TOKEN }} 19 | repository: paritytech/substrate-playground 20 | event-type: template-updated 21 | client-payload: '{"id": "recipes"}' 22 | -------------------------------------------------------------------------------- /.github/workflows/test-code.yml: -------------------------------------------------------------------------------- 1 | name: Test Code 2 | 3 | on: 4 | pull_request: 5 | branches: 6 | - master 7 | push: 8 | branches: 9 | - master 10 | - test-ci # always want to including test-ci for testing gh-action 11 | paths-ignore: 12 | - 'README.md' 13 | 14 | jobs: 15 | test-code: 16 | name: Test 17 | strategy: 18 | matrix: 19 | toolchain: 20 | - stable 21 | runs-on: ubuntu-latest 22 | env: 23 | RUST_BACKTRACE: full 24 | CARGO_INCREMENTAL: 0 25 | 26 | steps: 27 | - name: Cancel previous runs 28 | uses: styfle/cancel-workflow-action@0.9.1 29 | with: 30 | access_token: ${{ github.token }} 31 | 32 | - name: Checkout sources & submodules 33 | uses: actions/checkout@v2 34 | with: 35 | fetch-depth: 5 36 | submodules: recursive 37 | 38 | - name: Rust Cache 39 | uses: Swatinem/rust-cache@v1 40 | 41 | - name: Install toolchain 42 | uses: actions-rs/toolchain@v1 43 | with: 44 | profile: minimal 45 | toolchain: nightly-2021-08-31 46 | components: rustfmt, clippy 47 | target: wasm32-unknown-unknown 48 | override: true 49 | default: true 50 | 51 | - name: Rust version 52 | shell: bash 53 | run: | 54 | rustup show 55 | rustup +nightly show 56 | 57 | ## --- Test stage --- 58 | 59 | - name: Run clippy 60 | run: | 61 | cargo +nightly-2021-08-31 clippy -- -D warnings 62 | 63 | - name: Run all recipes tests 64 | uses: actions-rs/cargo@v1 65 | with: 66 | command: test 67 | args: --all --verbose 68 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # md book build directory 2 | book 3 | 4 | # MacOS thing 5 | **/.DS_Store 6 | 7 | # Rust directories 8 | **/target 9 | modules/*/Cargo.lock 10 | runtimes/*/Cargo.lock 11 | 12 | # Javascript snippets burried in the code 13 | **/node_modules 14 | .idea/* -------------------------------------------------------------------------------- /.prettierrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "printWidth": 100, 3 | "proseWrap": "always" 4 | } 5 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = [ 3 | "pallets/basic-token", 4 | "pallets/charity", 5 | "pallets/check-membership", 6 | "pallets/compounding-interest", 7 | "pallets/constant-config", 8 | "pallets/currency-imbalances", 9 | "pallets/default-instance", 10 | "pallets/double-map", 11 | "pallets/fixed-point", 12 | "pallets/generic-event", 13 | "pallets/hello-substrate", 14 | "pallets/last-caller", 15 | "pallets/lockable-currency", 16 | "pallets/map-set", 17 | "pallets/ocw-demo", 18 | "pallets/randomness", 19 | "pallets/reservable-currency", 20 | "pallets/ringbuffer-queue", 21 | "pallets/simple-crowdfund", 22 | "pallets/simple-event", 23 | "pallets/simple-map", 24 | "pallets/storage-cache", 25 | "pallets/struct-storage", 26 | "pallets/sum-storage", 27 | "pallets/vec-set", 28 | "pallets/weights", 29 | "runtimes/api-runtime", 30 | "runtimes/ocw-runtime", 31 | "runtimes/minimal-grandpa-runtime", 32 | "runtimes/super-runtime", 33 | "runtimes/weight-fee-runtime", 34 | "nodes/basic-pow", 35 | "nodes/hybrid-consensus", 36 | "nodes/kitchen-node", 37 | "nodes/rpc-node", 38 | "consensus/sha3pow", 39 | "traits/account-set", 40 | ] 41 | librocksdb-sys = "6.17.3" 42 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Substrate Recipes 🍴😋🍴 2 | 3 | ![Build Status](https://img.shields.io/endpoint.svg?url=https%3A%2F%2Factions-badge.atrox.dev%2Fsubstrate-developer-hub%2Frecipes%2Fbadge%3Fref%3Dmaster&style=flat) 4 | 5 | ![Lines of Code](https://tokei.rs/b1/github/substrate-developer-hub/recipes) 6 | [![Try on playground](https://img.shields.io/badge/Playground-Recipes-brightgreen?logo=Parity%20Substrate)](https://playground.substrate.dev/?deploy=recipes) 7 | 8 | _A Hands-On Cookbook for Aspiring Blockchain Chefs_ 9 | 10 | ## Get Started 11 | 12 | Ready to roll up your sleeves and cook some blockchain? Read the book online at 13 | [substrate.recipes](https://substrate.recipes) 😋 14 | 15 | ## Repository Structure 16 | 17 | There are five primary directories in this repository: 18 | 19 | - **Text**: Source of [the book](https://substrate.recipes) written in markdown. This text 20 | describes the code in the other three directories. 21 | - **Pallets**: Pallets for use in FRAME-based runtimes. 22 | - **Runtimes**: Runtimes for use in Substrate nodes. 23 | - **Consensus**: Consensus engines for use in Substrate nodes. 24 | - **Nodes**: Complete Substrate nodes ready to run. 25 | 26 | The book is built with [mdbook](https://github.com/rust-lang/mdBook) and deployed via 27 | [github pages](https://pages.github.com/). 28 | 29 | ## Building This Book Locally 30 | 31 | Building the book requires [mdBook], ideally the same version that 32 | rust-lang/rust uses in [this file][rust-mdbook]. To get it: 33 | 34 | [mdBook]: https://github.com/rust-lang-nursery/mdBook 35 | [rust-mdbook]: https://github.com/rust-lang/rust/blob/master/src/tools/rustbook/Cargo.toml 36 | 37 | ```bash 38 | $ cargo install mdbook --vers [version-num] 39 | ``` 40 | To build the book, type: 41 | 42 | ```bash 43 | $ mdbook build 44 | ``` 45 | 46 | The output will be in the `book` subdirectory. To check it out, open up `book/index.html` in 47 | a web browser, or to serve the book locally, type: 48 | 49 | ```bash 50 | $ mdbook serve 51 | ``` 52 | 53 | The default address to view the book will be located at [http://localhost:3000](http://localhost:3000) . 54 | 55 | ## License 56 | 57 | The Substrate Recipes are [GPL 3.0 Licensed](LICENSE) It is open source and 58 | [open for contributions](./CONTRIBUTING.md). 59 | 60 | ## Using Recipes in External Projects 61 | 62 | The pallets and runtimes provided here are tested and ready to be used in other Substrate-based 63 | blockchains. The big caveat is that you must use the same upstream Substrate version throughout the 64 | project. 65 | -------------------------------------------------------------------------------- /book.toml: -------------------------------------------------------------------------------- 1 | [book] 2 | authors = ['Amar Singh', 'Joshy Orndorff', 'Jimmy Chu', 'Others'] 3 | language = "en" 4 | multilingual = false 5 | src = "text" 6 | title = "Substrate Recipes" 7 | description = "A Hands-On Cookbook for Aspiring Blockchain Chefs" 8 | 9 | [output.html] 10 | cname = "substrate.recipes" -------------------------------------------------------------------------------- /consensus/sha3pow/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = 'sha3pow' 3 | version = "3.0.0" 4 | edition = '2018' 5 | authors = ['Substrate DevHub '] 6 | repository = 'https://github.com/substrate-developer-hub/recipes' 7 | description = 'Sha3-based Proof of Work algorithms for Substrate' 8 | license = "GPL-3.0-or-later" 9 | 10 | [dependencies] 11 | parity-scale-codec = '2.0' 12 | rand = { version = "0.8", features = ["small_rng"] } 13 | sha3 = "0.9" 14 | 15 | # Substrate packages 16 | sc-consensus-pow = '0.9' 17 | sp-api = '3.0' 18 | sp-consensus-pow = '0.9' 19 | sp-core = '3.0' 20 | sp-runtime = '3.0' 21 | -------------------------------------------------------------------------------- /nodes/basic-pow/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = 'basic-pow' 3 | version = "3.0.0" 4 | edition = '2018' 5 | authors = ['Substrate DevHub '] 6 | repository = 'https://github.com/substrate-developer-hub/recipes' 7 | description = 'A Substrate node that demonstrates minimal proof of work consensus' 8 | license = "GPL-3.0-or-later" 9 | 10 | [[bin]] 11 | name = 'basic-pow' 12 | path = 'src/main.rs' 13 | 14 | [dependencies] 15 | futures = '0.3.4' 16 | log = '0.4.8' 17 | rand = { version = "0.7.2", features = ["small_rng"] } 18 | sha3 = "0.8.0" 19 | structopt = '0.3.8' 20 | 21 | # Substrate packages 22 | sc-basic-authorship = '0.9' 23 | sc-cli = '0.9' 24 | sc-client-api = '3.0' 25 | sc-consensus = '0.9' 26 | sc-consensus-pow = '0.9' 27 | sc-executor = '0.9' 28 | sc-network = '0.9' 29 | sc-service = '0.9' 30 | sc-transaction-pool = '3.0' 31 | sp-api = '3.0' 32 | sp-blockchain = '3.0' 33 | sp-consensus = '0.9' 34 | sp-core = '3.0' 35 | sp-inherents = '3.0' 36 | sp-runtime = '3.0' 37 | sp-timestamp = '3.0' 38 | sp-transaction-pool = '3.0' 39 | 40 | # local packages 41 | sha3pow = { path = '../../consensus/sha3pow' } 42 | 43 | # This node is compatible with any of the runtimes below 44 | # --- 45 | # Common runtime configured with most Recipes pallets. 46 | runtime = { package = "super-runtime", path = "../../runtimes/super-runtime" } 47 | 48 | # Runtime with custom weight and fee calculation. 49 | # runtime = { package = "weight-fee-runtime", path = "../../runtimes/weight-fee-runtime"} 50 | 51 | # Runtime with custom runtime-api (custom API only used in rpc-node) 52 | # runtime = { package = "api-runtime", path = "../../runtimes/api-runtime" } 53 | # --- 54 | 55 | [build-dependencies] 56 | substrate-build-script-utils = '3.0' 57 | vergen = '3.1.0' 58 | -------------------------------------------------------------------------------- /nodes/basic-pow/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM debian:stretch-slim 2 | 3 | # This dockerfile assumes that the node has already been built locally. 4 | # To ensure that run the command `cargo build --release -p basic-pow` 5 | 6 | # Copy the node into the image 7 | COPY ./target/release/basic-pow . 8 | 9 | # Open default ports. User is responsible for re-mapping these, using 10 | # host networking, or otherwise resolving their port-related needs. 11 | EXPOSE 30333 9933 9944 12 | 13 | ENTRYPOINT ["./basic-pow"] 14 | -------------------------------------------------------------------------------- /nodes/basic-pow/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 | -------------------------------------------------------------------------------- /nodes/basic-pow/src/chain_spec.rs: -------------------------------------------------------------------------------- 1 | use runtime::{ 2 | genesis::{account_id_from_seed, dev_genesis, testnet_genesis}, 3 | GenesisConfig, WASM_BINARY, 4 | }; 5 | use sp_core::sr25519; 6 | 7 | // Note this is the URL for the telemetry server 8 | //const STAGING_TELEMETRY_URL: &str = "wss://telemetry.polkadot.io/submit/"; 9 | 10 | /// Specialized `ChainSpec`. This is a specialization of the general Substrate `ChainSpec` type. 11 | pub type ChainSpec = sc_service::GenericChainSpec; 12 | 13 | pub fn dev_config() -> Result { 14 | let wasm_binary = WASM_BINARY.ok_or_else(|| "Development wasm not available".to_string())?; 15 | 16 | Ok(ChainSpec::from_genesis( 17 | "Development", 18 | "dev", 19 | sc_service::ChainType::Development, 20 | move || dev_genesis(wasm_binary), 21 | vec![], 22 | None, 23 | None, 24 | None, 25 | None, 26 | )) 27 | } 28 | 29 | pub fn local_testnet_config() -> Result { 30 | let wasm_binary = WASM_BINARY.ok_or_else(|| "Development wasm not available".to_string())?; 31 | 32 | Ok(ChainSpec::from_genesis( 33 | "Local Testnet", 34 | "local_testnet", 35 | sc_service::ChainType::Local, 36 | move || { 37 | testnet_genesis( 38 | wasm_binary, 39 | account_id_from_seed::("Alice"), 40 | vec![ 41 | account_id_from_seed::("Alice"), 42 | account_id_from_seed::("Bob"), 43 | account_id_from_seed::("Charlie"), 44 | account_id_from_seed::("Dave"), 45 | account_id_from_seed::("Eve"), 46 | account_id_from_seed::("Ferdie"), 47 | account_id_from_seed::("Alice//stash"), 48 | account_id_from_seed::("Bob//stash"), 49 | account_id_from_seed::("Charlie//stash"), 50 | account_id_from_seed::("Dave//stash"), 51 | account_id_from_seed::("Eve//stash"), 52 | account_id_from_seed::("Ferdie//stash"), 53 | ], 54 | ) 55 | }, 56 | vec![], 57 | None, 58 | None, 59 | None, 60 | None, 61 | )) 62 | } 63 | -------------------------------------------------------------------------------- /nodes/basic-pow/src/cli.rs: -------------------------------------------------------------------------------- 1 | use sc_cli::RunCmd; 2 | use structopt::StructOpt; 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 | /// Build a chain specification. 16 | BuildSpec(sc_cli::BuildSpecCmd), 17 | 18 | /// Validate blocks. 19 | CheckBlock(sc_cli::CheckBlockCmd), 20 | 21 | /// Export blocks. 22 | ExportBlocks(sc_cli::ExportBlocksCmd), 23 | 24 | /// Export the state of a given block into a chain spec. 25 | ExportState(sc_cli::ExportStateCmd), 26 | 27 | /// Import blocks. 28 | ImportBlocks(sc_cli::ImportBlocksCmd), 29 | 30 | /// Remove the whole chain. 31 | PurgeChain(sc_cli::PurgeChainCmd), 32 | 33 | /// Revert the chain to a previous state. 34 | Revert(sc_cli::RevertCmd), 35 | } 36 | -------------------------------------------------------------------------------- /nodes/basic-pow/src/command.rs: -------------------------------------------------------------------------------- 1 | use crate::chain_spec; 2 | use crate::cli::{Cli, Subcommand}; 3 | use crate::service; 4 | use sc_cli::{ChainSpec, Role, RuntimeVersion, SubstrateCli}; 5 | use sc_service::PartialComponents; 6 | 7 | impl SubstrateCli for Cli { 8 | fn impl_name() -> String { 9 | "Basic PoW Node".into() 10 | } 11 | 12 | fn impl_version() -> String { 13 | env!("SUBSTRATE_CLI_IMPL_VERSION").into() 14 | } 15 | 16 | fn description() -> String { 17 | env!("CARGO_PKG_DESCRIPTION").into() 18 | } 19 | 20 | fn author() -> String { 21 | env!("CARGO_PKG_AUTHORS").into() 22 | } 23 | 24 | fn support_url() -> String { 25 | "https://github.com/substrate-developer-hub/recipes/issues".into() 26 | } 27 | 28 | fn copyright_start_year() -> i32 { 29 | 2019 30 | } 31 | 32 | fn load_spec(&self, id: &str) -> Result, String> { 33 | Ok(match id { 34 | "dev" => Box::new(chain_spec::dev_config()?), 35 | "" | "local" => Box::new(chain_spec::local_testnet_config()?), 36 | path => Box::new(chain_spec::ChainSpec::from_json_file( 37 | std::path::PathBuf::from(path), 38 | )?), 39 | }) 40 | } 41 | 42 | fn native_runtime_version(_: &Box) -> &'static RuntimeVersion { 43 | &runtime::VERSION 44 | } 45 | } 46 | 47 | /// Parse and run command line arguments 48 | pub fn run() -> sc_cli::Result<()> { 49 | let cli = Cli::from_args(); 50 | 51 | match &cli.subcommand { 52 | Some(Subcommand::BuildSpec(cmd)) => { 53 | let runner = cli.create_runner(cmd)?; 54 | runner.sync_run(|config| cmd.run(config.chain_spec, config.network)) 55 | } 56 | Some(Subcommand::CheckBlock(cmd)) => { 57 | let runner = cli.create_runner(cmd)?; 58 | runner.async_run(|config| { 59 | let PartialComponents { 60 | client, 61 | task_manager, 62 | import_queue, 63 | .. 64 | } = service::new_partial(&config)?; 65 | Ok((cmd.run(client, import_queue), task_manager)) 66 | }) 67 | } 68 | Some(Subcommand::ExportBlocks(cmd)) => { 69 | let runner = cli.create_runner(cmd)?; 70 | runner.async_run(|config| { 71 | let PartialComponents { 72 | client, 73 | task_manager, 74 | .. 75 | } = service::new_partial(&config)?; 76 | Ok((cmd.run(client, config.database), task_manager)) 77 | }) 78 | } 79 | Some(Subcommand::ExportState(cmd)) => { 80 | let runner = cli.create_runner(cmd)?; 81 | runner.async_run(|config| { 82 | let PartialComponents { 83 | client, 84 | task_manager, 85 | .. 86 | } = service::new_partial(&config)?; 87 | Ok((cmd.run(client, config.chain_spec), task_manager)) 88 | }) 89 | } 90 | Some(Subcommand::ImportBlocks(cmd)) => { 91 | let runner = cli.create_runner(cmd)?; 92 | runner.async_run(|config| { 93 | let PartialComponents { 94 | client, 95 | task_manager, 96 | import_queue, 97 | .. 98 | } = service::new_partial(&config)?; 99 | Ok((cmd.run(client, import_queue), task_manager)) 100 | }) 101 | } 102 | Some(Subcommand::PurgeChain(cmd)) => { 103 | let runner = cli.create_runner(cmd)?; 104 | runner.sync_run(|config| cmd.run(config.database)) 105 | } 106 | Some(Subcommand::Revert(cmd)) => { 107 | let runner = cli.create_runner(cmd)?; 108 | runner.async_run(|config| { 109 | let PartialComponents { 110 | client, 111 | task_manager, 112 | backend, 113 | .. 114 | } = service::new_partial(&config)?; 115 | Ok((cmd.run(client, backend), task_manager)) 116 | }) 117 | } 118 | None => { 119 | let runner = cli.create_runner(&cli.run)?; 120 | runner.run_node_until_exit(|config| async move { 121 | match config.role { 122 | Role::Light => service::new_light(config), 123 | _ => service::new_full(config), 124 | } 125 | .map_err(sc_cli::Error::Service) 126 | }) 127 | } 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /nodes/basic-pow/src/main.rs: -------------------------------------------------------------------------------- 1 | //! Basic POW 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 | 10 | fn main() -> sc_cli::Result<()> { 11 | command::run() 12 | } 13 | -------------------------------------------------------------------------------- /nodes/hybrid-consensus/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "hybrid-consensus" 3 | version = "3.0.0" 4 | edition = "2018" 5 | authors = ['Substrate DevHub '] 6 | repository = 'https://github.com/substrate-developer-hub/recipes' 7 | description = 'A Substrate node with PoW authoring and PoA finality' 8 | license = "GPL-3.0-or-later" 9 | 10 | [[bin]] 11 | name = "hybrid-consensus" 12 | path = "src/main.rs" 13 | 14 | [dependencies] 15 | ctrlc = { version = "3.1.3", features = ["termination"] } 16 | derive_more = "0.15.0" 17 | exit-future = "0.2.0" 18 | futures = "0.3.1" 19 | futures01 = { package = "futures", version = "0.1.29" } 20 | log = "0.4.8" 21 | parking_lot = "0.9.0" 22 | structopt = "0.3.8" 23 | tokio = "0.1.22" 24 | trie-root = "0.15.2" 25 | 26 | # Substrate packages 27 | sc-basic-authorship = '0.9' 28 | sc-cli = '0.9' 29 | sc-client-api = '3.0' 30 | sc-consensus = '0.9' 31 | sc-consensus-pow = '0.9' 32 | sc-executor = '0.9' 33 | sc-finality-grandpa = '0.9' 34 | sc-network = '0.9' 35 | sc-service = '0.9' 36 | sc-transaction-pool = '3.0' 37 | sp-api = '3.0' 38 | sp-consensus = '0.9' 39 | sp-consensus-pow = '0.9' 40 | sp-core = '3.0' 41 | sp-finality-grandpa = '3.0' 42 | sp-inherents = '3.0' 43 | sp-io = '3.0' 44 | sp-runtime = '3.0' 45 | sp-timestamp = '3.0' 46 | sp-transaction-pool = '3.0' 47 | 48 | # local packages 49 | runtime = { package = "minimal-grandpa-runtime", path = "../../runtimes/minimal-grandpa-runtime"} 50 | sha3pow = { path = '../../consensus/sha3pow' } 51 | 52 | [build-dependencies] 53 | substrate-build-script-utils = '3.0' 54 | vergen = "3.0.4" 55 | -------------------------------------------------------------------------------- /nodes/hybrid-consensus/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM debian:stretch-slim 2 | 3 | # This dockerfile assumes that the node has already been built locally. 4 | # To ensure that run the command `cargo build --release -p hybrid-consensus` 5 | 6 | # Copy the node into the image 7 | COPY ./target/release/hybrid-consensus . 8 | 9 | # Open default ports. User is responsible for re-mapping these, using 10 | # host networking, or otherwise resolving their port-related needs. 11 | EXPOSE 30333 9933 9944 12 | 13 | ENTRYPOINT ["./hybrid-consensus"] 14 | -------------------------------------------------------------------------------- /nodes/hybrid-consensus/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 | -------------------------------------------------------------------------------- /nodes/hybrid-consensus/src/chain_spec.rs: -------------------------------------------------------------------------------- 1 | use runtime::{ 2 | genesis::{account_id_from_seed, authority_keys_from_seed, dev_genesis, testnet_genesis}, 3 | GenesisConfig, WASM_BINARY, 4 | }; 5 | use sp_core::sr25519; 6 | 7 | // Note this is the URL for the telemetry server 8 | //const STAGING_TELEMETRY_URL: &str = "wss://telemetry.polkadot.io/submit/"; 9 | 10 | /// Specialized `ChainSpec`. This is a specialization of the general Substrate ChainSpec type. 11 | pub type ChainSpec = sc_service::GenericChainSpec; 12 | 13 | /// Build a Development ChainSpec 14 | pub fn dev_config() -> Result { 15 | let wasm_binary = WASM_BINARY.ok_or_else(|| "Development wasm not available".to_string())?; 16 | 17 | Ok(ChainSpec::from_genesis( 18 | "Development", 19 | "dev", 20 | sc_service::ChainType::Development, 21 | move || dev_genesis(wasm_binary), 22 | vec![], 23 | None, 24 | None, 25 | None, 26 | None, 27 | )) 28 | } 29 | 30 | /// Build a Local Chainspec 31 | pub fn local_testnet_config() -> Result { 32 | let wasm_binary = WASM_BINARY.ok_or_else(|| "Development wasm not available".to_string())?; 33 | 34 | Ok(ChainSpec::from_genesis( 35 | "Local Testnet", 36 | "local_testnet", 37 | sc_service::ChainType::Local, 38 | move || { 39 | testnet_genesis( 40 | wasm_binary, 41 | vec![ 42 | authority_keys_from_seed("Alice"), 43 | authority_keys_from_seed("Bob"), 44 | ], 45 | account_id_from_seed::("Alice"), 46 | vec![ 47 | account_id_from_seed::("Alice"), 48 | account_id_from_seed::("Bob"), 49 | account_id_from_seed::("Charlie"), 50 | account_id_from_seed::("Dave"), 51 | account_id_from_seed::("Eve"), 52 | account_id_from_seed::("Ferdie"), 53 | account_id_from_seed::("Alice//stash"), 54 | account_id_from_seed::("Bob//stash"), 55 | account_id_from_seed::("Charlie//stash"), 56 | account_id_from_seed::("Dave//stash"), 57 | account_id_from_seed::("Eve//stash"), 58 | account_id_from_seed::("Ferdie//stash"), 59 | ], 60 | ) 61 | }, 62 | vec![], 63 | None, 64 | None, 65 | None, 66 | None, 67 | )) 68 | } 69 | -------------------------------------------------------------------------------- /nodes/hybrid-consensus/src/cli.rs: -------------------------------------------------------------------------------- 1 | use sc_cli::RunCmd; 2 | use structopt::StructOpt; 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 | /// Build a chain specification. 16 | BuildSpec(sc_cli::BuildSpecCmd), 17 | 18 | /// Validate blocks. 19 | CheckBlock(sc_cli::CheckBlockCmd), 20 | 21 | /// Export blocks. 22 | ExportBlocks(sc_cli::ExportBlocksCmd), 23 | 24 | /// Export the state of a given block into a chain spec. 25 | ExportState(sc_cli::ExportStateCmd), 26 | 27 | /// Import blocks. 28 | ImportBlocks(sc_cli::ImportBlocksCmd), 29 | 30 | /// Remove the whole chain. 31 | PurgeChain(sc_cli::PurgeChainCmd), 32 | 33 | /// Revert the chain to a previous state. 34 | Revert(sc_cli::RevertCmd), 35 | } 36 | -------------------------------------------------------------------------------- /nodes/hybrid-consensus/src/main.rs: -------------------------------------------------------------------------------- 1 | //! Hybrid Consensus CLI library. 2 | 3 | #![warn(missing_docs)] 4 | #![warn(unused_extern_crates)] 5 | 6 | mod chain_spec; 7 | #[macro_use] 8 | mod service; 9 | mod cli; 10 | mod command; 11 | 12 | fn main() -> sc_cli::Result<()> { 13 | command::run() 14 | } 15 | -------------------------------------------------------------------------------- /nodes/kitchen-node/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "kitchen-node" 3 | version = "3.0.0" 4 | edition = "2018" 5 | authors = ['Substrate DevHub '] 6 | repository = 'https://github.com/substrate-developer-hub/recipes' 7 | description = 'An instant-sealing Substrate node. Can be used with most recipe runtimes.' 8 | license = "GPL-3.0-or-later" 9 | 10 | [[bin]] 11 | name = "kitchen-node" 12 | path = "src/main.rs" 13 | 14 | [dependencies] 15 | derive_more = "0.15.0" 16 | futures = "0.3.1" 17 | structopt = "0.3.8" 18 | futures01 = { package = "futures", version = "0.1.29" } 19 | ctrlc = { version = "3.1.3", features = ["termination"] } 20 | log = "0.4.8" 21 | tokio = "0.1.22" 22 | exit-future = "0.2.0" 23 | parking_lot = "0.9.0" 24 | trie-root = "0.15.2" 25 | 26 | # Substrate packages 27 | sc-basic-authorship = '0.9' 28 | sc-cli = '0.9' 29 | sc-client-api = '3.0' 30 | sc-consensus = '0.9' 31 | sc-consensus-manual-seal = '0.9' 32 | sc-executor = '0.9' 33 | sc-network = '0.9' 34 | sc-service = '0.9' 35 | sc-transaction-pool = '3.0' 36 | sp-api = '3.0' 37 | sp-consensus = '0.9' 38 | sp-core = '3.0' 39 | sp-inherents = '3.0' 40 | sp-io = '3.0' 41 | sp-keystore = '0.9' 42 | sp-runtime = '3.0' 43 | sp-timestamp = '3.0' 44 | sp-transaction-pool = '3.0' 45 | 46 | # local packages 47 | 48 | # This node is compatible with any of the runtimes below 49 | # --- 50 | # Common runtime configured with most Recipes pallets. 51 | runtime = { package = "super-runtime", path = "../../runtimes/super-runtime" } 52 | 53 | # Runtime with custom weight and fee calculation. 54 | # runtime = { package = "weight-fee-runtime", path = "../../runtimes/weight-fee-runtime"} 55 | 56 | # Runtime with off-chain worker enabled. 57 | # To use this runtime, compile the node with `ocw` feature enabled, 58 | # `cargo build --release --features ocw`. 59 | # runtime = { package = "ocw-runtime", path = "../../runtimes/ocw-runtime" } 60 | 61 | # Runtime with custom runtime-api (custom API only used in rpc-node) 62 | # runtime = { package = "api-runtime", path = "../../runtimes/api-runtime" } 63 | # --- 64 | 65 | [build-dependencies] 66 | substrate-build-script-utils = '3.0' 67 | vergen = "3.0.4" 68 | 69 | [features] 70 | ocw = [] 71 | -------------------------------------------------------------------------------- /nodes/kitchen-node/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM debian:stretch-slim 2 | 3 | # This dockerfile assumes that the node has already been built locally. 4 | # To ensure that run the command `cargo build --release -p kitchen-node` 5 | 6 | # Copy the node into the image 7 | COPY ./target/release/kitchen-node . 8 | 9 | # Open default ports. User is responsible for re-mapping these, using 10 | # host networking, or otherwise resolving their port-related needs. 11 | EXPOSE 30333 9933 9944 12 | 13 | ENTRYPOINT ["./kitchen-node"] 14 | -------------------------------------------------------------------------------- /nodes/kitchen-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 | -------------------------------------------------------------------------------- /nodes/kitchen-node/src/chain_spec.rs: -------------------------------------------------------------------------------- 1 | use runtime::{ 2 | genesis::{account_id_from_seed, dev_genesis, testnet_genesis}, 3 | GenesisConfig, WASM_BINARY, 4 | }; 5 | use sp_core::sr25519; 6 | 7 | // Note this is the URL for the telemetry server 8 | //const STAGING_TELEMETRY_URL: &str = "wss://telemetry.polkadot.io/submit/"; 9 | 10 | /// Specialized `ChainSpec`. This is a specialization of the general Substrate ChainSpec type. 11 | pub type ChainSpec = sc_service::GenericChainSpec; 12 | 13 | /// Build a Development ChainSpec 14 | pub fn dev_config() -> Result { 15 | let wasm_binary = WASM_BINARY.ok_or_else(|| "Development wasm not available".to_string())?; 16 | 17 | Ok(ChainSpec::from_genesis( 18 | "Development", 19 | "dev", 20 | sc_service::ChainType::Development, 21 | move || dev_genesis(wasm_binary), 22 | vec![], 23 | None, 24 | None, 25 | None, 26 | None, 27 | )) 28 | } 29 | 30 | /// Build a Local Chainspec 31 | pub fn local_testnet_config() -> Result { 32 | let wasm_binary = WASM_BINARY.ok_or_else(|| "Development wasm not available".to_string())?; 33 | 34 | Ok(ChainSpec::from_genesis( 35 | "Local Testnet", 36 | "local_testnet", 37 | sc_service::ChainType::Local, 38 | move || { 39 | testnet_genesis( 40 | wasm_binary, 41 | account_id_from_seed::("Alice"), 42 | vec![ 43 | account_id_from_seed::("Alice"), 44 | account_id_from_seed::("Bob"), 45 | account_id_from_seed::("Charlie"), 46 | account_id_from_seed::("Dave"), 47 | account_id_from_seed::("Eve"), 48 | account_id_from_seed::("Ferdie"), 49 | account_id_from_seed::("Alice//stash"), 50 | account_id_from_seed::("Bob//stash"), 51 | account_id_from_seed::("Charlie//stash"), 52 | account_id_from_seed::("Dave//stash"), 53 | account_id_from_seed::("Eve//stash"), 54 | account_id_from_seed::("Ferdie//stash"), 55 | ], 56 | ) 57 | }, 58 | vec![], 59 | None, 60 | None, 61 | None, 62 | None, 63 | )) 64 | } 65 | -------------------------------------------------------------------------------- /nodes/kitchen-node/src/cli.rs: -------------------------------------------------------------------------------- 1 | use sc_cli::RunCmd; 2 | use structopt::StructOpt; 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 | /// Build a chain specification. 16 | BuildSpec(sc_cli::BuildSpecCmd), 17 | 18 | /// Validate blocks. 19 | CheckBlock(sc_cli::CheckBlockCmd), 20 | 21 | /// Export blocks. 22 | ExportBlocks(sc_cli::ExportBlocksCmd), 23 | 24 | /// Export the state of a given block into a chain spec. 25 | ExportState(sc_cli::ExportStateCmd), 26 | 27 | /// Import blocks. 28 | ImportBlocks(sc_cli::ImportBlocksCmd), 29 | 30 | /// Remove the whole chain. 31 | PurgeChain(sc_cli::PurgeChainCmd), 32 | 33 | /// Revert the chain to a previous state. 34 | Revert(sc_cli::RevertCmd), 35 | } 36 | -------------------------------------------------------------------------------- /nodes/kitchen-node/src/command.rs: -------------------------------------------------------------------------------- 1 | use crate::chain_spec; 2 | use crate::cli::{Cli, Subcommand}; 3 | use crate::service; 4 | use sc_cli::{ChainSpec, Role, RuntimeVersion, SubstrateCli}; 5 | use sc_service::PartialComponents; 6 | 7 | impl SubstrateCli for Cli { 8 | fn impl_name() -> String { 9 | "Kitchen Node".into() 10 | } 11 | 12 | fn impl_version() -> String { 13 | env!("SUBSTRATE_CLI_IMPL_VERSION").into() 14 | } 15 | 16 | fn description() -> String { 17 | env!("CARGO_PKG_DESCRIPTION").into() 18 | } 19 | 20 | fn author() -> String { 21 | env!("CARGO_PKG_AUTHORS").into() 22 | } 23 | 24 | fn support_url() -> String { 25 | "https://github.com/substrate-developer-hub/recipes/issues".into() 26 | } 27 | 28 | fn copyright_start_year() -> i32 { 29 | 2019 30 | } 31 | 32 | fn load_spec(&self, id: &str) -> Result, String> { 33 | Ok(match id { 34 | "dev" => Box::new(chain_spec::dev_config()?), 35 | "" | "local" => Box::new(chain_spec::local_testnet_config()?), 36 | path => Box::new(chain_spec::ChainSpec::from_json_file( 37 | std::path::PathBuf::from(path), 38 | )?), 39 | }) 40 | } 41 | 42 | fn native_runtime_version(_: &Box) -> &'static RuntimeVersion { 43 | &runtime::VERSION 44 | } 45 | } 46 | 47 | /// Parse and run command line arguments 48 | pub fn run() -> sc_cli::Result<()> { 49 | let cli = Cli::from_args(); 50 | 51 | match &cli.subcommand { 52 | Some(Subcommand::BuildSpec(cmd)) => { 53 | let runner = cli.create_runner(cmd)?; 54 | runner.sync_run(|config| cmd.run(config.chain_spec, config.network)) 55 | } 56 | Some(Subcommand::CheckBlock(cmd)) => { 57 | let runner = cli.create_runner(cmd)?; 58 | runner.async_run(|config| { 59 | let PartialComponents { 60 | client, 61 | task_manager, 62 | import_queue, 63 | .. 64 | } = service::new_partial(&config)?; 65 | Ok((cmd.run(client, import_queue), task_manager)) 66 | }) 67 | } 68 | Some(Subcommand::ExportBlocks(cmd)) => { 69 | let runner = cli.create_runner(cmd)?; 70 | runner.async_run(|config| { 71 | let PartialComponents { 72 | client, 73 | task_manager, 74 | .. 75 | } = service::new_partial(&config)?; 76 | Ok((cmd.run(client, config.database), task_manager)) 77 | }) 78 | } 79 | Some(Subcommand::ExportState(cmd)) => { 80 | let runner = cli.create_runner(cmd)?; 81 | runner.async_run(|config| { 82 | let PartialComponents { 83 | client, 84 | task_manager, 85 | .. 86 | } = service::new_partial(&config)?; 87 | Ok((cmd.run(client, config.chain_spec), task_manager)) 88 | }) 89 | } 90 | Some(Subcommand::ImportBlocks(cmd)) => { 91 | let runner = cli.create_runner(cmd)?; 92 | runner.async_run(|config| { 93 | let PartialComponents { 94 | client, 95 | task_manager, 96 | import_queue, 97 | .. 98 | } = service::new_partial(&config)?; 99 | Ok((cmd.run(client, import_queue), task_manager)) 100 | }) 101 | } 102 | Some(Subcommand::PurgeChain(cmd)) => { 103 | let runner = cli.create_runner(cmd)?; 104 | runner.sync_run(|config| cmd.run(config.database)) 105 | } 106 | Some(Subcommand::Revert(cmd)) => { 107 | let runner = cli.create_runner(cmd)?; 108 | runner.async_run(|config| { 109 | let PartialComponents { 110 | client, 111 | task_manager, 112 | backend, 113 | .. 114 | } = service::new_partial(&config)?; 115 | Ok((cmd.run(client, backend), task_manager)) 116 | }) 117 | } 118 | None => { 119 | let runner = cli.create_runner(&cli.run)?; 120 | runner.run_node_until_exit(|config| async move { 121 | match config.role { 122 | Role::Light => service::new_light(config), 123 | _ => service::new_full(config), 124 | } 125 | .map_err(sc_cli::Error::Service) 126 | }) 127 | } 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /nodes/kitchen-node/src/main.rs: -------------------------------------------------------------------------------- 1 | //! Kitchen Node CLI library. 2 | 3 | #![warn(missing_docs)] 4 | #![warn(unused_extern_crates)] 5 | 6 | mod chain_spec; 7 | #[macro_use] 8 | mod service; 9 | mod cli; 10 | mod command; 11 | 12 | fn main() -> sc_cli::Result<()> { 13 | command::run() 14 | } 15 | -------------------------------------------------------------------------------- /nodes/manual-seal/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM debian:stretch-slim 2 | 3 | # This dockerfile assumes that the node has already been built locally. 4 | # To ensure that run the command `cargo build --release -p manual-seal` 5 | 6 | # Copy the node into the image 7 | COPY ./target/release/manual-seal . 8 | 9 | # Open default ports. User is responsible for re-mapping these, using 10 | # host networking, or otherwise resolving their port-related needs. 11 | EXPOSE 30333 9933 9944 12 | 13 | ENTRYPOINT ["./manual-seal"] 14 | -------------------------------------------------------------------------------- /nodes/rpc-node/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = 'rpc-node' 3 | version = "3.0.0" 4 | edition = '2018' 5 | authors = ['Substrate DevHub '] 6 | repository = 'https://github.com/substrate-developer-hub/recipes' 7 | description = "A Substrate node that demonstrates a custom RPC endpoint" 8 | build = 'build.rs' 9 | license = "GPL-3.0-or-later" 10 | 11 | [[bin]] 12 | name = 'rpc-node' 13 | path = 'src/main.rs' 14 | 15 | [dependencies] 16 | ctrlc = { features = ['termination'], version = '3.1.3' } 17 | futures = '0.3.1' 18 | futures01 = { package = 'futures', version = '0.1.29'} 19 | jsonrpc-core = "15.0" 20 | jsonrpc-core-client = "15.0" 21 | jsonrpc-derive = "15.0" 22 | log = '0.4.8' 23 | parking_lot = '0.9' 24 | structopt = "0.3.8" 25 | tokio = '0.1.22' 26 | trie-root = '0.15.2' 27 | 28 | # Substrate packages 29 | sc-basic-authorship = '0.9' 30 | sc-cli = '0.9' 31 | sc-client-api = '3.0' 32 | sc-consensus = '0.9' 33 | sc-consensus-manual-seal = '0.9' 34 | sc-executor = '0.9' 35 | sc-network = '0.9' 36 | sc-rpc = '3.0' 37 | sc-rpc-api = '0.9' 38 | sc-service = '0.9' 39 | sc-transaction-pool = '3.0' 40 | sp-api = '3.0' 41 | sp-block-builder = '3.0' 42 | sp-blockchain = '3.0' 43 | sp-consensus = '0.9' 44 | sp-core = '3.0' 45 | sp-inherents = '3.0' 46 | sp-io = '3.0' 47 | sp-runtime = '3.0' 48 | sp-timestamp = '3.0' 49 | sp-transaction-pool = '3.0' 50 | 51 | # local packages 52 | 53 | # RPC Node only works with Runtime's that provide the sum-storage-runtime-api 54 | # That means it only works with the api-runtime 55 | runtime = { package = "api-runtime", path = "../../runtimes/api-runtime" } 56 | sum-storage-rpc = { path = "../../pallets/sum-storage/rpc" } 57 | sum-storage-runtime-api = { path = "../../pallets/sum-storage/runtime-api" } 58 | 59 | [build-dependencies] 60 | substrate-build-script-utils = '3.0' 61 | vergen = '3.0.4' 62 | -------------------------------------------------------------------------------- /nodes/rpc-node/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM debian:stretch-slim 2 | 3 | # This dockerfile assumes that the node has already been built locally. 4 | # To ensure that run the command `cargo build --release -p rpc-node` 5 | 6 | # Copy the node into the image 7 | COPY ./target/release/rpc-node . 8 | 9 | # Open default ports. User is responsible for re-mapping these, using 10 | # host networking, or otherwise resolving their port-related needs. 11 | EXPOSE 30333 9933 9944 12 | 13 | ENTRYPOINT ["./rpc-node"] 14 | -------------------------------------------------------------------------------- /nodes/rpc-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 | -------------------------------------------------------------------------------- /nodes/rpc-node/js/index.js: -------------------------------------------------------------------------------- 1 | // A demonstration of interacting with custom RPCs using Polkadot js API 2 | 3 | const { ApiPromise, WsProvider } = require('@polkadot/api'); 4 | const { readFileSync } = require('fs'); 5 | 6 | // Construct parameters for API instance 7 | const wsProvider = new WsProvider('ws://localhost:9944'); 8 | const types = JSON.parse(readFileSync('../../../runtimes/super-runtime/types.json', 'utf8')); 9 | const rpc = { 10 | silly: { 11 | seven: { 12 | description: "Always returns 7", 13 | params: [], 14 | type: "u32", 15 | }, 16 | double: { 17 | description: "Doubles the parameter", 18 | params: [ 19 | { 20 | name: "val", 21 | type: "u32", 22 | } 23 | ], 24 | type: "u32", 25 | } 26 | }, 27 | sumStorage: { 28 | getSum: { 29 | description: "Gets the sum of the two storage values in sum-storage pallet via a runtime api.", 30 | params: [], 31 | type: "u32", 32 | } 33 | } 34 | } 35 | 36 | async function main() { 37 | // Construct the actual api 38 | const api = await ApiPromise.create({ 39 | provider: wsProvider, 40 | types, 41 | rpc, 42 | }); 43 | 44 | // Query the custom SillyRpc 45 | let silly7 = await api.rpc.silly.seven(); 46 | let silly14 = await api.rpc.silly.double(7); 47 | console.log(`The value from the silly_seven is ${silly7}\n`); 48 | console.log(`The double of 7 according to silly_double is ${silly14}\n`); 49 | 50 | // Query raw storage values, the oldschool way 51 | const v1 = ( await api.query.sumStorage.thing1() ).toNumber(); 52 | const v2 = ( await api.query.sumStorage.thing2() ).toNumber(); 53 | console.log(`The individual storage values are ${v1}, and ${v2}.`); 54 | console.log(`The sum calculated in javascript is ${v1 + v2}\n`); 55 | 56 | // Query the custom RPC that uses the runtimeAPI 57 | let directSum = ( await api.rpc.sumStorage.getSum() ).toNumber(); 58 | console.log(`The sum queried directly from the RPC is ${directSum}`); 59 | } 60 | 61 | main().catch(console.error).finally(() => process.exit()); 62 | -------------------------------------------------------------------------------- /nodes/rpc-node/js/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sum-storage", 3 | "version": "1.0.0", 4 | "description": "Example of using Polkadot-js API to query custom rpc", 5 | "main": "index.js", 6 | "author": "Joshy Orndorff", 7 | "license": "GPL-3.0-or-later", 8 | "private": false, 9 | "dependencies": { 10 | "@polkadot/api": "^4.4.1" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /nodes/rpc-node/src/chain_spec.rs: -------------------------------------------------------------------------------- 1 | use runtime::{ 2 | genesis::{account_id_from_seed, dev_genesis, testnet_genesis}, 3 | GenesisConfig, WASM_BINARY, 4 | }; 5 | use sp_core::sr25519; 6 | 7 | // Note this is the URL for the telemetry server 8 | //const STAGING_TELEMETRY_URL: &str = "wss://telemetry.polkadot.io/submit/"; 9 | 10 | /// Specialized `ChainSpec`. This is a specialization of the general Substrate ChainSpec type. 11 | pub type ChainSpec = sc_service::GenericChainSpec; 12 | 13 | pub fn dev_config() -> Result { 14 | let wasm_binary = WASM_BINARY.ok_or_else(|| "Development wasm not available".to_string())?; 15 | 16 | Ok(ChainSpec::from_genesis( 17 | "Development", 18 | "dev", 19 | sc_service::ChainType::Development, 20 | move || dev_genesis(wasm_binary), 21 | vec![], 22 | None, 23 | None, 24 | None, 25 | None, 26 | )) 27 | } 28 | 29 | pub fn local_testnet_config() -> Result { 30 | let wasm_binary = WASM_BINARY.ok_or_else(|| "Development wasm not available".to_string())?; 31 | 32 | Ok(ChainSpec::from_genesis( 33 | "Local Testnet", 34 | "local_testnet", 35 | sc_service::ChainType::Local, 36 | move || { 37 | testnet_genesis( 38 | wasm_binary, 39 | account_id_from_seed::("Alice"), 40 | vec![ 41 | account_id_from_seed::("Alice"), 42 | account_id_from_seed::("Bob"), 43 | account_id_from_seed::("Charlie"), 44 | account_id_from_seed::("Dave"), 45 | account_id_from_seed::("Eve"), 46 | account_id_from_seed::("Ferdie"), 47 | account_id_from_seed::("Alice//stash"), 48 | account_id_from_seed::("Bob//stash"), 49 | account_id_from_seed::("Charlie//stash"), 50 | account_id_from_seed::("Dave//stash"), 51 | account_id_from_seed::("Eve//stash"), 52 | account_id_from_seed::("Ferdie//stash"), 53 | ], 54 | ) 55 | }, 56 | vec![], 57 | None, 58 | None, 59 | None, 60 | None, 61 | )) 62 | } 63 | -------------------------------------------------------------------------------- /nodes/rpc-node/src/cli.rs: -------------------------------------------------------------------------------- 1 | use sc_cli::RunCmd; 2 | use structopt::StructOpt; 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 | /// Build a chain specification. 16 | BuildSpec(sc_cli::BuildSpecCmd), 17 | 18 | /// Validate blocks. 19 | CheckBlock(sc_cli::CheckBlockCmd), 20 | 21 | /// Export blocks. 22 | ExportBlocks(sc_cli::ExportBlocksCmd), 23 | 24 | /// Export the state of a given block into a chain spec. 25 | ExportState(sc_cli::ExportStateCmd), 26 | 27 | /// Import blocks. 28 | ImportBlocks(sc_cli::ImportBlocksCmd), 29 | 30 | /// Remove the whole chain. 31 | PurgeChain(sc_cli::PurgeChainCmd), 32 | 33 | /// Revert the chain to a previous state. 34 | Revert(sc_cli::RevertCmd), 35 | } 36 | -------------------------------------------------------------------------------- /nodes/rpc-node/src/command.rs: -------------------------------------------------------------------------------- 1 | use crate::chain_spec; 2 | use crate::cli::{Cli, Subcommand}; 3 | use crate::service; 4 | use sc_cli::{ChainSpec, Role, RuntimeVersion, SubstrateCli}; 5 | use sc_service::PartialComponents; 6 | 7 | impl SubstrateCli for Cli { 8 | fn impl_name() -> String { 9 | "RPC Node".into() 10 | } 11 | 12 | fn impl_version() -> String { 13 | env!("SUBSTRATE_CLI_IMPL_VERSION").into() 14 | } 15 | 16 | fn description() -> String { 17 | env!("CARGO_PKG_DESCRIPTION").into() 18 | } 19 | 20 | fn author() -> String { 21 | env!("CARGO_PKG_AUTHORS").into() 22 | } 23 | 24 | fn support_url() -> String { 25 | "https://github.com/substrate-developer-hub/recipes/issues".into() 26 | } 27 | 28 | fn copyright_start_year() -> i32 { 29 | 2019 30 | } 31 | 32 | fn load_spec(&self, id: &str) -> Result, String> { 33 | Ok(match id { 34 | "dev" => Box::new(chain_spec::dev_config()?), 35 | "" | "local" => Box::new(chain_spec::local_testnet_config()?), 36 | path => Box::new(chain_spec::ChainSpec::from_json_file( 37 | std::path::PathBuf::from(path), 38 | )?), 39 | }) 40 | } 41 | 42 | fn native_runtime_version(_: &Box) -> &'static RuntimeVersion { 43 | &runtime::VERSION 44 | } 45 | } 46 | 47 | /// Parse and run command line arguments 48 | pub fn run() -> sc_cli::Result<()> { 49 | let cli = Cli::from_args(); 50 | 51 | match &cli.subcommand { 52 | Some(Subcommand::BuildSpec(cmd)) => { 53 | let runner = cli.create_runner(cmd)?; 54 | runner.sync_run(|config| cmd.run(config.chain_spec, config.network)) 55 | } 56 | Some(Subcommand::CheckBlock(cmd)) => { 57 | let runner = cli.create_runner(cmd)?; 58 | runner.async_run(|config| { 59 | let PartialComponents { 60 | client, 61 | task_manager, 62 | import_queue, 63 | .. 64 | } = service::new_partial(&config)?; 65 | Ok((cmd.run(client, import_queue), task_manager)) 66 | }) 67 | } 68 | Some(Subcommand::ExportBlocks(cmd)) => { 69 | let runner = cli.create_runner(cmd)?; 70 | runner.async_run(|config| { 71 | let PartialComponents { 72 | client, 73 | task_manager, 74 | .. 75 | } = service::new_partial(&config)?; 76 | Ok((cmd.run(client, config.database), task_manager)) 77 | }) 78 | } 79 | Some(Subcommand::ExportState(cmd)) => { 80 | let runner = cli.create_runner(cmd)?; 81 | runner.async_run(|config| { 82 | let PartialComponents { 83 | client, 84 | task_manager, 85 | .. 86 | } = service::new_partial(&config)?; 87 | Ok((cmd.run(client, config.chain_spec), task_manager)) 88 | }) 89 | } 90 | Some(Subcommand::ImportBlocks(cmd)) => { 91 | let runner = cli.create_runner(cmd)?; 92 | runner.async_run(|config| { 93 | let PartialComponents { 94 | client, 95 | task_manager, 96 | import_queue, 97 | .. 98 | } = service::new_partial(&config)?; 99 | Ok((cmd.run(client, import_queue), task_manager)) 100 | }) 101 | } 102 | Some(Subcommand::PurgeChain(cmd)) => { 103 | let runner = cli.create_runner(cmd)?; 104 | runner.sync_run(|config| cmd.run(config.database)) 105 | } 106 | Some(Subcommand::Revert(cmd)) => { 107 | let runner = cli.create_runner(cmd)?; 108 | runner.async_run(|config| { 109 | let PartialComponents { 110 | client, 111 | task_manager, 112 | backend, 113 | .. 114 | } = service::new_partial(&config)?; 115 | Ok((cmd.run(client, backend), task_manager)) 116 | }) 117 | } 118 | None => { 119 | let runner = cli.create_runner(&cli.run)?; 120 | runner.run_node_until_exit(|config| async move { 121 | match config.role { 122 | Role::Light => service::new_light(config), 123 | _ => service::new_full(config), 124 | } 125 | .map_err(sc_cli::Error::Service) 126 | }) 127 | } 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /nodes/rpc-node/src/main.rs: -------------------------------------------------------------------------------- 1 | //! RPC Node Template CLI library. 2 | #![warn(missing_docs)] 3 | #![warn(unused_extern_crates)] 4 | 5 | mod chain_spec; 6 | #[macro_use] 7 | mod service; 8 | mod cli; 9 | mod command; 10 | mod rpc; 11 | mod silly_rpc; 12 | 13 | fn main() -> sc_cli::Result<()> { 14 | command::run() 15 | } 16 | -------------------------------------------------------------------------------- /nodes/rpc-node/src/rpc.rs: -------------------------------------------------------------------------------- 1 | #![warn(missing_docs)] 2 | 3 | use std::sync::Arc; 4 | 5 | use futures::channel::mpsc::Sender; 6 | use runtime::{opaque::Block, Hash}; 7 | use sc_consensus_manual_seal::{ 8 | rpc::{ManualSeal, ManualSealApi}, 9 | EngineCommand, 10 | }; 11 | pub use sc_rpc_api::DenyUnsafe; 12 | use sp_api::ProvideRuntimeApi; 13 | use sp_block_builder::BlockBuilder; 14 | use sp_blockchain::{Error as BlockChainError, HeaderBackend, HeaderMetadata}; 15 | use sp_transaction_pool::TransactionPool; 16 | 17 | /// Full client dependencies. 18 | pub struct FullDeps { 19 | /// The client instance to use. 20 | pub client: Arc, 21 | /// Transaction pool instance. 22 | pub pool: Arc

, 23 | /// Whether to deny unsafe calls 24 | pub deny_unsafe: DenyUnsafe, 25 | /// A command stream to send authoring commands to manual seal consensus engine 26 | pub command_sink: Sender>, 27 | } 28 | 29 | /// Instantiate all full RPC extensions. 30 | pub fn create_full(deps: FullDeps) -> jsonrpc_core::IoHandler 31 | where 32 | C: ProvideRuntimeApi, 33 | C: HeaderBackend + HeaderMetadata + 'static, 34 | C: Send + Sync + 'static, 35 | C::Api: BlockBuilder, 36 | C::Api: sum_storage_runtime_api::SumStorageApi, 37 | P: TransactionPool + 'static, 38 | { 39 | let mut io = jsonrpc_core::IoHandler::default(); 40 | let FullDeps { 41 | command_sink, 42 | client, 43 | .. 44 | } = deps; 45 | 46 | // Add a silly RPC that returns constant values 47 | io.extend_with(crate::silly_rpc::SillyRpc::to_delegate( 48 | crate::silly_rpc::Silly {}, 49 | )); 50 | 51 | // Add a second RPC extension 52 | // Because this one calls a Runtime API it needs a reference to the client. 53 | io.extend_with(sum_storage_rpc::SumStorageApi::to_delegate( 54 | sum_storage_rpc::SumStorage::new(client), 55 | )); 56 | 57 | // The final RPC extension receives commands for the manual seal consensus engine. 58 | io.extend_with( 59 | // We provide the rpc handler with the sending end of the channel to allow the rpc 60 | // send EngineCommands to the background block authorship task. 61 | ManualSealApi::to_delegate(ManualSeal::new(command_sink)), 62 | ); 63 | 64 | io 65 | } 66 | -------------------------------------------------------------------------------- /nodes/rpc-node/src/silly_rpc.rs: -------------------------------------------------------------------------------- 1 | use jsonrpc_core::Result; 2 | use jsonrpc_derive::rpc; 3 | 4 | #[rpc] 5 | pub trait SillyRpc { 6 | #[rpc(name = "silly_seven")] 7 | fn silly_7(&self) -> Result; 8 | 9 | #[rpc(name = "silly_double")] 10 | fn silly_double(&self, val: u64) -> Result; 11 | } 12 | 13 | /// A struct that implements the `SillyRpc` 14 | pub struct Silly; 15 | 16 | impl SillyRpc for Silly { 17 | fn silly_7(&self) -> Result { 18 | Ok(7) 19 | } 20 | 21 | fn silly_double(&self, val: u64) -> Result { 22 | Ok(2 * val) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /pallets/basic-token/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "basic-token" 3 | version = "3.0.0" 4 | edition = "2018" 5 | authors = ['Substrate DevHub '] 6 | repository = 'https://github.com/substrate-developer-hub/recipes' 7 | description = "A Pallet that implements a basic account-based cryptocurrency" 8 | license = "GPL-3.0-or-later" 9 | 10 | [dependencies] 11 | parity-scale-codec = { version = "2.0", features = ["derive"], default-features = false } 12 | 13 | # Substrate packages 14 | frame-support = { version = '3.0', default-features = false } 15 | frame-system = { version = '3.0', default-features = false } 16 | 17 | [dev-dependencies] 18 | serde = '1.0' 19 | 20 | # Substrate packages 21 | sp-core = '3.0' 22 | sp-io = '3.0' 23 | sp-runtime = '3.0' 24 | 25 | [features] 26 | default = ['std'] 27 | std = [ 28 | 'frame-support/std', 29 | 'frame-system/std', 30 | 'parity-scale-codec/std', 31 | ] 32 | -------------------------------------------------------------------------------- /pallets/basic-token/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![cfg_attr(not(feature = "std"), no_std)] 2 | #![allow(clippy::unused_unit)] 3 | 4 | //! Simple Token Transfer 5 | //! 1. set total supply 6 | //! 2. establish ownership upon configuration of circulating tokens 7 | //! 3. coordinate token transfers with the runtime functions 8 | 9 | pub use pallet::*; 10 | 11 | #[cfg(test)] 12 | mod tests; 13 | 14 | #[frame_support::pallet] 15 | pub mod pallet { 16 | use frame_support::{dispatch::DispatchResultWithPostInfo, pallet_prelude::*}; 17 | use frame_system::pallet_prelude::*; 18 | 19 | #[pallet::config] 20 | pub trait Config: frame_system::Config { 21 | /// The overarching event type. 22 | type Event: From> + IsType<::Event>; 23 | } 24 | 25 | #[pallet::event] 26 | #[pallet::metadata(T::AccountId = "AccountId")] 27 | #[pallet::generate_deposit(pub (super) fn deposit_event)] 28 | pub enum Event { 29 | /// Token was initialized by user 30 | Initialized(T::AccountId), 31 | /// Tokens successfully transferred between users 32 | Transfer(T::AccountId, T::AccountId, u64), // (from, to, value) 33 | } 34 | 35 | #[pallet::storage] 36 | #[pallet::getter(fn get_balance)] 37 | pub(super) type Balances = 38 | StorageMap<_, Blake2_128Concat, T::AccountId, u64, ValueQuery>; 39 | 40 | #[pallet::type_value] 41 | pub(super) fn TotalSupplyDefaultValue() -> u64 { 42 | 21000000 43 | } 44 | 45 | #[pallet::storage] 46 | #[pallet::getter(fn total_supply)] 47 | pub(super) type TotalSupply = 48 | StorageValue<_, u64, ValueQuery, TotalSupplyDefaultValue>; 49 | 50 | #[pallet::storage] 51 | #[pallet::getter(fn is_init)] 52 | pub(super) type Init = StorageValue<_, bool, ValueQuery>; 53 | 54 | #[pallet::pallet] 55 | #[pallet::generate_store(pub (super) trait Store)] 56 | pub struct Pallet(PhantomData); 57 | 58 | #[pallet::hooks] 59 | impl Hooks> for Pallet {} 60 | 61 | #[pallet::error] 62 | pub enum Error { 63 | /// Attempted to initialize the token after it had already been initialized. 64 | AlreadyInitialized, 65 | /// Attempted to transfer more funds than were available 66 | InsufficientFunds, 67 | } 68 | 69 | #[pallet::call] 70 | impl Pallet { 71 | /// Initialize the token 72 | /// transfers the total_supply amout to the caller 73 | #[pallet::weight(10_000)] 74 | pub fn init(_origin: OriginFor) -> DispatchResultWithPostInfo { 75 | let sender = ensure_signed(_origin)?; 76 | ensure!(!Self::is_init(), >::AlreadyInitialized); 77 | 78 | >::insert(sender, Self::total_supply()); 79 | 80 | Init::::put(true); 81 | Ok(().into()) 82 | } 83 | 84 | /// Transfer tokens from one account to another 85 | #[pallet::weight(10_000)] 86 | pub fn transfer( 87 | _origin: OriginFor, 88 | to: T::AccountId, 89 | value: u64, 90 | ) -> DispatchResultWithPostInfo { 91 | let sender = ensure_signed(_origin)?; 92 | let sender_balance = Self::get_balance(&sender); 93 | let receiver_balance = Self::get_balance(&to); 94 | 95 | // Calculate new balances 96 | let updated_from_balance = sender_balance 97 | .checked_sub(value) 98 | .ok_or(>::InsufficientFunds)?; 99 | let updated_to_balance = receiver_balance 100 | .checked_add(value) 101 | .expect("Entire supply fits in u64; qed"); 102 | 103 | // Write new balances to storage 104 | >::insert(&sender, updated_from_balance); 105 | >::insert(&to, updated_to_balance); 106 | 107 | Self::deposit_event(Event::Transfer(sender, to, value)); 108 | Ok(().into()) 109 | } 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /pallets/basic-token/src/tests.rs: -------------------------------------------------------------------------------- 1 | use crate::{self as basic_token, Config, Error}; 2 | use frame_support::{assert_noop, assert_ok, construct_runtime, parameter_types}; 3 | use frame_system as system; 4 | use sp_core::H256; 5 | use sp_io::TestExternalities; 6 | use sp_runtime::{ 7 | testing::Header, 8 | traits::{BlakeTwo256, IdentityLookup}, 9 | }; 10 | 11 | type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; 12 | type Block = frame_system::mocking::MockBlock; 13 | 14 | construct_runtime!( 15 | pub enum TestRuntime where 16 | Block = Block, 17 | NodeBlock = Block, 18 | UncheckedExtrinsic = UncheckedExtrinsic, 19 | { 20 | System: frame_system::{Module, Call, Config, Storage, Event}, 21 | BasicToken: basic_token::{Module, Call, Storage, Event}, 22 | } 23 | ); 24 | 25 | parameter_types! { 26 | pub const BlockHashCount: u64 = 250; 27 | pub BlockWeights: frame_system::limits::BlockWeights = 28 | frame_system::limits::BlockWeights::simple_max(1024); 29 | } 30 | impl frame_system::Config for TestRuntime { 31 | type BaseCallFilter = (); 32 | type BlockWeights = (); 33 | type BlockLength = (); 34 | type Origin = Origin; 35 | type Index = u64; 36 | type Call = Call; 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 = (); 44 | type BlockHashCount = BlockHashCount; 45 | type DbWeight = (); 46 | type Version = (); 47 | type PalletInfo = PalletInfo; 48 | type AccountData = (); 49 | type OnNewAccount = (); 50 | type OnKilledAccount = (); 51 | type SystemWeightInfo = (); 52 | type SS58Prefix = (); 53 | } 54 | 55 | impl Config for TestRuntime { 56 | type Event = (); 57 | } 58 | 59 | struct ExternalityBuilder; 60 | 61 | impl ExternalityBuilder { 62 | pub fn build() -> TestExternalities { 63 | let storage = system::GenesisConfig::default() 64 | .build_storage::() 65 | .unwrap(); 66 | TestExternalities::from(storage) 67 | } 68 | } 69 | 70 | #[test] 71 | fn init_works() { 72 | ExternalityBuilder::build().execute_with(|| { 73 | assert_ok!(BasicToken::init(Origin::signed(1))); 74 | assert_eq!(BasicToken::get_balance(1), 21000000); 75 | }) 76 | } 77 | 78 | #[test] 79 | fn cant_double_init() { 80 | ExternalityBuilder::build().execute_with(|| { 81 | assert_ok!(BasicToken::init(Origin::signed(1))); 82 | assert_noop!( 83 | BasicToken::init(Origin::signed(1)), 84 | Error::::AlreadyInitialized 85 | ); 86 | }) 87 | } 88 | 89 | #[test] 90 | fn transfer_works() { 91 | ExternalityBuilder::build().execute_with(|| { 92 | assert_ok!(BasicToken::init(Origin::signed(1))); 93 | 94 | // Transfer 100 tokens from user 1 to user 2 95 | assert_ok!(BasicToken::transfer(Origin::signed(1), 2, 100)); 96 | 97 | assert_eq!(BasicToken::get_balance(1), 20999900); 98 | assert_eq!(BasicToken::get_balance(2), 100); 99 | }) 100 | } 101 | 102 | #[test] 103 | fn cant_spend_more_than_you_have() { 104 | ExternalityBuilder::build().execute_with(|| { 105 | assert_ok!(BasicToken::init(Origin::signed(1))); 106 | assert_noop!( 107 | BasicToken::transfer(Origin::signed(1), 2, 21000001), 108 | Error::::InsufficientFunds 109 | ); 110 | }) 111 | } 112 | -------------------------------------------------------------------------------- /pallets/basic-token/types.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /pallets/charity/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "charity" 3 | version = "3.0.0" 4 | edition = "2018" 5 | authors = ['Substrate DevHub '] 6 | repository = 'https://github.com/substrate-developer-hub/recipes' 7 | description = "A charitable organization that accepts donations and imbalances" 8 | license = "GPL-3.0-or-later" 9 | 10 | [dependencies] 11 | parity-scale-codec = { version = "2.0", features = ["derive"], default-features = false } 12 | serde = '1.0' 13 | 14 | # Substrate packages 15 | pallet-balances = { version = '3.0', default-features = false } 16 | frame-support = { version = '3.0', default-features = false } 17 | frame-system = { version = '3.0', default-features = false } 18 | sp-runtime = { version = '3.0', default-features = false } 19 | sp-std = { version = '3.0', default-features = false } 20 | 21 | [dev-dependencies] 22 | sp-core = '3.0' 23 | sp-io = '3.0' 24 | 25 | [features] 26 | default = ['std'] 27 | std = [ 28 | 'pallet-balances/std', 29 | 'frame-support/std', 30 | 'frame-system/std', 31 | 'parity-scale-codec/std', 32 | 'sp-runtime/std', 33 | ] 34 | -------------------------------------------------------------------------------- /pallets/charity/types.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /pallets/check-membership/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "check-membership" 3 | version = "3.0.0" 4 | edition = "2018" 5 | authors = ['Substrate DevHub '] 6 | repository = 'https://github.com/substrate-developer-hub/recipes' 7 | description = "A pallet that demonstrates permissioned method calls" 8 | license = "GPL-3.0-or-later" 9 | 10 | [dependencies] 11 | parity-scale-codec = { version = "2.0", features = ["derive"], default-features = false } 12 | 13 | frame-support = { version = '3.0', default-features = false } 14 | frame-system = { version = '3.0', default-features = false} 15 | sp-runtime = { version = '3.0', default-features = false } 16 | sp-std = { version = '3.0', default-features = false } 17 | account-set = { path = '../../traits/account-set', default-features = false } 18 | vec-set = { path = '../vec-set', default-features = false } 19 | 20 | [dev-dependencies] 21 | sp-core = '3.0' 22 | sp-io = '3.0' 23 | serde = '1.0' 24 | 25 | [features] 26 | default = ['std'] 27 | std = [ 28 | 'account-set/std', 29 | 'frame-support/std', 30 | 'frame-system/std', 31 | 'parity-scale-codec/std', 32 | 'sp-runtime/std', 33 | 'sp-std/std', 34 | 'vec-set/std', 35 | ] 36 | -------------------------------------------------------------------------------- /pallets/check-membership/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![cfg_attr(not(feature = "std"), no_std)] 2 | 3 | //! This module contains two nearly identical Substrate pallets. Both demonstrate access control 4 | //! and coupling multiple pallets together in a FRAME runtime. 5 | //! 6 | //! The _tight_ variant demonstrates tightly coupling pallets and is itself tightly coupled to the 7 | //! `vec-set` pallet. 8 | //! 9 | //! The _loose_ variant demonstrates loosely coupling pallets and is itself loosely coupled through 10 | //! the `AccountSet` trait. 11 | 12 | pub mod loose; 13 | pub mod tight; 14 | -------------------------------------------------------------------------------- /pallets/check-membership/src/loose/mod.rs: -------------------------------------------------------------------------------- 1 | //! Pallet that demonstrates a minimal access control check. When a user calls this pallet's 2 | //! only dispatchable function, `check_membership`, the caller is checked against a set of approved 3 | //! callers. If the caller is a member of the set, the pallet's `IsAMember` event is emitted. Otherwise a `NotAMember` error is returned. 4 | //! 5 | //! The list of approved members is provided by an external source and exposed through an associated 6 | //! type in this pallet's configuration trait. Any type that implements the `AccountSet` trait can be 7 | //! used to supply the membership set. 8 | 9 | #![allow(clippy::unused_unit)] 10 | pub use pallet::*; 11 | 12 | #[cfg(test)] 13 | mod tests; 14 | 15 | #[frame_support::pallet] 16 | pub mod pallet { 17 | use account_set::AccountSet; 18 | use frame_support::{dispatch::DispatchResultWithPostInfo, pallet_prelude::*}; 19 | use frame_system::pallet_prelude::*; 20 | 21 | /// The pallet's configuration trait 22 | /// Notice the loose coupling: any pallet that implements the `AccountSet` behavior works here. 23 | #[pallet::config] 24 | pub trait Config: frame_system::Config { 25 | /// The ubiquitous event type 26 | type Event: From> + IsType<::Event>; 27 | 28 | /// A type that will supply a set of members to check access control against 29 | type MembershipSource: AccountSet; 30 | } 31 | 32 | #[pallet::event] 33 | #[pallet::metadata(T::AccountId = "AccountId")] 34 | #[pallet::generate_deposit(pub (super) fn deposit_event)] 35 | pub enum Event { 36 | /// The caller is a member. 37 | IsAMember(T::AccountId), 38 | } 39 | 40 | #[pallet::error] 41 | pub enum Error { 42 | /// The caller is not a member 43 | NotAMember, 44 | } 45 | 46 | #[pallet::pallet] 47 | #[pallet::generate_store(pub (super) trait Store)] 48 | pub struct Pallet(PhantomData); 49 | 50 | #[pallet::hooks] 51 | impl Hooks> for Pallet {} 52 | 53 | #[pallet::call] 54 | impl Pallet { 55 | /// Checks whether the caller is a member of the set of account IDs provided by the 56 | /// MembershipSource type. Emits an event if they are, and errors if not. 57 | #[pallet::weight(10_000)] 58 | pub fn check_membership(origin: OriginFor) -> DispatchResultWithPostInfo { 59 | let caller = ensure_signed(origin)?; 60 | 61 | // Get the members from the `vec-set` pallet 62 | let members = T::MembershipSource::accounts(); 63 | 64 | // Check whether the caller is a member 65 | ensure!(members.contains(&caller), Error::::NotAMember); 66 | 67 | // If the previous call didn't error, then the caller is a member, so emit the event 68 | Self::deposit_event(Event::IsAMember(caller)); 69 | Ok(().into()) 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /pallets/check-membership/src/loose/tests.rs: -------------------------------------------------------------------------------- 1 | use crate::loose::{self as check_membership, Config, Error}; 2 | use frame_support::{assert_noop, assert_ok, construct_runtime, parameter_types}; 3 | use sp_core::H256; 4 | use sp_io::TestExternalities; 5 | use sp_runtime::{ 6 | testing::Header, 7 | traits::{BlakeTwo256, IdentityLookup}, 8 | }; 9 | 10 | type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; 11 | type Block = frame_system::mocking::MockBlock; 12 | 13 | construct_runtime!( 14 | pub enum TestRuntime where 15 | Block = Block, 16 | NodeBlock = Block, 17 | UncheckedExtrinsic = UncheckedExtrinsic, 18 | { 19 | System: frame_system::{Module, Call, Config, Storage, Event}, 20 | VecSet: vec_set::{Module, Call, Storage, Event}, 21 | CheckMembership: check_membership::{Module, Call, Event}, 22 | } 23 | ); 24 | 25 | parameter_types! { 26 | pub const BlockHashCount: u64 = 250; 27 | pub BlockWeights: frame_system::limits::BlockWeights = 28 | frame_system::limits::BlockWeights::simple_max(1024); 29 | } 30 | impl frame_system::Config for TestRuntime { 31 | type BaseCallFilter = (); 32 | type BlockWeights = (); 33 | type BlockLength = (); 34 | type Origin = Origin; 35 | type Index = u64; 36 | type Call = Call; 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 DbWeight = (); 46 | type Version = (); 47 | type PalletInfo = PalletInfo; 48 | type AccountData = (); 49 | type OnNewAccount = (); 50 | type OnKilledAccount = (); 51 | type SystemWeightInfo = (); 52 | type SS58Prefix = (); 53 | } 54 | 55 | impl vec_set::Config for TestRuntime { 56 | type Event = Event; 57 | } 58 | 59 | impl Config for TestRuntime { 60 | type Event = Event; 61 | type MembershipSource = VecSet; 62 | } 63 | 64 | struct ExternalityBuilder; 65 | 66 | impl ExternalityBuilder { 67 | pub fn build() -> TestExternalities { 68 | let storage = frame_system::GenesisConfig::default() 69 | .build_storage::() 70 | .unwrap(); 71 | let mut ext = TestExternalities::from(storage); 72 | ext.execute_with(|| System::set_block_number(1)); 73 | ext 74 | } 75 | } 76 | 77 | #[test] 78 | fn members_can_call() { 79 | ExternalityBuilder::build().execute_with(|| { 80 | assert_ok!(VecSet::add_member(Origin::signed(1))); 81 | 82 | assert_ok!(CheckMembership::check_membership(Origin::signed(1))); 83 | 84 | let expected_event = Event::check_membership(check_membership::Event::IsAMember(1)); 85 | 86 | assert_eq!(System::events()[1].event, expected_event,); 87 | }) 88 | } 89 | 90 | #[test] 91 | fn non_members_cant_call() { 92 | ExternalityBuilder::build().execute_with(|| { 93 | assert_noop!( 94 | CheckMembership::check_membership(Origin::signed(1)), 95 | Error::::NotAMember 96 | ); 97 | }) 98 | } 99 | -------------------------------------------------------------------------------- /pallets/check-membership/src/tight/mod.rs: -------------------------------------------------------------------------------- 1 | //! Pallet that demonstrates a minimal access control check. When a user calls this pallet's 2 | //! only dispatchable function, `check_membership`, the caller is checked against a set of approved 3 | //! callers. If the caller is a member of the set, the pallet's `IsAMember` event is emitted. Otherwise a `NotAMember` error is returned. 4 | //! 5 | //! The list of approved members is provided by the `vec-set` pallet. In order for this pallet to be 6 | //! used, the `vec-set` pallet must also be present in the runtime. 7 | 8 | #![allow(clippy::unused_unit)] 9 | pub use pallet::*; 10 | 11 | #[cfg(test)] 12 | mod tests; 13 | 14 | #[frame_support::pallet] 15 | pub mod pallet { 16 | use frame_support::{dispatch::DispatchResultWithPostInfo, pallet_prelude::*}; 17 | use frame_system::pallet_prelude::*; 18 | 19 | /// The pallet's configuration trait. 20 | /// Notice the explicit tight coupling to the `vec-set` pallet 21 | #[pallet::config] 22 | pub trait Config: frame_system::Config + vec_set::Config { 23 | type Event: From> + IsType<::Event>; 24 | } 25 | 26 | #[pallet::event] 27 | #[pallet::metadata(T::AccountId = "AccountId")] 28 | #[pallet::generate_deposit(pub (super) fn deposit_event)] 29 | pub enum Event { 30 | /// The caller is a member. 31 | IsAMember(T::AccountId), 32 | } 33 | 34 | #[pallet::error] 35 | pub enum Error { 36 | /// The caller is not a member 37 | NotAMember, 38 | } 39 | 40 | #[pallet::pallet] 41 | #[pallet::generate_store(pub (super) trait Store)] 42 | pub struct Pallet(PhantomData); 43 | 44 | #[pallet::hooks] 45 | impl Hooks> for Pallet {} 46 | 47 | #[pallet::call] 48 | impl Pallet { 49 | /// Checks whether the caller is a member of the set of account IDs provided by the `vec-set` 50 | /// pallet. Emits an event if they are, and errors if not. 51 | #[pallet::weight(10_000)] 52 | pub fn check_membership(origin: OriginFor) -> DispatchResultWithPostInfo { 53 | let caller = ensure_signed(origin)?; 54 | 55 | // Get the members from the `vec-set` pallet 56 | let members = vec_set::Module::::members(); 57 | 58 | // Check whether the caller is a member 59 | members 60 | .binary_search(&caller) 61 | .map_err(|_| Error::::NotAMember)?; 62 | 63 | // If the previous call didn't error, then the caller is a member, so emit the event 64 | Self::deposit_event(Event::IsAMember(caller)); 65 | Ok(().into()) 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /pallets/check-membership/src/tight/tests.rs: -------------------------------------------------------------------------------- 1 | use crate::tight::{self as check_membership, Config, Error}; 2 | use frame_support::{assert_noop, assert_ok, construct_runtime, parameter_types}; 3 | use sp_core::H256; 4 | use sp_io::TestExternalities; 5 | use sp_runtime::{ 6 | testing::Header, 7 | traits::{BlakeTwo256, IdentityLookup}, 8 | }; 9 | 10 | type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; 11 | type Block = frame_system::mocking::MockBlock; 12 | 13 | construct_runtime!( 14 | pub enum TestRuntime where 15 | Block = Block, 16 | NodeBlock = Block, 17 | UncheckedExtrinsic = UncheckedExtrinsic, 18 | { 19 | System: frame_system::{Module, Call, Config, Storage, Event}, 20 | VecSet: vec_set::{Module, Call, Storage, Event}, 21 | CheckMembership: check_membership::{Module, Call, Event}, 22 | } 23 | ); 24 | 25 | parameter_types! { 26 | pub const BlockHashCount: u64 = 250; 27 | pub BlockWeights: frame_system::limits::BlockWeights = 28 | frame_system::limits::BlockWeights::simple_max(1024); 29 | } 30 | impl frame_system::Config for TestRuntime { 31 | type BaseCallFilter = (); 32 | type BlockWeights = (); 33 | type BlockLength = (); 34 | type Origin = Origin; 35 | type Index = u64; 36 | type Call = Call; 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 DbWeight = (); 46 | type Version = (); 47 | type PalletInfo = PalletInfo; 48 | type AccountData = (); 49 | type OnNewAccount = (); 50 | type OnKilledAccount = (); 51 | type SystemWeightInfo = (); 52 | type SS58Prefix = (); 53 | } 54 | 55 | impl vec_set::Config for TestRuntime { 56 | type Event = Event; 57 | } 58 | 59 | impl Config for TestRuntime { 60 | type Event = Event; 61 | } 62 | 63 | struct ExternalityBuilder; 64 | 65 | impl ExternalityBuilder { 66 | pub fn build() -> TestExternalities { 67 | let storage = frame_system::GenesisConfig::default() 68 | .build_storage::() 69 | .unwrap(); 70 | let mut ext = TestExternalities::from(storage); 71 | ext.execute_with(|| System::set_block_number(1)); 72 | ext 73 | } 74 | } 75 | 76 | #[test] 77 | fn members_can_call() { 78 | ExternalityBuilder::build().execute_with(|| { 79 | assert_ok!(VecSet::add_member(Origin::signed(1))); 80 | 81 | assert_ok!(CheckMembership::check_membership(Origin::signed(1))); 82 | 83 | let expected_event = Event::check_membership(check_membership::Event::IsAMember(1)); 84 | 85 | assert_eq!(System::events()[1].event, expected_event,); 86 | }) 87 | } 88 | 89 | #[test] 90 | fn non_members_cant_call() { 91 | ExternalityBuilder::build().execute_with(|| { 92 | assert_noop!( 93 | CheckMembership::check_membership(Origin::signed(1)), 94 | Error::::NotAMember 95 | ); 96 | }) 97 | } 98 | -------------------------------------------------------------------------------- /pallets/check-membership/types.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /pallets/compounding-interest/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "compounding-interest" 3 | version = "3.0.0" 4 | edition = "2018" 5 | authors = ['Substrate DevHub '] 6 | repository = 'https://github.com/substrate-developer-hub/recipes' 7 | description = "A savings account that uses fixed point arithmetic to implement compounding interest" 8 | license = "GPL-3.0-or-later" 9 | 10 | [dependencies] 11 | substrate-fixed = { git = 'https://github.com/encointer/substrate-fixed.git', branch = "master" } 12 | parity-scale-codec = { version = "2.0", features = ["derive"], default-features = false } 13 | 14 | # Substrate packages 15 | frame-support = { version = '3.0', default-features = false } 16 | frame-system = { version = '3.0', default-features = false } 17 | sp-arithmetic = { version = '3.0', default-features = false } 18 | sp-runtime = { version = '3.0', default-features = false } 19 | sp-std = { version = '3.0', default-features = false } 20 | 21 | [dev-dependencies] 22 | serde = '1.0' 23 | 24 | # Substrate packages 25 | sp-core = '3.0' 26 | sp-io = '3.0' 27 | 28 | [features] 29 | default = ['std'] 30 | std = [ 31 | 'frame-support/std', 32 | 'frame-system/std', 33 | 'parity-scale-codec/std', 34 | 'sp-arithmetic/std', 35 | 'sp-runtime/std', 36 | 'sp-std/std', 37 | ] 38 | -------------------------------------------------------------------------------- /pallets/compounding-interest/types.json: -------------------------------------------------------------------------------- 1 | { 2 | "ContinuousAccountData": { 3 | "principal": "u64", 4 | "deposit_date": "BlockNumber" 5 | }, 6 | "U16F16": "[u8; 4]" 7 | } 8 | -------------------------------------------------------------------------------- /pallets/constant-config/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "constant-config" 3 | version = "3.0.0" 4 | edition = "2018" 5 | authors = ['Substrate DevHub '] 6 | repository = 'https://github.com/substrate-developer-hub/recipes' 7 | description = "A pallet that demonstrates constants declared in the configuration trait" 8 | license = "GPL-3.0-or-later" 9 | 10 | [dependencies] 11 | parity-scale-codec = { version = "2.0", features = ["derive"], default-features = false } 12 | 13 | # Substrate packages 14 | frame-support = { version = '3.0', default-features = false } 15 | frame-system = { version = '3.0', default-features = false } 16 | sp-runtime = { version = '3.0', default-features = false } 17 | 18 | [dev-dependencies] 19 | serde = '1.0' 20 | 21 | # Substrate packages 22 | sp-core = '3.0' 23 | sp-io = '3.0' 24 | 25 | [features] 26 | default = ['std'] 27 | std = [ 28 | 'frame-support/std', 29 | 'frame-system/std', 30 | 'parity-scale-codec/std', 31 | 'sp-runtime/std', 32 | ] 33 | -------------------------------------------------------------------------------- /pallets/constant-config/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![cfg_attr(not(feature = "std"), no_std)] 2 | #![allow(clippy::unused_unit)] 3 | //! A pallet to demonstrate configurable pallet constants. 4 | //! This pallet has a single storage value that can be added to by calling the 5 | //! `add_value` extrinsic. 6 | //! 7 | //! The value added cannot exceed a maximum which is specified as a configuration constant. 8 | //! The stored value is cleared (set to zero) at a regular interval which is specified 9 | //! as a configuration constant. 10 | 11 | pub use pallet::*; 12 | 13 | #[cfg(test)] 14 | mod tests; 15 | 16 | #[frame_support::pallet] 17 | pub mod pallet { 18 | use frame_support::dispatch::{DispatchErrorWithPostInfo, PostDispatchInfo}; 19 | use frame_support::{dispatch::DispatchResultWithPostInfo, pallet_prelude::*}; 20 | use frame_system::pallet_prelude::*; 21 | use sp_runtime::traits::Zero; 22 | 23 | #[pallet::config] 24 | pub trait Config: frame_system::Config { 25 | type Event: From + IsType<::Event>; 26 | 27 | /// Maximum amount added per invocation 28 | type MaxAddend: Get; 29 | 30 | /// Frequency with which the stored value is deleted 31 | type ClearFrequency: Get; 32 | } 33 | 34 | #[pallet::storage] 35 | #[pallet::getter(fn single_value)] 36 | pub(super) type SingleValue = StorageValue<_, u32, ValueQuery>; 37 | 38 | #[pallet::event] 39 | #[pallet::generate_deposit(pub(super) fn deposit_event)] 40 | pub enum Event { 41 | /// The value has ben added to. The parameters are 42 | /// ( initial amount, amount added, final amount) 43 | Added(u32, u32, u32), 44 | /// The value has been cleared. The parameter is the value before clearing. 45 | Cleared(u32), 46 | } 47 | 48 | #[pallet::pallet] 49 | #[pallet::generate_store(pub(super) trait Store)] 50 | pub struct Pallet(PhantomData); 51 | 52 | #[pallet::hooks] 53 | impl Hooks for Pallet { 54 | fn on_finalize(n: T::BlockNumber) { 55 | if (n % T::ClearFrequency::get()).is_zero() { 56 | let c_val = SingleValue::::get(); 57 | SingleValue::::put(0u32); 58 | Self::deposit_event(Event::Cleared(c_val)); 59 | } 60 | } 61 | } 62 | 63 | #[pallet::call] 64 | impl Pallet { 65 | /// Add to the stored value. The `val_to_add` parameter cannot exceed the specified manimum. 66 | #[pallet::weight(10_000)] 67 | pub fn add_value(origin: OriginFor, val_to_add: u32) -> DispatchResultWithPostInfo { 68 | let _ = ensure_signed(origin)?; 69 | ensure!( 70 | val_to_add <= T::MaxAddend::get(), 71 | "value must be <= maximum add amount constant" 72 | ); 73 | 74 | // previous value got 75 | let c_val = SingleValue::::get(); 76 | 77 | // checks for overflow when new value added 78 | let result = match c_val.checked_add(val_to_add) { 79 | Some(r) => r, 80 | None => { 81 | return Err(DispatchErrorWithPostInfo { 82 | post_info: PostDispatchInfo::from(()), 83 | error: DispatchError::Other("Addition overflowed"), 84 | }) 85 | } 86 | }; 87 | SingleValue::::put(result); 88 | Self::deposit_event(Event::Added(c_val, val_to_add, result)); 89 | Ok(().into()) 90 | } 91 | 92 | /// For testing purposes 93 | /// Sets the stored value to a given value 94 | #[pallet::weight(10_000)] 95 | pub fn set_value(origin: OriginFor, value: u32) -> DispatchResultWithPostInfo { 96 | let _ = ensure_signed(origin)?; 97 | SingleValue::::put(value); 98 | Ok(().into()) 99 | } 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /pallets/constant-config/types.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /pallets/currency-imbalances/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "currency-imbalances" 3 | version = "3.0.0" 4 | edition = "2018" 5 | authors = ['Substrate DevHub '] 6 | repository = 'https://github.com/substrate-developer-hub/recipes' 7 | description = "A pallet that demonstrates using currency imbalances" 8 | license = "GPL-3.0-or-later" 9 | 10 | [dependencies] 11 | parity-scale-codec = { version = "2.0", features = ["derive"], default-features = false } 12 | 13 | # Substrate packages 14 | frame-support = { version = '3.0', default-features = false } 15 | frame-system = { version = '3.0', default-features = false } 16 | sp-runtime = { version = '3.0', default-features = false } 17 | 18 | [dev-dependencies] 19 | sp-core = '3.0' 20 | sp-io = '3.0' 21 | 22 | [features] 23 | default = ['std'] 24 | std = [ 25 | 'frame-support/std', 26 | 'frame-system/std', 27 | 'parity-scale-codec/std', 28 | 'sp-runtime/std', 29 | ] 30 | -------------------------------------------------------------------------------- /pallets/currency-imbalances/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![cfg_attr(not(feature = "std"), no_std)] 2 | #![allow(clippy::unused_unit)] 3 | //! A Pallet to demonstrate using currency imbalances 4 | //! 5 | //! WARNING: never use this code in production (for demonstration/teaching purposes only) 6 | //! it only checks for signed extrinsics to enable arbitrary minting/slashing!!! 7 | 8 | use frame_support::{ 9 | decl_event, decl_module, 10 | traits::{Currency, Imbalance, OnUnbalanced, ReservableCurrency}, 11 | }; 12 | use frame_system::ensure_signed; 13 | 14 | // balance type using reservable currency type 15 | type BalanceOf = 16 | <::Currency as Currency<::AccountId>>::Balance; 17 | type PositiveImbalanceOf = <::Currency as Currency< 18 | ::AccountId, 19 | >>::PositiveImbalance; 20 | type NegativeImbalanceOf = <::Currency as Currency< 21 | ::AccountId, 22 | >>::NegativeImbalance; 23 | 24 | pub trait Config: frame_system::Config + Sized { 25 | /// The overarching event type 26 | type Event: From> + Into<::Event>; 27 | 28 | /// Currency type for this pallet. 29 | type Currency: Currency + ReservableCurrency; 30 | 31 | /// Handler for the unbalanced increment when rewarding (minting rewards) 32 | type Reward: OnUnbalanced>; 33 | 34 | /// Handler for the unbalanced decrement when slashing (burning collateral) 35 | type Slash: OnUnbalanced>; 36 | } 37 | 38 | decl_event!( 39 | pub enum Event 40 | where 41 | AccountId = ::AccountId, 42 | Balance = BalanceOf, 43 | BlockNumber = ::BlockNumber, 44 | { 45 | SlashFunds(AccountId, Balance, BlockNumber), 46 | RewardFunds(AccountId, Balance, BlockNumber), 47 | } 48 | ); 49 | 50 | decl_module! { 51 | pub struct Module for enum Call where origin: T::Origin { 52 | fn deposit_event() = default; 53 | 54 | /// Slashes the specified amount of funds from the specified account 55 | #[weight = 10_000] 56 | pub fn slash_funds(origin, to_punish: T::AccountId, collateral: BalanceOf) { 57 | let _ = ensure_signed(origin)?; 58 | 59 | let imbalance = T::Currency::slash_reserved(&to_punish, collateral).0; 60 | T::Slash::on_unbalanced(imbalance); 61 | 62 | let now = >::block_number(); 63 | Self::deposit_event(RawEvent::SlashFunds(to_punish, collateral, now)); 64 | } 65 | 66 | /// Awards the specified amount of funds to the specified account 67 | #[weight = 10_000] 68 | pub fn reward_funds(origin, to_reward: T::AccountId, reward: BalanceOf) { 69 | let _ = ensure_signed(origin)?; 70 | 71 | let mut total_imbalance = >::zero(); 72 | 73 | let r = T::Currency::deposit_into_existing(&to_reward, reward).ok(); 74 | total_imbalance.maybe_subsume(r); 75 | T::Reward::on_unbalanced(total_imbalance); 76 | 77 | let now = >::block_number(); 78 | Self::deposit_event(RawEvent::RewardFunds(to_reward, reward, now)); 79 | } 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /pallets/currency-imbalances/types.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /pallets/default-instance/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "default-instance" 3 | version = "3.0.0" 4 | edition = "2018" 5 | authors = ['Substrate DevHub '] 6 | repository = 'https://github.com/substrate-developer-hub/recipes' 7 | description = "An instantiable pallet featuring deafult instance" 8 | license = "GPL-3.0-or-later" 9 | 10 | [dependencies] 11 | parity-scale-codec = { version = "2.0", features = ["derive"], default-features = false } 12 | 13 | # Substrate packages 14 | frame-support = { version = '3.0', default-features = false } 15 | frame-system = { version = '3.0', default-features = false } 16 | sp-core = { version = '3.0', default-features = false } 17 | sp-runtime = { version = '3.0', default-features = false } 18 | 19 | [dev-dependencies] 20 | sp-io = '3.0' 21 | 22 | [features] 23 | default = ['std'] 24 | std = [ 25 | 'frame-support/std', 26 | 'frame-system/std', 27 | 'parity-scale-codec/std', 28 | 'sp-runtime/std', 29 | ] 30 | -------------------------------------------------------------------------------- /pallets/default-instance/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! An example instantiable pallet (with default instance) 2 | //! TODO combine this and last caller into a singe crate (see check membership for an example) 3 | 4 | #![cfg_attr(not(feature = "std"), no_std)] 5 | #![allow(clippy::unused_unit)] 6 | pub use pallet::*; 7 | 8 | #[frame_support::pallet] 9 | pub mod pallet { 10 | use frame_support::{dispatch::DispatchResultWithPostInfo, pallet_prelude::*}; 11 | use frame_system::pallet_prelude::*; 12 | 13 | // The pallet's configuration trait takes an instance as a type parameter. The instance type is 14 | // created by the `decl_storage!` macro below. Giving it a value of `DefaultInstance` allows us 15 | // to use the pallet in a runtime where only a single instance is desired without the extra syntax 16 | // that is otherwise needed to use instantiable pallets. 17 | #[pallet::config] 18 | pub trait Config: frame_system::Config { 19 | /// The overarching event type. 20 | type Event: From> + IsType<::Event>; 21 | } 22 | 23 | #[pallet::storage] 24 | pub(super) type Caller = StorageValue<_, T::AccountId, ValueQuery>; 25 | 26 | #[pallet::event] 27 | #[pallet::metadata(T::AccountId = "AccountId")] 28 | #[pallet::generate_deposit(pub (super) fn deposit_event)] 29 | pub enum Event { 30 | Called(T::AccountId), 31 | } 32 | 33 | #[pallet::pallet] 34 | #[pallet::generate_store(pub (super) trait Store)] 35 | pub struct Pallet(PhantomData); 36 | 37 | #[pallet::hooks] 38 | impl Hooks> for Pallet {} 39 | 40 | #[pallet::call] 41 | impl Pallet { 42 | /// The only dispatchable call, updates the single storage item, 43 | /// and emits an event. 44 | #[pallet::weight(10_000)] 45 | fn call(origin: OriginFor) -> DispatchResultWithPostInfo { 46 | let caller = ensure_signed(origin)?; 47 | 48 | // When writing to storage, we supply, not only a configuration T, but also an 49 | // instance, I. 50 | >::put(&caller); 51 | Self::deposit_event(Event::Called(caller)); 52 | Ok(().into()) 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /pallets/default-instance/types.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /pallets/double-map/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "double-map" 3 | version = "3.0.0" 4 | edition = "2018" 5 | authors = ['Substrate DevHub '] 6 | repository = 'https://github.com/substrate-developer-hub/recipes' 7 | description = "A pallet that demonstrates using a double map in Substrate" 8 | license = "GPL-3.0-or-later" 9 | 10 | [dependencies] 11 | parity-scale-codec = { version = "2.0", features = ["derive"], default-features = false } 12 | 13 | # Substrate packages 14 | frame-support = { version = '3.0', default-features = false } 15 | frame-system = { version = '3.0', default-features = false } 16 | sp-runtime = { version = '3.0', default-features = false } 17 | sp-std = { version = '3.0', default-features = false } 18 | 19 | [dev-dependencies] 20 | sp-core = '3.0' 21 | sp-io = '3.0' 22 | serde = '1.0' 23 | 24 | [features] 25 | default = ['std'] 26 | std = [ 27 | 'frame-support/std', 28 | 'frame-system/std', 29 | 'parity-scale-codec/std', 30 | 'sp-runtime/std', 31 | 'sp-std/std', 32 | ] 33 | -------------------------------------------------------------------------------- /pallets/double-map/types.json: -------------------------------------------------------------------------------- 1 | { 2 | "GroupIndex": "u32" 3 | } 4 | -------------------------------------------------------------------------------- /pallets/fixed-point/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "fixed-point" 3 | version = "3.0.0" 4 | edition = "2018" 5 | authors = ['Substrate DevHub '] 6 | description = "A pallet that demonstrates using fixed-point arithmetic in Substrate" 7 | repository = "https://github.com/substrate-developer-hub/recipes" 8 | license = "GPL-3.0-or-later" 9 | 10 | [dependencies] 11 | parity-scale-codec = { version = "2.0", features = ["derive"], default-features = false } 12 | substrate-fixed = { git = 'https://github.com/encointer/substrate-fixed.git', rev = "b33d186888c60f38adafcfc0ec3a21aab263aef1" } 13 | 14 | # Substrate packages 15 | frame-support = { version = '3.0', default-features = false } 16 | frame-system = { version = '3.0', default-features = false } 17 | sp-arithmetic = { version = '3.0', default-features = false } 18 | sp-core = { version = '3.0', default-features = false } 19 | sp-runtime = { version = '3.0', default-features = false } 20 | sp-std = { version = '3.0', default-features = false } 21 | 22 | [dev-dependencies] 23 | sp-io = '3.0' 24 | serde = '1.0' 25 | 26 | [features] 27 | default = ['std'] 28 | std = [ 29 | 'frame-support/std', 30 | 'frame-system/std', 31 | 'parity-scale-codec/std', 32 | 'sp-arithmetic/std', 33 | 'sp-runtime/std', 34 | 'sp-std/std', 35 | ] 36 | -------------------------------------------------------------------------------- /pallets/fixed-point/types.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /pallets/generic-event/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "generic-event" 3 | version = "3.0.0" 4 | edition = "2018" 5 | authors = ['Substrate DevHub '] 6 | repository = 'https://github.com/substrate-developer-hub/recipes' 7 | description = "A pallet that raises events encapsulating data types from the configuration trait" 8 | license = "GPL-3.0-or-later" 9 | 10 | [dependencies] 11 | parity-scale-codec = { version = "2.0", features = ["derive"], default-features = false } 12 | 13 | # Substrate packages 14 | frame-support = { version = '3.0', default-features = false } 15 | frame-system = { version = '3.0', default-features = false } 16 | sp-runtime = { version = '3.0', default-features = false } 17 | 18 | [dev-dependencies] 19 | sp-core = '3.0' 20 | sp-io = '3.0' 21 | serde = '1.0' 22 | 23 | [features] 24 | default = ['std'] 25 | std = [ 26 | 'frame-support/std', 27 | 'frame-system/std', 28 | 'parity-scale-codec/std', 29 | 'sp-runtime/std', 30 | ] 31 | -------------------------------------------------------------------------------- /pallets/generic-event/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! Demonstration of Event variants that use type(s) from the pallet's configuration trait 2 | 3 | #![cfg_attr(not(feature = "std"), no_std)] 4 | #![allow(clippy::unused_unit)] 5 | pub use pallet::*; 6 | 7 | #[cfg(test)] 8 | mod tests; 9 | 10 | #[frame_support::pallet] 11 | pub mod pallet { 12 | use frame_support::{dispatch::DispatchResultWithPostInfo, pallet_prelude::*}; 13 | use frame_system::pallet_prelude::*; 14 | 15 | #[pallet::pallet] 16 | #[pallet::generate_store(pub (super) trait Store)] 17 | pub struct Pallet(PhantomData); 18 | 19 | #[pallet::config] 20 | pub trait Config: frame_system::Config { 21 | /// The overarching event type. 22 | type Event: From> + IsType<::Event>; 23 | } 24 | 25 | #[pallet::hooks] 26 | impl Hooks> for Pallet {} 27 | 28 | #[pallet::event] 29 | #[pallet::metadata(T::AccountId = "AccountId")] 30 | #[pallet::generate_deposit(pub (super) fn deposit_event)] 31 | pub enum Event { 32 | /// Some input was sent 33 | EmitInput(T::AccountId, u32), 34 | } 35 | 36 | #[pallet::call] 37 | impl Pallet { 38 | /// A simple call that does little more than emit an event 39 | #[pallet::weight(10_000)] 40 | pub fn do_something(origin: OriginFor, input: u32) -> DispatchResultWithPostInfo { 41 | let user = ensure_signed(origin)?; 42 | 43 | // could do something with the input here instead 44 | let new_number = input; 45 | 46 | Self::deposit_event(Event::EmitInput(user, new_number)); 47 | Ok(().into()) 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /pallets/generic-event/src/tests.rs: -------------------------------------------------------------------------------- 1 | use crate::{self as generic_event, Config}; 2 | use frame_support::{assert_ok, construct_runtime, parameter_types}; 3 | use sp_core::H256; 4 | use sp_io::TestExternalities; 5 | use sp_runtime::{ 6 | testing::Header, 7 | traits::{BlakeTwo256, IdentityLookup}, 8 | }; 9 | 10 | type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; 11 | type Block = frame_system::mocking::MockBlock; 12 | 13 | construct_runtime!( 14 | pub enum TestRuntime where 15 | Block = Block, 16 | NodeBlock = Block, 17 | UncheckedExtrinsic = UncheckedExtrinsic, 18 | { 19 | System: frame_system::{Module, Call, Config, Storage, Event}, 20 | GenericEvent: generic_event::{Module, Call, Event}, 21 | } 22 | ); 23 | 24 | parameter_types! { 25 | pub const BlockHashCount: u64 = 250; 26 | pub BlockWeights: frame_system::limits::BlockWeights = 27 | frame_system::limits::BlockWeights::simple_max(1024); 28 | } 29 | impl frame_system::Config for TestRuntime { 30 | type BaseCallFilter = (); 31 | type BlockWeights = (); 32 | type BlockLength = (); 33 | type Origin = Origin; 34 | type Index = u64; 35 | type Call = Call; 36 | type BlockNumber = u64; 37 | type Hash = H256; 38 | type Hashing = BlakeTwo256; 39 | type AccountId = u64; 40 | type Lookup = IdentityLookup; 41 | type Header = Header; 42 | type Event = Event; 43 | type BlockHashCount = BlockHashCount; 44 | type DbWeight = (); 45 | type Version = (); 46 | type PalletInfo = PalletInfo; 47 | type AccountData = (); 48 | type OnNewAccount = (); 49 | type OnKilledAccount = (); 50 | type SystemWeightInfo = (); 51 | type SS58Prefix = (); 52 | } 53 | 54 | impl Config for TestRuntime { 55 | type Event = Event; 56 | } 57 | 58 | struct ExternalityBuilder; 59 | 60 | impl ExternalityBuilder { 61 | pub fn build() -> TestExternalities { 62 | let storage = frame_system::GenesisConfig::default() 63 | .build_storage::() 64 | .unwrap(); 65 | let mut ext = TestExternalities::from(storage); 66 | ext.execute_with(|| System::set_block_number(1)); 67 | ext 68 | } 69 | } 70 | 71 | #[test] 72 | fn test() { 73 | ExternalityBuilder::build().execute_with(|| { 74 | assert_ok!(GenericEvent::do_something(Origin::signed(1), 32)); 75 | 76 | // construct event that should be emitted in the method call directly above 77 | let expected_event = Event::generic_event(generic_event::Event::EmitInput(1, 32)); 78 | 79 | // iterate through array of `EventRecord`s 80 | assert_eq!(System::events()[0].event, expected_event,); 81 | }) 82 | } 83 | -------------------------------------------------------------------------------- /pallets/generic-event/types.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /pallets/hello-substrate/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "hello-substrate" 3 | version = "3.0.0" 4 | edition = "2018" 5 | authors = ['Substrate DevHub '] 6 | repository = 'https://github.com/substrate-developer-hub/recipes' 7 | description = "A pallet that demonstrates printing output the a node's console" 8 | license = "GPL-3.0-or-later" 9 | 10 | [dependencies] 11 | parity-scale-codec = { version = '2.0', features = ['derive'], default-features = false} 12 | 13 | # Substrate packages 14 | frame-support = { version = '3.0', default-features = false } 15 | frame-system = { version = '3.0', default-features = false } 16 | sp-runtime = { version = '3.0', default-features = false } 17 | 18 | [dev-dependencies] 19 | sp-core = '3.0' 20 | sp-io = '3.0' 21 | serde = '1.0' 22 | 23 | [features] 24 | default = ['std'] 25 | std = [ 26 | 'frame-support/std', 27 | 'frame-system/std', 28 | 'parity-scale-codec/std', 29 | 'sp-runtime/std', 30 | ] 31 | -------------------------------------------------------------------------------- /pallets/hello-substrate/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![cfg_attr(not(feature = "std"), no_std)] 2 | #![allow(clippy::unused_unit)] 3 | //! A pallet to demonstrate usage of a simple storage map 4 | //! 5 | //! Storage maps map a key type to a value type. The hasher used to hash the key can be customized. 6 | //! This pallet uses the `blake2_128_concat` hasher. This is a good default hasher. 7 | 8 | pub use pallet::*; 9 | 10 | #[cfg(test)] 11 | mod tests; 12 | 13 | #[frame_support::pallet] 14 | pub mod pallet { 15 | use frame_support::{dispatch::DispatchResultWithPostInfo, pallet_prelude::*}; 16 | use frame_system::pallet_prelude::*; 17 | use sp_runtime::print; 18 | 19 | #[pallet::config] 20 | pub trait Config: frame_system::Config {} 21 | 22 | #[pallet::pallet] 23 | #[pallet::generate_store(pub(super) trait Store)] 24 | pub struct Pallet(PhantomData); 25 | 26 | #[pallet::hooks] 27 | impl Hooks> for Pallet {} 28 | 29 | #[pallet::call] 30 | impl Pallet { 31 | /// Increase the value associated with a particular key 32 | #[pallet::weight(10_000)] 33 | pub fn say_hello(origin: OriginFor) -> DispatchResultWithPostInfo { 34 | // Ensure that the caller is a regular keypair account 35 | let caller = ensure_signed(origin)?; 36 | 37 | // Print a message 38 | print("Hello World"); 39 | // Inspecting a variable as well 40 | debug::info!("Request sent by: {:?}", caller); 41 | 42 | // Indicate that this call succeeded 43 | Ok(().into()) 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /pallets/hello-substrate/src/tests.rs: -------------------------------------------------------------------------------- 1 | use crate::{self as hello_substrate, Config}; 2 | use frame_support::{ 3 | assert_noop, assert_ok, construct_runtime, dispatch::DispatchError, parameter_types, 4 | }; 5 | use frame_system::RawOrigin; 6 | use sp_core::H256; 7 | use sp_io::TestExternalities; 8 | use sp_runtime::{ 9 | testing::Header, 10 | traits::{BlakeTwo256, IdentityLookup}, 11 | }; 12 | 13 | type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; 14 | type Block = frame_system::mocking::MockBlock; 15 | 16 | construct_runtime!( 17 | pub enum TestRuntime where 18 | Block = Block, 19 | NodeBlock = Block, 20 | UncheckedExtrinsic = UncheckedExtrinsic, 21 | { 22 | System: frame_system::{Module, Call, Config, Storage, Event}, 23 | HelloSubstrate: hello_substrate::{Module, Call}, 24 | } 25 | ); 26 | 27 | parameter_types! { 28 | pub const BlockHashCount: u64 = 250; 29 | pub BlockWeights: frame_system::limits::BlockWeights = 30 | frame_system::limits::BlockWeights::simple_max(1024); 31 | } 32 | impl frame_system::Config for TestRuntime { 33 | type BaseCallFilter = (); 34 | type BlockWeights = (); 35 | type BlockLength = (); 36 | type Origin = Origin; 37 | type Index = u64; 38 | type Call = Call; 39 | type BlockNumber = u64; 40 | type Hash = H256; 41 | type Hashing = BlakeTwo256; 42 | type AccountId = u64; 43 | type Lookup = IdentityLookup; 44 | type Header = Header; 45 | type Event = Event; 46 | type BlockHashCount = BlockHashCount; 47 | type DbWeight = (); 48 | type Version = (); 49 | type PalletInfo = PalletInfo; 50 | type AccountData = (); 51 | type OnNewAccount = (); 52 | type OnKilledAccount = (); 53 | type SystemWeightInfo = (); 54 | type SS58Prefix = (); 55 | } 56 | 57 | impl Config for TestRuntime {} 58 | 59 | struct ExternalityBuilder; 60 | 61 | impl ExternalityBuilder { 62 | pub fn build() -> TestExternalities { 63 | let storage = frame_system::GenesisConfig::default() 64 | .build_storage::() 65 | .unwrap(); 66 | let mut ext = TestExternalities::from(storage); 67 | ext.execute_with(|| System::set_block_number(1)); 68 | ext 69 | } 70 | } 71 | 72 | #[test] 73 | fn say_hello_works() { 74 | ExternalityBuilder::build().execute_with(|| { 75 | assert_ok!(HelloSubstrate::say_hello(Origin::signed(1))); 76 | }) 77 | } 78 | 79 | #[test] 80 | fn say_hello_no_root() { 81 | ExternalityBuilder::build().execute_with(|| { 82 | assert_noop!( 83 | HelloSubstrate::say_hello(RawOrigin::Root.into()), 84 | DispatchError::BadOrigin 85 | ); 86 | }) 87 | } 88 | -------------------------------------------------------------------------------- /pallets/hello-substrate/types.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /pallets/last-caller/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "last-caller" 3 | version = "3.0.0" 4 | edition = "2018" 5 | authors = ['Substrate DevHub '] 6 | repository = 'https://github.com/substrate-developer-hub/recipes' 7 | description = "An instantiable pallet that tracks the last account to call it" 8 | license = "GPL-3.0-or-later" 9 | 10 | [dependencies] 11 | parity-scale-codec = { version = "2.0", features = ["derive"], default-features = false } 12 | 13 | # Substrate packages 14 | frame-support = { version = '3.0', default-features = false } 15 | frame-system = { version = '3.0', default-features = false } 16 | sp-core = { version = '3.0', default-features = false } 17 | sp-runtime = { version = '3.0', default-features = false } 18 | 19 | [dev-dependencies] 20 | sp-io = '3.0' 21 | 22 | [features] 23 | default = ['std'] 24 | std = [ 25 | 'frame-support/std', 26 | 'frame-system/std', 27 | 'parity-scale-codec/std', 28 | 'sp-runtime/std', 29 | ] 30 | -------------------------------------------------------------------------------- /pallets/last-caller/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! An example instantiable pallet (without default instance) 2 | 3 | #![cfg_attr(not(feature = "std"), no_std)] 4 | #![allow(clippy::unused_unit)] 5 | pub use pallet::*; 6 | 7 | #[frame_support::pallet] 8 | pub mod pallet { 9 | use frame_support::{dispatch::DispatchResultWithPostInfo, pallet_prelude::*}; 10 | use frame_system::pallet_prelude::*; 11 | 12 | // The pallet's configuration trait takes an instance as a type parameter. The instance type is 13 | // created by the `decl_storage!` macro below. 14 | #[pallet::config] 15 | pub trait Config: frame_system::Config { 16 | /// The overarching event type. 17 | type Event: From> + IsType<::Event>; 18 | } 19 | 20 | #[pallet::storage] 21 | pub(super) type Caller = StorageValue<_, T::AccountId, ValueQuery>; 22 | 23 | #[pallet::event] 24 | #[pallet::metadata(T::AccountId = "AccountId")] 25 | #[pallet::generate_deposit(pub (super) fn deposit_event)] 26 | pub enum Event { 27 | Called(T::AccountId), 28 | } 29 | 30 | #[pallet::pallet] 31 | #[pallet::generate_store(pub (super) trait Store)] 32 | pub struct Pallet(PhantomData); 33 | 34 | #[pallet::hooks] 35 | impl Hooks> for Pallet {} 36 | 37 | #[pallet::call] 38 | impl Pallet { 39 | // The only dispatchable call, updates the single storage item, 40 | // and emits an event. 41 | #[pallet::weight(10_000)] 42 | fn call(origin: OriginFor) -> DispatchResultWithPostInfo { 43 | let caller = ensure_signed(origin)?; 44 | 45 | // When writing to storage, we supply, not only a configuration T, but also an 46 | // instance, I. 47 | >::put(&caller); 48 | Self::deposit_event(Event::Called(caller)); 49 | Ok(().into()) 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /pallets/last-caller/types.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /pallets/lockable-currency/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "lockable-currency" 3 | version = "3.0.0" 4 | edition = "2018" 5 | authors = ['Substrate DevHub '] 6 | repository = 'https://github.com/substrate-developer-hub/recipes' 7 | description = "A pallet that demonstrates the LockableCurrency trait" 8 | license = "GPL-3.0-or-later" 9 | 10 | [dependencies] 11 | parity-scale-codec = { version = "2.0", features = ["derive"], default-features = false } 12 | 13 | # Substrate packages 14 | balances = { package = 'pallet-balances', version = '3.0', default-features = false } 15 | frame-support = { version = '3.0', default-features = false } 16 | frame-system = { version = '3.0', default-features = false } 17 | 18 | [dev-dependencies] 19 | sp-core = '3.0' 20 | sp-io = '3.0' 21 | 22 | [features] 23 | default = ['std'] 24 | std = [ 25 | 'balances/std', 26 | 'frame-support/std', 27 | 'frame-system/std', 28 | 'parity-scale-codec/std', 29 | ] 30 | -------------------------------------------------------------------------------- /pallets/lockable-currency/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! A pallet to demonstrate the `LockableCurrency` trait 2 | //! borrows collateral locking logic from pallet_staking 3 | #![allow(clippy::unused_unit)] 4 | pub use pallet::*; 5 | 6 | #[frame_support::pallet] 7 | pub mod pallet { 8 | use frame_support::traits::{Currency, LockIdentifier, LockableCurrency, WithdrawReasons}; 9 | use frame_support::{dispatch::DispatchResultWithPostInfo, pallet_prelude::*}; 10 | use frame_system::pallet_prelude::*; 11 | 12 | const EXAMPLE_ID: LockIdentifier = *b"example "; 13 | 14 | type BalanceOf = 15 | <::Currency as Currency<::AccountId>>::Balance; 16 | 17 | #[pallet::config] 18 | pub trait Config: frame_system::Config { 19 | /// The lockable currency type 20 | type Currency: LockableCurrency; 21 | 22 | /// The overarching event type 23 | type Event: From> + IsType<::Event>; 24 | } 25 | 26 | #[pallet::pallet] 27 | #[pallet::generate_store(pub (super) trait Store)] 28 | pub struct Pallet(PhantomData); 29 | 30 | #[pallet::hooks] 31 | impl Hooks> for Pallet {} 32 | 33 | #[pallet::event] 34 | #[pallet::metadata(T::AccountId = "AccountId")] 35 | #[pallet::generate_deposit(pub (super) fn deposit_event)] 36 | pub enum Event { 37 | Locked(T::AccountId, BalanceOf), 38 | ExtendedLock(T::AccountId, BalanceOf), 39 | Unlocked(T::AccountId), 40 | } 41 | 42 | #[pallet::call] 43 | impl Pallet { 44 | /// Locks the specified amount of tokens from the caller 45 | #[pallet::weight(10_000)] 46 | fn lock_capital(origin: OriginFor, amount: BalanceOf) -> DispatchResultWithPostInfo { 47 | let user = ensure_signed(origin)?; 48 | 49 | T::Currency::set_lock(EXAMPLE_ID, &user, amount, WithdrawReasons::all()); 50 | 51 | Self::deposit_event(Event::Locked(user, amount)); 52 | Ok(().into()) 53 | } 54 | 55 | /// Extends the lock period 56 | #[pallet::weight(10_000)] 57 | fn extend_lock(origin: OriginFor, amount: BalanceOf) -> DispatchResultWithPostInfo { 58 | let user = ensure_signed(origin)?; 59 | 60 | T::Currency::extend_lock(EXAMPLE_ID, &user, amount, WithdrawReasons::all()); 61 | 62 | Self::deposit_event(Event::ExtendedLock(user, amount)); 63 | Ok(().into()) 64 | } 65 | 66 | /// Releases all locked tokens 67 | #[pallet::weight(10_000)] 68 | fn unlock_all(origin: OriginFor) -> DispatchResultWithPostInfo { 69 | let user = ensure_signed(origin)?; 70 | 71 | T::Currency::remove_lock(EXAMPLE_ID, &user); 72 | 73 | Self::deposit_event(Event::Unlocked(user)); 74 | Ok(().into()) 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /pallets/lockable-currency/types.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /pallets/map-set/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "map-set" 3 | version = "3.0.0" 4 | edition = "2018" 5 | authors = ['Substrate DevHub '] 6 | repository = 'https://github.com/substrate-developer-hub/recipes' 7 | description = "A pallet that implements a storage Set on top of a storage map" 8 | license = "GPL-3.0-or-later" 9 | 10 | [dependencies] 11 | parity-scale-codec = { version = "2.0", features = ["derive"], default-features = false } 12 | 13 | # Substrate packages 14 | account-set = { path = '../../traits/account-set', default-features = false } 15 | frame-support = { version = '3.0', default-features = false } 16 | frame-system = { version = '3.0', default-features = false } 17 | sp-runtime = { version = '3.0', default-features = false } 18 | sp-std = { version = '3.0', default-features = false } 19 | 20 | [dev-dependencies] 21 | sp-core = '3.0' 22 | sp-io = '3.0' 23 | serde = '1.0' 24 | 25 | [features] 26 | default = ['std'] 27 | std = [ 28 | 'account-set/std', 29 | 'frame-support/std', 30 | 'frame-system/std', 31 | 'parity-scale-codec/std', 32 | 'sp-runtime/std', 33 | ] 34 | -------------------------------------------------------------------------------- /pallets/map-set/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![cfg_attr(not(feature = "std"), no_std)] 2 | #![allow(clippy::unused_unit)] 3 | //! A pallet that implements a storage set on top of a storage map and demonstrates performance 4 | //! tradeoffs when using vec sets. 5 | 6 | use account_set::AccountSet; 7 | use frame_support::storage::IterableStorageMap; 8 | use sp_std::collections::btree_set::BTreeSet; 9 | 10 | #[cfg(test)] 11 | mod tests; 12 | 13 | pub use pallet::*; 14 | 15 | #[frame_support::pallet] 16 | pub mod pallet { 17 | use frame_support::{dispatch::DispatchResultWithPostInfo, pallet_prelude::*}; 18 | use frame_system::pallet_prelude::*; 19 | 20 | /// A maximum number of members. When membership reaches this number, no new members may join. 21 | pub const MAX_MEMBERS: u32 = 16; 22 | 23 | #[pallet::config] 24 | pub trait Config: frame_system::Config { 25 | /// The overarching event type. 26 | type Event: From> + IsType<::Event>; 27 | } 28 | 29 | #[pallet::storage] 30 | #[pallet::getter(fn members)] 31 | pub(super) type Members = 32 | StorageMap<_, Blake2_128Concat, T::AccountId, (), ValueQuery>; 33 | 34 | #[pallet::storage] 35 | pub(super) type MemberCount = StorageValue<_, u32, ValueQuery>; 36 | 37 | #[pallet::hooks] 38 | impl Hooks> for Pallet {} 39 | 40 | #[pallet::pallet] 41 | #[pallet::generate_store(pub(super) trait Store)] 42 | pub struct Pallet(PhantomData); 43 | 44 | #[pallet::event] 45 | #[pallet::metadata(T::AccountId = "AccountId")] 46 | #[pallet::generate_deposit(pub(super) fn deposit_event)] 47 | pub enum Event { 48 | /// Added a member 49 | MemberAdded(T::AccountId), 50 | /// Removed a member 51 | MemberRemoved(T::AccountId), 52 | } 53 | 54 | #[pallet::error] 55 | pub enum Error { 56 | /// Cannot join as a member because you are already a member 57 | AlreadyMember, 58 | /// Cannot give up membership because you are not currently a member 59 | NotMember, 60 | /// Cannot add another member because the limit is already reached 61 | MembershipLimitReached, 62 | } 63 | 64 | #[pallet::call] 65 | impl Pallet { 66 | /// Adds a member to the membership set 67 | #[pallet::weight(10_000)] 68 | pub fn add_member(origin: OriginFor) -> DispatchResultWithPostInfo { 69 | let new_member = ensure_signed(origin)?; 70 | 71 | let member_count = MemberCount::::get(); 72 | ensure!( 73 | member_count < MAX_MEMBERS, 74 | Error::::MembershipLimitReached 75 | ); 76 | 77 | // We don't want to add duplicate members, so we check whether the potential new 78 | // member is already present in the list. Because the membership is stored as a hash 79 | // map this check is constant time O(1) 80 | ensure!( 81 | !Members::::contains_key(&new_member), 82 | Error::::AlreadyMember 83 | ); 84 | 85 | // Insert the new member and emit the event 86 | Members::::insert(&new_member, ()); 87 | MemberCount::::put(member_count + 1); // overflow check not necessary because of maximum 88 | Self::deposit_event(Event::MemberAdded(new_member)); 89 | Ok(().into()) 90 | } 91 | 92 | /// Removes a member. 93 | #[pallet::weight(10_000)] 94 | pub fn remove_member(origin: OriginFor) -> DispatchResultWithPostInfo { 95 | let old_member = ensure_signed(origin)?; 96 | 97 | ensure!( 98 | Members::::contains_key(&old_member), 99 | Error::::NotMember 100 | ); 101 | 102 | Members::::remove(&old_member); 103 | MemberCount::::mutate(|v| *v -= 1); 104 | Self::deposit_event(Event::MemberRemoved(old_member)); 105 | Ok(().into()) 106 | } 107 | } 108 | } 109 | 110 | impl AccountSet for Module { 111 | type AccountId = T::AccountId; 112 | 113 | fn accounts() -> BTreeSet { 114 | as IterableStorageMap>::iter() 115 | .map(|(acct, _)| acct) 116 | .collect::>() 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /pallets/map-set/src/tests.rs: -------------------------------------------------------------------------------- 1 | use crate::{self as map_set, *}; 2 | use frame_support::{assert_noop, assert_ok, construct_runtime, parameter_types}; 3 | use sp_core::H256; 4 | use sp_io::TestExternalities; 5 | use sp_runtime::{ 6 | testing::Header, 7 | traits::{BlakeTwo256, IdentityLookup}, 8 | }; 9 | 10 | type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; 11 | type Block = frame_system::mocking::MockBlock; 12 | 13 | construct_runtime!( 14 | pub enum TestRuntime where 15 | Block = Block, 16 | NodeBlock = Block, 17 | UncheckedExtrinsic = UncheckedExtrinsic, 18 | { 19 | System: frame_system::{Module, Call, Config, Storage, Event}, 20 | MapSet: map_set::{Module, Call, Storage, Event}, 21 | } 22 | ); 23 | 24 | parameter_types! { 25 | pub const BlockHashCount: u64 = 250; 26 | pub BlockWeights: frame_system::limits::BlockWeights = 27 | frame_system::limits::BlockWeights::simple_max(1024); 28 | } 29 | impl frame_system::Config for TestRuntime { 30 | type BaseCallFilter = (); 31 | type BlockWeights = (); 32 | type BlockLength = (); 33 | type Origin = Origin; 34 | type Index = u64; 35 | type Call = Call; 36 | type BlockNumber = u64; 37 | type Hash = H256; 38 | type Hashing = BlakeTwo256; 39 | type AccountId = u64; 40 | type Lookup = IdentityLookup; 41 | type Header = Header; 42 | type Event = Event; 43 | type BlockHashCount = BlockHashCount; 44 | type DbWeight = (); 45 | type Version = (); 46 | type PalletInfo = PalletInfo; 47 | type AccountData = (); 48 | type OnNewAccount = (); 49 | type OnKilledAccount = (); 50 | type SystemWeightInfo = (); 51 | type SS58Prefix = (); 52 | } 53 | 54 | impl Config for TestRuntime { 55 | type Event = Event; 56 | } 57 | 58 | struct ExternalityBuilder; 59 | 60 | impl ExternalityBuilder { 61 | pub fn build() -> TestExternalities { 62 | let storage = frame_system::GenesisConfig::default() 63 | .build_storage::() 64 | .unwrap(); 65 | let mut ext = TestExternalities::from(storage); 66 | ext.execute_with(|| System::set_block_number(1)); 67 | ext 68 | } 69 | } 70 | 71 | #[test] 72 | fn add_member_works() { 73 | ExternalityBuilder::build().execute_with(|| { 74 | assert_ok!(MapSet::add_member(Origin::signed(1))); 75 | 76 | let expected_event = Event::map_set(map_set::Event::MemberAdded(1)); 77 | 78 | assert_eq!(System::events()[0].event, expected_event,); 79 | 80 | assert!(>::contains_key(1)); 81 | }) 82 | } 83 | 84 | #[test] 85 | fn cant_add_duplicate_members() { 86 | ExternalityBuilder::build().execute_with(|| { 87 | assert_ok!(MapSet::add_member(Origin::signed(1))); 88 | 89 | assert_noop!( 90 | MapSet::add_member(Origin::signed(1)), 91 | Error::::AlreadyMember 92 | ); 93 | }) 94 | } 95 | 96 | #[test] 97 | fn cant_exceed_max_members() { 98 | ExternalityBuilder::build().execute_with(|| { 99 | // Add 16 members, reaching the max 100 | for i in 0..16 { 101 | assert_ok!(MapSet::add_member(Origin::signed(i))); 102 | } 103 | 104 | // Try to add the 17th member exceeding the max 105 | assert_noop!( 106 | MapSet::add_member(Origin::signed(16)), 107 | Error::::MembershipLimitReached 108 | ); 109 | }) 110 | } 111 | 112 | #[test] 113 | fn remove_member_works() { 114 | ExternalityBuilder::build().execute_with(|| { 115 | assert_ok!(MapSet::add_member(Origin::signed(1))); 116 | assert_ok!(MapSet::remove_member(Origin::signed(1))); 117 | 118 | // check correct event emission 119 | let expected_event = Event::map_set(map_set::Event::MemberRemoved(1)); 120 | 121 | assert_eq!(System::events()[1].event, expected_event,); 122 | 123 | // check storage changes 124 | assert!(!>::contains_key(1)); 125 | }) 126 | } 127 | 128 | #[test] 129 | fn remove_member_handles_errors() { 130 | ExternalityBuilder::build().execute_with(|| { 131 | // 2 is NOT previously added as a member 132 | assert_noop!( 133 | MapSet::remove_member(Origin::signed(2)), 134 | Error::::NotMember 135 | ); 136 | }) 137 | } 138 | -------------------------------------------------------------------------------- /pallets/map-set/types.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /pallets/ocw-demo/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "ocw-demo" 3 | version = "2.0.0" 4 | edition = "2018" 5 | authors = ['Substrate DevHub '] 6 | repository = "https://github.com/substrate-developer-hub/recipes/" 7 | description = "A pallet that demonstrates many aspects of offchain workers" 8 | license = "GPL-3.0-or-later" 9 | 10 | [dependencies] 11 | parking_lot = '0.11' 12 | parity-scale-codec = { version = '2.0', default-features = false, features = ['derive'] } 13 | # https://github.com/serde-rs/json/pull/606 14 | serde = { version = '1.0.100', default-features = false, features = ['derive'] } 15 | serde_json = { version = '1.0.45', default-features = false, features = ['alloc'] } 16 | 17 | # Substrate packages 18 | frame-support = { version = '3.0', default-features = false } 19 | frame-system = { version = '3.0', default-features = false } 20 | sp-arithmetic = { version = '3.0', default-features = false } 21 | sp-core = { version = '3.0', default-features = false } 22 | sp-io = { version = '3.0', default-features = false } 23 | sp-runtime = { version = '3.0', default-features = false } 24 | sp-std = { version = '3.0', default-features = false } 25 | sp-keystore = { version = '0.9', optional = true } 26 | 27 | [features] 28 | default = ['std'] 29 | std = [ 30 | 'frame-support/std', 31 | 'frame-system/std', 32 | 'parity-scale-codec/std', 33 | 'sp-keystore', 34 | 'sp-io/std', 35 | 'sp-runtime/std', 36 | 'sp-std/std', 37 | 'sp-arithmetic/std', 38 | 'sp-keystore/std', 39 | ] 40 | -------------------------------------------------------------------------------- /pallets/ocw-demo/types.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /pallets/randomness/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "randomness" 3 | version = "3.0.0" 4 | edition = "2018" 5 | authors = ['Substrate DevHub '] 6 | repository = 'https://github.com/substrate-developer-hub/recipes' 7 | description = "A pallet that demonstrates consuming pseudorandomness from the Randomness Trait" 8 | license = "GPL-3.0-or-later" 9 | 10 | [dependencies] 11 | parity-scale-codec = { version = "2.0", features = ["derive"], default-features = false } 12 | 13 | # Substrate packages 14 | frame-support = { version = '3.0', default-features = false } 15 | frame-system = { version = '3.0', default-features = false } 16 | sp-core = { version = '3.0', default-features = false } 17 | sp-runtime = { version = '3.0', default-features = false } 18 | sp-std = { version = '3.0', default-features = false } 19 | 20 | [dev-dependencies] 21 | pallet-randomness-collective-flip = '3.0' 22 | sp-io = '3.0' 23 | serde = '1.0' 24 | 25 | [features] 26 | default = ['std'] 27 | std = [ 28 | 'frame-support/std', 29 | 'frame-system/std', 30 | 'parity-scale-codec/std', 31 | 'sp-core/std', 32 | 'sp-runtime/std', 33 | ] 34 | -------------------------------------------------------------------------------- /pallets/randomness/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! Generating (insecure) randomness 2 | #![cfg_attr(not(feature = "std"), no_std)] 3 | #![allow(clippy::unused_unit)] 4 | pub use pallet::*; 5 | use parity_scale_codec::Encode; 6 | use sp_std::vec::Vec; 7 | 8 | #[cfg(test)] 9 | mod tests; 10 | 11 | #[frame_support::pallet] 12 | pub mod pallet { 13 | use frame_support::{dispatch::DispatchResultWithPostInfo, pallet_prelude::*}; 14 | use frame_support::{sp_runtime::app_crypto::sp_core::H256, traits::Randomness}; 15 | use frame_system::pallet_prelude::*; 16 | 17 | #[pallet::config] 18 | pub trait Config: frame_system::Config { 19 | type Event: From> + IsType<::Event>; 20 | 21 | /// The pallet doesn't know what the source of randomness is; it can be anything that 22 | /// implements the trait. When installing this pallet in a runtime, you 23 | /// must make sure to give it a randomness source that suits its needs. 24 | type RandomnessSource: Randomness; 25 | } 26 | 27 | #[pallet::event] 28 | #[pallet::generate_deposit(pub (super) fn deposit_event)] 29 | pub enum Event { 30 | /// First element is raw seed, second is using nonce. 31 | RandomnessConsumed(H256, H256), 32 | } 33 | 34 | #[pallet::storage] 35 | #[pallet::getter(fn nonce)] 36 | pub(super) type Nonce = StorageValue<_, u32, ValueQuery>; 37 | 38 | #[pallet::pallet] 39 | #[pallet::generate_store(pub (super) trait Store)] 40 | pub struct Pallet(PhantomData); 41 | 42 | #[pallet::hooks] 43 | impl Hooks> for Pallet {} 44 | 45 | #[pallet::call] 46 | impl Pallet { 47 | /// Grab a random seed and random value from the randomness collective flip pallet 48 | #[pallet::weight(10_000)] 49 | pub fn consume_randomness(origin: OriginFor) -> DispatchResultWithPostInfo { 50 | let _ = ensure_signed(origin)?; 51 | 52 | // Using a subject is recommended to prevent accidental re-use of the seed 53 | // (This does not add security or entropy) 54 | let subject = Self::encode_and_update_nonce(); 55 | 56 | let random_seed = T::RandomnessSource::random_seed(); 57 | let random_result = T::RandomnessSource::random(&subject); 58 | 59 | Self::deposit_event(Event::RandomnessConsumed(random_seed, random_result)); 60 | Ok(().into()) 61 | } 62 | } 63 | } 64 | 65 | impl Pallet { 66 | /// Reads the nonce from storage, increments the stored nonce, and returns 67 | /// the encoded nonce to the caller. 68 | fn encode_and_update_nonce() -> Vec { 69 | let nonce = Nonce::::get(); 70 | Nonce::::put(nonce.wrapping_add(1)); 71 | nonce.encode() 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /pallets/randomness/src/tests.rs: -------------------------------------------------------------------------------- 1 | use crate::{self as randomness, Config, Event as PalletEvent}; 2 | use frame_support::{assert_ok, construct_runtime, parameter_types}; 3 | use sp_core::H256; 4 | use sp_io; 5 | use sp_runtime::{ 6 | testing::Header, 7 | traits::{BlakeTwo256, IdentityLookup}, 8 | }; 9 | 10 | type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; 11 | type Block = frame_system::mocking::MockBlock; 12 | 13 | construct_runtime!( 14 | pub enum TestRuntime where 15 | Block = Block, 16 | NodeBlock = Block, 17 | UncheckedExtrinsic = UncheckedExtrinsic, 18 | { 19 | System: frame_system::{Module, Call, Config, Storage, Event}, 20 | CollectiveFlip: pallet_randomness_collective_flip::{Module, Call, Storage}, 21 | Randomness: randomness::{Module, Call, Storage, Event}, 22 | } 23 | ); 24 | 25 | parameter_types! { 26 | pub const BlockHashCount: u64 = 250; 27 | pub BlockWeights: frame_system::limits::BlockWeights = 28 | frame_system::limits::BlockWeights::simple_max(1024); 29 | } 30 | impl frame_system::Config for TestRuntime { 31 | type BaseCallFilter = (); 32 | type BlockWeights = (); 33 | type BlockLength = (); 34 | type Origin = Origin; 35 | type Index = u64; 36 | type Call = Call; 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 DbWeight = (); 46 | type Version = (); 47 | type PalletInfo = PalletInfo; 48 | type AccountData = (); 49 | type OnNewAccount = (); 50 | type OnKilledAccount = (); 51 | type SystemWeightInfo = (); 52 | type SS58Prefix = (); 53 | } 54 | 55 | impl Config for TestRuntime { 56 | type Event = Event; 57 | type RandomnessSource = CollectiveFlip; 58 | } 59 | 60 | struct ExternalityBuilder; 61 | 62 | impl ExternalityBuilder { 63 | pub fn build() -> sp_io::TestExternalities { 64 | let storage = frame_system::GenesisConfig::default() 65 | .build_storage::() 66 | .unwrap(); 67 | let mut ext = sp_io::TestExternalities::from(storage); 68 | ext.execute_with(|| System::set_block_number(1)); 69 | ext 70 | } 71 | } 72 | 73 | #[test] 74 | fn generate_works() { 75 | ExternalityBuilder::build().execute_with(|| { 76 | assert_ok!(Randomness::consume_randomness(Origin::signed(1))); 77 | 78 | // Check for the eventx 79 | let expected_event = 80 | Event::randomness(PalletEvent::RandomnessConsumed(H256::zero(), H256::zero())); 81 | 82 | assert_eq!(System::events()[0].event, expected_event); 83 | }) 84 | } 85 | -------------------------------------------------------------------------------- /pallets/randomness/types.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /pallets/reservable-currency/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "reservable-currency" 3 | version = "3.0.0" 4 | edition = "2018" 5 | authors = ['Substrate DevHub '] 6 | repository = 'https://github.com/substrate-developer-hub/recipes' 7 | description = "A pallet that demonstrates the ReservableCurrency trait" 8 | license = "GPL-3.0-or-later" 9 | 10 | [dependencies] 11 | parity-scale-codec = { version = "2.0", features = ["derive"], default-features = false } 12 | 13 | # Substrate packages 14 | pallet-balances = { version = '3.0', default-features = false } 15 | frame-support = { version = '3.0', default-features = false } 16 | frame-system = { version = '3.0', default-features = false } 17 | sp-runtime = { version = '3.0', default-features = false } 18 | 19 | [dev-dependencies] 20 | sp-core = { version = '3.0', default-features = false } 21 | sp-io = { version = '3.0', default-features = false } 22 | serde = '1.0' 23 | 24 | [features] 25 | default = ['std'] 26 | std = [ 27 | 'pallet-balances/std', 28 | 'frame-support/std', 29 | 'frame-system/std', 30 | 'parity-scale-codec/std', 31 | 'sp-runtime/std', 32 | ] 33 | -------------------------------------------------------------------------------- /pallets/reservable-currency/types.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /pallets/ringbuffer-queue/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "ringbuffer-queue" 3 | version = "3.0.0" 4 | edition = "2018" 5 | authors = ['Substrate DevHub '] 6 | repository = 'https://github.com/substrate-developer-hub/recipes' 7 | description = "A pallet that demonstrates a ringbuffer queue built on top of Substrate's storage" 8 | license = "GPL-3.0-or-later" 9 | 10 | [dependencies] 11 | codec = { package = 'parity-scale-codec', default-features = false, features = ['derive'], version = '2.0' } 12 | 13 | # Substrate packages 14 | frame-support = { version = '3.0', default-features = false } 15 | frame-system = { version = '3.0', default-features = false } 16 | sp-std = { version = '3.0', default-features = false } 17 | 18 | [dev-dependencies] 19 | serde = '1.0' 20 | sp-runtime = '3.0' 21 | sp-core = '3.0' 22 | sp-io = '3.0' 23 | 24 | [features] 25 | default = ['std'] 26 | std = [ 27 | 'codec/std', 28 | 'frame-support/std', 29 | 'frame-system/std', 30 | ] 31 | -------------------------------------------------------------------------------- /pallets/ringbuffer-queue/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! A pallet that demonstrates the Transient Storage Adapter pattern through 2 | //! the concrete example of a ringbuffer queue 3 | 4 | #![cfg_attr(not(feature = "std"), no_std)] 5 | #![allow(clippy::unused_unit)] 6 | use sp_std::prelude::*; 7 | 8 | mod ringbuffer; 9 | 10 | use ringbuffer::{RingBufferTrait, RingBufferTransient}; 11 | 12 | pub use pallet::*; 13 | 14 | #[cfg(test)] 15 | mod tests; 16 | 17 | #[frame_support::pallet] 18 | pub mod pallet { 19 | use frame_support::{dispatch::DispatchResultWithPostInfo, pallet_prelude::*}; 20 | use frame_system::pallet_prelude::*; 21 | use sp_std::vec::Vec; 22 | type BufferIndex = u8; 23 | 24 | #[pallet::config] 25 | pub trait Config: frame_system::Config { 26 | /// The overarching event type. 27 | type Event: From> + IsType<::Event>; 28 | } 29 | 30 | #[derive(Encode, Decode, Default, Clone, PartialEq, Eq)] 31 | #[cfg_attr(feature = "std", derive(Debug))] 32 | pub struct ValueStruct { 33 | pub integer: i32, 34 | pub boolean: bool, 35 | } 36 | 37 | #[pallet::storage] 38 | #[pallet::getter(fn get_value)] 39 | pub(super) type BufferMap = 40 | StorageMap<_, Blake2_128Concat, BufferIndex, ValueStruct, ValueQuery>; 41 | 42 | #[pallet::type_value] 43 | pub(super) fn BufferIndexDefaultValue() -> (BufferIndex, BufferIndex) { 44 | (0, 0) 45 | } 46 | 47 | #[pallet::storage] 48 | #[pallet::getter(fn range)] 49 | pub(super) type BufferRange = 50 | StorageValue<_, (BufferIndex, BufferIndex), ValueQuery, BufferIndexDefaultValue>; 51 | 52 | #[pallet::event] 53 | #[pallet::generate_deposit(pub (super) fn deposit_event)] 54 | pub enum Event { 55 | Popped(i32, bool), 56 | DummyEvent(T::AccountId), 57 | } 58 | 59 | #[pallet::pallet] 60 | #[pallet::generate_store(pub (super) trait Store)] 61 | pub struct Pallet(PhantomData); 62 | 63 | #[pallet::hooks] 64 | impl Hooks> for Pallet {} 65 | 66 | #[pallet::call] 67 | impl Pallet { 68 | /// Add an item to the queue 69 | #[pallet::weight(10_000)] 70 | pub fn add_to_queue( 71 | origin: OriginFor, 72 | integer: i32, 73 | boolean: bool, 74 | ) -> DispatchResultWithPostInfo { 75 | // only a user can push into the queue 76 | let _user = ensure_signed(origin)?; 77 | 78 | let mut queue = Self::queue_transient(); 79 | queue.push(ValueStruct { integer, boolean }); 80 | 81 | Ok(().into()) 82 | } 83 | 84 | /// Add several items to the queue 85 | #[pallet::weight(10_000)] 86 | pub fn add_multiple( 87 | origin: OriginFor, 88 | integers: Vec, 89 | boolean: bool, 90 | ) -> DispatchResultWithPostInfo { 91 | // only a user can push into the queue 92 | let _user = ensure_signed(origin)?; 93 | 94 | let mut queue = Self::queue_transient(); 95 | for integer in integers { 96 | queue.push(ValueStruct { integer, boolean }); 97 | } 98 | 99 | Ok(().into()) 100 | } 101 | 102 | /// Remove and return an item from the queue 103 | #[pallet::weight(10_000)] 104 | pub fn pop_from_queue(origin: OriginFor) -> DispatchResultWithPostInfo { 105 | // only a user can pop from the queue 106 | let _user = ensure_signed(origin)?; 107 | 108 | let mut queue = Self::queue_transient(); 109 | if let Some(ValueStruct { integer, boolean }) = queue.pop() { 110 | Self::deposit_event(Event::Popped(integer, boolean)); 111 | } 112 | 113 | Ok(().into()) 114 | } 115 | } 116 | } 117 | 118 | impl Pallet { 119 | /// Constructor function so we don't have to specify the types every time. 120 | /// 121 | /// Constructs a ringbuffer transient and returns it as a boxed trait object. 122 | /// See [this part of the Rust book](https://doc.rust-lang.org/book/ch17-02-trait-objects.html#trait-objects-perform-dynamic-dispatch) 123 | fn queue_transient() -> Box> { 124 | Box::new(RingBufferTransient::< 125 | ValueStruct, 126 | ::BufferRange, 127 | ::BufferMap, 128 | u8, 129 | >::new()) 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /pallets/ringbuffer-queue/src/tests.rs: -------------------------------------------------------------------------------- 1 | use crate::{self as ringbuffer_queue, Config, ValueStruct}; 2 | use frame_support::{assert_ok, construct_runtime, parameter_types}; 3 | use sp_core::H256; 4 | use sp_io::TestExternalities; 5 | use sp_runtime::{ 6 | testing::Header, 7 | traits::{BlakeTwo256, IdentityLookup}, 8 | }; 9 | 10 | type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; 11 | type Block = frame_system::mocking::MockBlock; 12 | 13 | construct_runtime!( 14 | pub enum TestRuntime where 15 | Block = Block, 16 | NodeBlock = Block, 17 | UncheckedExtrinsic = UncheckedExtrinsic, 18 | { 19 | System: frame_system::{Module, Call, Config, Storage, Event}, 20 | RingBuffer: ringbuffer_queue::{Module, Call, Event}, 21 | } 22 | ); 23 | 24 | parameter_types! { 25 | pub const BlockHashCount: u64 = 250; 26 | pub BlockWeights: frame_system::limits::BlockWeights = 27 | frame_system::limits::BlockWeights::simple_max(1024); 28 | } 29 | impl frame_system::Config for TestRuntime { 30 | type BaseCallFilter = (); 31 | type BlockWeights = (); 32 | type BlockLength = (); 33 | type Origin = Origin; 34 | type Index = u64; 35 | type Call = Call; 36 | type BlockNumber = u64; 37 | type Hash = H256; 38 | type Hashing = BlakeTwo256; 39 | type AccountId = u64; 40 | type Lookup = IdentityLookup; 41 | type Header = Header; 42 | type Event = Event; 43 | type BlockHashCount = BlockHashCount; 44 | type DbWeight = (); 45 | type Version = (); 46 | type PalletInfo = PalletInfo; 47 | type AccountData = (); 48 | type OnNewAccount = (); 49 | type OnKilledAccount = (); 50 | type SystemWeightInfo = (); 51 | type SS58Prefix = (); 52 | } 53 | 54 | impl Config for TestRuntime { 55 | type Event = Event; 56 | } 57 | 58 | struct ExternalityBuilder; 59 | 60 | impl ExternalityBuilder { 61 | pub fn build() -> TestExternalities { 62 | let storage = frame_system::GenesisConfig::default() 63 | .build_storage::() 64 | .unwrap(); 65 | let mut ext = TestExternalities::from(storage); 66 | ext.execute_with(|| System::set_block_number(1)); 67 | ext 68 | } 69 | } 70 | 71 | #[test] 72 | fn add_to_queue_works() { 73 | ExternalityBuilder::build().execute_with(|| { 74 | assert_ok!(RingBuffer::add_to_queue(Origin::signed(1), 1, true)); 75 | assert_eq!( 76 | RingBuffer::get_value(0), 77 | ValueStruct { 78 | integer: 1, 79 | boolean: true 80 | } 81 | ); 82 | assert_eq!(RingBuffer::range(), (0, 1)); 83 | }) 84 | } 85 | 86 | #[test] 87 | fn add_multiple_works() { 88 | ExternalityBuilder::build().execute_with(|| { 89 | assert_ok!(RingBuffer::add_multiple( 90 | Origin::signed(1), 91 | vec![1, 2, 3], 92 | true 93 | )); 94 | assert_eq!( 95 | RingBuffer::get_value(0), 96 | ValueStruct { 97 | integer: 1, 98 | boolean: true 99 | } 100 | ); 101 | assert_eq!(RingBuffer::range(), (0, 3)); 102 | }) 103 | } 104 | 105 | #[test] 106 | fn pop_works() { 107 | ExternalityBuilder::build().execute_with(|| { 108 | assert_ok!(RingBuffer::add_to_queue(Origin::signed(1), 1, true)); 109 | assert_eq!( 110 | RingBuffer::get_value(0), 111 | ValueStruct { 112 | integer: 1, 113 | boolean: true 114 | } 115 | ); 116 | assert_eq!(RingBuffer::range(), (0, 1)); 117 | 118 | assert_ok!(RingBuffer::pop_from_queue(Origin::signed(1))); 119 | assert_eq!(RingBuffer::range(), (1, 1)); 120 | 121 | let expected_event = Event::ringbuffer_queue(ringbuffer_queue::Event::Popped(1, true)); 122 | 123 | assert_eq!(System::events()[0].event, expected_event,); 124 | }) 125 | } 126 | -------------------------------------------------------------------------------- /pallets/ringbuffer-queue/types.json: -------------------------------------------------------------------------------- 1 | { 2 | "ValueStruct": { 3 | "integer": "i32", 4 | "boolean": "bool" 5 | }, 6 | "BufferIndex": "u8" 7 | } 8 | -------------------------------------------------------------------------------- /pallets/simple-crowdfund/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "simple-crowdfund" 3 | version = "3.0.0" 4 | edition = "2018" 5 | authors = ['Substrate DevHub '] 6 | repository = 'https://github.com/substrate-developer-hub/recipes' 7 | description = "A pallet that implements a crowdfund and demonstrates using child storage tries" 8 | license = "GPL-3.0-or-later" 9 | 10 | [dependencies] 11 | parity-scale-codec = { version = "2.0", features = ["derive"], default-features = false } 12 | serde = '1.0' 13 | 14 | # Substrate packages 15 | pallet-balances = { version = '3.0', default-features = false } 16 | frame-support = { version = '3.0', default-features = false } 17 | frame-system = { version = '3.0', default-features = false } 18 | sp-core = { version = '3.0', default-features = false } 19 | sp-runtime = { version = '3.0', default-features = false } 20 | sp-std = { version = '3.0', default-features = false } 21 | sp-storage = { version = '3.0', default-features = false } 22 | 23 | [dev-dependencies] 24 | sp-core = '3.0' 25 | sp-io = '3.0' 26 | 27 | [features] 28 | default = ['std'] 29 | std = [ 30 | 'pallet-balances/std', 31 | 'frame-support/std', 32 | 'frame-system/std', 33 | 'parity-scale-codec/std', 34 | 'sp-core/std', 35 | 'sp-runtime/std', 36 | 'sp-std/std', 37 | 'sp-storage/std', 38 | ] 39 | -------------------------------------------------------------------------------- /pallets/simple-crowdfund/types.json: -------------------------------------------------------------------------------- 1 | { 2 | "AccountIdOf": "AccountId", 3 | "BalanceOf": "Balance", 4 | "FundInfoOf": "FundInfo", 5 | "FundInfo": { 6 | "beneficiary": "AccountId", 7 | "deposit": "Balance", 8 | "raised": "Balance", 9 | "end": "BlockNumber", 10 | "goal": "Balance" 11 | }, 12 | "FundIndex": "u32" 13 | } 14 | -------------------------------------------------------------------------------- /pallets/simple-event/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "simple-event" 3 | version = "3.0.0" 4 | edition = "2018" 5 | authors = ['Substrate DevHub '] 6 | repository = 'https://github.com/substrate-developer-hub/recipes' 7 | description = "A pallet that emits simple events that do not encapsulate generic data types" 8 | license = "GPL-3.0-or-later" 9 | 10 | [package.metadata.docs.rs] 11 | targets = ['x86_64-unknown-linux-gnu'] 12 | 13 | [dependencies] 14 | frame-support = { default-features = false, version = '3.0.0' } 15 | frame-system = { default-features = false, version = '3.0.0' } 16 | 17 | # Substrate packages 18 | sp-runtime = { version = '3.0', default-features = false } 19 | 20 | [dependencies.codec] 21 | default-features = false 22 | features = ['derive'] 23 | package = 'parity-scale-codec' 24 | version = '2.0.0' 25 | 26 | [dev-dependencies] 27 | serde = { version = "1.0.119" } 28 | sp-core = { default-features = false, version = '3.0.0' } 29 | sp-io = { default-features = false, version = '3.0.0' } 30 | sp-runtime = { default-features = false, version = '3.0.0' } 31 | 32 | [features] 33 | default = ['std'] 34 | std = [ 35 | 'frame-support/std', 36 | 'frame-system/std', 37 | 'sp-runtime/std', 38 | ] 39 | -------------------------------------------------------------------------------- /pallets/simple-event/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![cfg_attr(not(feature = "std"), no_std)] 2 | #![allow(clippy::unused_unit)] 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 tests; 10 | 11 | #[frame_support::pallet] 12 | pub mod pallet { 13 | use frame_support::{dispatch::DispatchResultWithPostInfo, pallet_prelude::*}; 14 | use frame_system::pallet_prelude::*; 15 | 16 | /// Configure the pallet by specifying the parameters and types on which it depends. 17 | #[pallet::config] 18 | pub trait Config: frame_system::Config { 19 | /// Because this pallet emits events, it depends on the runtime's definition of an event. 20 | type Event: From> + IsType<::Event>; 21 | } 22 | 23 | // 2. Declaration of the Pallet type 24 | // This is a placeholder to implement traits and methods. 25 | #[pallet::pallet] 26 | #[pallet::generate_store(pub(super) trait Store)] 27 | pub struct Pallet(PhantomData); 28 | 29 | // Pallets use events to inform users when important changes are made. 30 | // https://substrate.dev/docs/en/knowledgebase/runtime/events 31 | #[pallet::event] 32 | #[pallet::metadata(T::AccountId = "AccountId")] 33 | #[pallet::generate_deposit(pub(super) fn deposit_event)] 34 | pub enum Event { 35 | /// Event documentation should end with an array that provides descriptive names for event 36 | /// parameters. [something, who] 37 | EmitInput(u32), 38 | } 39 | 40 | #[pallet::hooks] 41 | impl Hooks> for Pallet {} 42 | 43 | // Dispatchable functions allows users to interact with the pallet and invoke state changes. 44 | // These functions materialize as "extrinsics", which are often compared to transactions. 45 | // Dispatchable functions must be annotated with a weight and must return a DispatchResult. 46 | #[pallet::call] 47 | impl Pallet { 48 | /// An example dispatchable that takes a singles value as a parameter, writes the value to 49 | /// storage and emits an event. This function must be dispatched by a signed extrinsic. 50 | #[pallet::weight(10_000 + T::DbWeight::get().writes(1))] 51 | pub fn do_something(origin: OriginFor, input: u32) -> DispatchResultWithPostInfo { 52 | let _ = ensure_signed(origin)?; 53 | 54 | // In practice, you could do some processing with the input here. 55 | let new_number = input; 56 | 57 | // emit event 58 | Self::deposit_event(Event::EmitInput(new_number)); 59 | Ok(().into()) 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /pallets/simple-event/src/tests.rs: -------------------------------------------------------------------------------- 1 | use crate as simple_event; 2 | use frame_support::{assert_ok, parameter_types}; 3 | use sp_core::H256; 4 | 5 | use sp_io::TestExternalities; 6 | 7 | use sp_runtime::{ 8 | testing::Header, 9 | traits::{BlakeTwo256, IdentityLookup}, 10 | }; 11 | 12 | use frame_system as system; 13 | use frame_system::{EventRecord, Phase}; 14 | 15 | type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; 16 | type Block = frame_system::mocking::MockBlock; 17 | 18 | // Configure a mock runtime to test the pallet. 19 | frame_support::construct_runtime!( 20 | pub enum Test where 21 | Block = Block, 22 | NodeBlock = Block, 23 | UncheckedExtrinsic = UncheckedExtrinsic, 24 | { 25 | System: frame_system::{Module, Call, Config, Storage, Event}, 26 | SimpleEvent: simple_event::{Module, Call, Storage, Event}, 27 | } 28 | ); 29 | 30 | parameter_types! { 31 | pub const BlockHashCount: u64 = 250; 32 | pub const SS58Prefix: u8 = 42; 33 | } 34 | 35 | impl system::Config for Test { 36 | type BaseCallFilter = (); 37 | type BlockWeights = (); 38 | type BlockLength = (); 39 | type DbWeight = (); 40 | type Origin = Origin; 41 | type Call = Call; 42 | type Index = u64; 43 | type BlockNumber = u64; 44 | type Hash = H256; 45 | type Hashing = BlakeTwo256; 46 | type AccountId = u64; 47 | type Lookup = IdentityLookup; 48 | type Header = Header; 49 | type Event = Event; 50 | type BlockHashCount = BlockHashCount; 51 | type Version = (); 52 | type PalletInfo = PalletInfo; 53 | type AccountData = (); 54 | type OnNewAccount = (); 55 | type OnKilledAccount = (); 56 | type SystemWeightInfo = (); 57 | type SS58Prefix = SS58Prefix; 58 | } 59 | 60 | impl simple_event::Config for Test { 61 | type Event = Event; 62 | } 63 | 64 | struct ExternalityBuilder; 65 | 66 | impl ExternalityBuilder { 67 | pub fn build() -> TestExternalities { 68 | let storage = frame_system::GenesisConfig::default() 69 | .build_storage::() 70 | .unwrap(); 71 | let mut ext = TestExternalities::from(storage); 72 | ext.execute_with(|| System::set_block_number(1)); 73 | ext 74 | } 75 | } 76 | 77 | #[test] 78 | fn test() { 79 | ExternalityBuilder::build().execute_with(|| { 80 | assert_ok!(SimpleEvent::do_something(Origin::signed(1), 32)); 81 | 82 | assert_eq!( 83 | System::events(), 84 | vec![EventRecord { 85 | phase: Phase::Initialization, 86 | event: Event::simple_event(simple_event::Event::EmitInput(32)), 87 | topics: vec![], 88 | }] 89 | ); 90 | }) 91 | } 92 | -------------------------------------------------------------------------------- /pallets/simple-event/types.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /pallets/simple-map/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "simple-map" 3 | version = "3.0.0" 4 | edition = "2018" 5 | authors = ['Substrate DevHub '] 6 | repository = 'https://github.com/substrate-developer-hub/recipes' 7 | description = "A pallet that demonstrates Substrate's storage maps" 8 | license = "GPL-3.0-or-later" 9 | 10 | [dependencies] 11 | parity-scale-codec = { default-features = false, features = ['derive'], version = '2.0' } 12 | 13 | # Substrate packages 14 | frame-support = { version = '3.0', default-features = false } 15 | frame-system = { version = '3.0', default-features = false } 16 | 17 | [dev-dependencies] 18 | serde = '1.0' 19 | sp-core = '3.0' 20 | sp-io = '3.0' 21 | sp-runtime = '3.0' 22 | 23 | [features] 24 | default = ['std'] 25 | std = [ 26 | 'frame-support/std', 27 | 'frame-system/std', 28 | 'parity-scale-codec/std', 29 | ] 30 | -------------------------------------------------------------------------------- /pallets/simple-map/types.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /pallets/storage-cache/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "storage-cache" 3 | version = "3.0.0" 4 | edition = "2018" 5 | authors = ['Substrate DevHub '] 6 | repository = 'https://github.com/substrate-developer-hub/recipes' 7 | description = "A pallet that demonstrates caching values read from storage to improve performance" 8 | license = "GPL-3.0-or-later" 9 | 10 | [dependencies] 11 | parity-scale-codec = { default-features = false, features = ['derive'], version = '2.0' } 12 | 13 | # Substrate packages 14 | frame-support = { package = 'frame-support', version = '3.0', default-features = false } 15 | frame-system = { package = 'frame-system', version = '3.0', default-features = false } 16 | sp-runtime = { version = '3.0', default-features = false } 17 | sp-std = { version = '3.0', default-features = false } 18 | 19 | [dev-dependencies] 20 | serde = '1.0' 21 | sp-core = '3.0' 22 | sp-io = '3.0' 23 | 24 | [features] 25 | default = ['std'] 26 | std = [ 27 | 'frame-support/std', 28 | 'frame-system/std', 29 | 'parity-scale-codec/std', 30 | 'sp-runtime/std', 31 | ] 32 | -------------------------------------------------------------------------------- /pallets/storage-cache/types.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /pallets/struct-storage/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "struct-storage" 3 | version = "3.0.0" 4 | edition = "2018" 5 | authors = ['Substrate DevHub '] 6 | repository = 'https://github.com/substrate-developer-hub/recipes' 7 | description = "A pallet that demonstrates storing custom structs in Substrate storage" 8 | license = "GPL-3.0-or-later" 9 | 10 | [dependencies] 11 | parity-scale-codec = { version = "2.0", features = ["derive"], default-features = false } 12 | 13 | # Substrate packages 14 | pallet-balances = { version = '3.0', default-features = false } 15 | frame-support = { version = '3.0', default-features = false } 16 | frame-system = { version = '3.0', default-features = false } 17 | sp-runtime = { version = '3.0', default-features = false } 18 | 19 | [dev-dependencies] 20 | serde = '1.0' 21 | sp-core = '3.0' 22 | sp-io = '3.0' 23 | 24 | [features] 25 | default = ['std'] 26 | std = [ 27 | 'pallet-balances/std', 28 | 'frame-support/std', 29 | 'frame-system/std', 30 | 'parity-scale-codec/std', 31 | 'sp-runtime/std', 32 | ] 33 | -------------------------------------------------------------------------------- /pallets/struct-storage/types.json: -------------------------------------------------------------------------------- 1 | { 2 | "InnerThing": { 3 | "number": "u32", 4 | "hash": "Hash", 5 | "balance": "Balance" 6 | }, 7 | "SuperThing": { 8 | "super_number": "u32", 9 | "inner_thing": "InnerThing" 10 | }, 11 | "InnerThingOf": "InnerThing" 12 | } 13 | -------------------------------------------------------------------------------- /pallets/sum-storage/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "sum-storage" 3 | version = "3.0.0" 4 | edition = "2018" 5 | authors = ['Substrate DevHub '] 6 | repository = "https://github.com/substrate-developer-hub/recipes" 7 | description = "A pallet with two storage items whose sum is exposed via a custom runtime API" 8 | license = "GPL-3.0-or-later" 9 | 10 | [dependencies] 11 | parity-scale-codec = { version = "2.0", default-features = false, features = ["derive"] } 12 | 13 | # Substrate packages 14 | frame-support = { version = '3.0', default-features = false} 15 | frame-system = { version = '3.0', default-features = false} 16 | sp-runtime = { version = '3.0', default-features = false} 17 | sp-std = { version = '3.0', default-features = false} 18 | 19 | [dev-dependencies] 20 | serde = '1.0' 21 | sp-core = '3.0' 22 | sp-io = '3.0' 23 | 24 | [features] 25 | default = ["std"] 26 | std = [ 27 | "parity-scale-codec/std", 28 | "sp-std/std", 29 | "sp-runtime/std", 30 | "frame-support/std", 31 | "frame-system/std", 32 | ] 33 | -------------------------------------------------------------------------------- /pallets/sum-storage/rpc/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "sum-storage-rpc" 3 | version = "2.0.0" 4 | edition = "2018" 5 | authors = ['Substrate DevHub '] 6 | repository = 'https://github.com/substrate-developer-hub/recipes' 7 | description = "A pallet that demonstrates simple RPC for summing numbers" 8 | license = "GPL-3.0-or-later" 9 | 10 | [dependencies] 11 | codec = { package = "parity-scale-codec", version = "1.3.0" } 12 | jsonrpc-core = "15.0" 13 | jsonrpc-core-client = "15.0" 14 | jsonrpc-derive = "15.0" 15 | serde = { version = "1.0", features = ["derive"], optional = true } 16 | 17 | # Substrate packages 18 | 19 | sp-api = { version = '3.0', default-features = false } 20 | sp-blockchain = { version = '3.0', default-features = false} 21 | sp-rpc = { version = '3.0', default-features = false} 22 | sp-runtime = { version = '3.0', default-features = false} 23 | 24 | # local packages 25 | 26 | sum-storage-runtime-api = { version = "2.0.0", path = "../runtime-api", default-features = false } 27 | 28 | [features] 29 | default = ["std"] 30 | std = [ 31 | "serde", 32 | "sp-api/std", 33 | "sp-runtime/std", 34 | "sum-storage-runtime-api/std" 35 | ] 36 | -------------------------------------------------------------------------------- /pallets/sum-storage/rpc/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! RPC interface for the transaction payment module. 2 | 3 | use jsonrpc_core::{Error as RpcError, ErrorCode, Result}; 4 | use jsonrpc_derive::rpc; 5 | use sp_api::ProvideRuntimeApi; 6 | use sp_blockchain::HeaderBackend; 7 | use sp_runtime::{generic::BlockId, traits::Block as BlockT}; 8 | use std::sync::Arc; 9 | use sum_storage_runtime_api::SumStorageApi as SumStorageRuntimeApi; 10 | 11 | #[rpc] 12 | pub trait SumStorageApi { 13 | #[rpc(name = "sumStorage_getSum")] 14 | fn get_sum(&self, at: Option) -> Result; 15 | } 16 | 17 | /// A struct that implements the `SumStorageApi`. 18 | pub struct SumStorage { 19 | // If you have more generics, no need to SumStorage 20 | // just use a tuple like SumStorage 21 | client: Arc, 22 | _marker: std::marker::PhantomData, 23 | } 24 | 25 | impl SumStorage { 26 | /// Create new `SumStorage` instance with the given reference to the client. 27 | pub fn new(client: Arc) -> Self { 28 | Self { 29 | client, 30 | _marker: Default::default(), 31 | } 32 | } 33 | } 34 | 35 | /// Error type of this RPC api. 36 | // pub enum Error { 37 | // /// The transaction was not decodable. 38 | // DecodeError, 39 | // /// The call to runtime failed. 40 | // RuntimeError, 41 | // } 42 | // 43 | // impl From for i64 { 44 | // fn from(e: Error) -> i64 { 45 | // match e { 46 | // Error::RuntimeError => 1, 47 | // Error::DecodeError => 2, 48 | // } 49 | // } 50 | // } 51 | 52 | impl SumStorageApi<::Hash> for SumStorage 53 | where 54 | Block: BlockT, 55 | C: Send + Sync + 'static, 56 | C: ProvideRuntimeApi, 57 | C: HeaderBackend, 58 | C::Api: SumStorageRuntimeApi, 59 | { 60 | fn get_sum(&self, at: Option<::Hash>) -> Result { 61 | let api = self.client.runtime_api(); 62 | let at = BlockId::hash(at.unwrap_or_else(|| 63 | // If the block hash is not supplied assume the best block. 64 | self.client.info().best_hash)); 65 | 66 | let runtime_api_result = api.get_sum(&at); 67 | runtime_api_result.map_err(|e| RpcError { 68 | code: ErrorCode::ServerError(9876), // No real reason for this value 69 | message: "Something wrong".into(), 70 | data: Some(format!("{:?}", e).into()), 71 | }) 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /pallets/sum-storage/runtime-api/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "sum-storage-runtime-api" 3 | version = "2.0.0" 4 | authors = ['Substrate DevHub '] 5 | edition = "2018" 6 | license = "GPL-3.0-or-later" 7 | 8 | [dependencies] 9 | sp-api = { version = '3.0', default-features = false} 10 | 11 | [dev-dependencies] 12 | serde_json = "1.0" 13 | 14 | [features] 15 | default = ["std"] 16 | std = [ 17 | "sp-api/std", 18 | ] 19 | -------------------------------------------------------------------------------- /pallets/sum-storage/runtime-api/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![cfg_attr(not(feature = "std"), no_std)] 2 | #![allow(clippy::too_many_arguments)] 3 | #![allow(clippy::unnecessary_mut_passed)] 4 | 5 | // Here we declare the runtime API. It is implemented it the `impl` block in 6 | // runtime amalgamator file (the `runtime/src/lib.rs`) 7 | sp_api::decl_runtime_apis! { 8 | pub trait SumStorageApi { 9 | fn get_sum() -> u32; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /pallets/sum-storage/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![cfg_attr(not(feature = "std"), no_std)] 2 | #![allow(clippy::unused_unit)] 3 | //! A simple pallet with two storage values. The pallet itself does not teach any new concepts. 4 | //! Rather we use this pallet as demonstration case as we demonstrate custom runtime APIs. 5 | //! This pallet supports a runtime API which will allow querying the runtime for the sum of 6 | //! the two storage items. 7 | 8 | pub use pallet::*; 9 | 10 | #[cfg(test)] 11 | mod tests; 12 | #[frame_support::pallet] 13 | pub mod pallet { 14 | use frame_support::pallet_prelude::*; 15 | use frame_system::pallet_prelude::*; 16 | 17 | /// The module's configuration trait. 18 | #[pallet::config] 19 | pub trait Config: frame_system::Config { 20 | /// The overarching event type. 21 | type Event: From> + IsType<::Event>; 22 | } 23 | 24 | #[pallet::event] 25 | #[pallet::generate_deposit(pub(super) fn deposit_event)] 26 | #[pallet::metadata(u32 = "Metadata")] 27 | pub enum Event { 28 | ValueSet(u32, u32), 29 | } 30 | 31 | #[pallet::pallet] 32 | #[pallet::generate_store(pub(super) trait Store)] 33 | pub struct Pallet(_); 34 | 35 | #[pallet::storage] 36 | #[pallet::getter(fn thing1)] 37 | pub type Thing1 = StorageValue<_, u32, ValueQuery>; 38 | 39 | #[pallet::storage] 40 | #[pallet::getter(fn thing2)] 41 | pub type Thing2 = StorageValue<_, u32, ValueQuery>; 42 | 43 | #[pallet::hooks] 44 | impl Hooks> for Pallet {} 45 | 46 | // The module's dispatchable functions. 47 | #[pallet::call] 48 | impl Pallet { 49 | /// Sets the first simple storage value 50 | #[pallet::weight(10_000)] 51 | pub fn set_thing_1(origin: OriginFor, val: u32) -> DispatchResultWithPostInfo { 52 | let _ = ensure_signed(origin)?; 53 | 54 | Thing1::::put(val); 55 | 56 | Self::deposit_event(Event::ValueSet(1, val)); 57 | Ok(().into()) 58 | } 59 | 60 | /// Sets the second stored value 61 | #[pallet::weight(10_000)] 62 | pub fn set_thing_2(origin: OriginFor, val: u32) -> DispatchResultWithPostInfo { 63 | let _ = ensure_signed(origin)?; 64 | 65 | Thing2::::put(val); 66 | 67 | Self::deposit_event(Event::ValueSet(2, val)); 68 | Ok(().into()) 69 | } 70 | } 71 | } 72 | 73 | impl Pallet { 74 | pub fn get_sum() -> u32 { 75 | Thing1::::get() + Thing2::::get() 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /pallets/sum-storage/src/tests.rs: -------------------------------------------------------------------------------- 1 | use crate::{self as sum_storage, Config}; 2 | 3 | use frame_support::{assert_ok, construct_runtime, parameter_types}; 4 | use sp_core::H256; 5 | use sp_runtime::{ 6 | testing::Header, 7 | traits::{BlakeTwo256, IdentityLookup}, 8 | }; 9 | 10 | type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; 11 | type Block = frame_system::mocking::MockBlock; 12 | 13 | construct_runtime!( 14 | pub enum TestRuntime where 15 | Block = Block, 16 | NodeBlock = Block, 17 | UncheckedExtrinsic = UncheckedExtrinsic, 18 | { 19 | System: frame_system::{Module, Call, Config, Storage, Event}, 20 | SumStorage: sum_storage::{Module, Call, Storage, Event}, 21 | } 22 | ); 23 | 24 | parameter_types! { 25 | pub const BlockHashCount: u64 = 250; 26 | pub BlockWeights: frame_system::limits::BlockWeights = 27 | frame_system::limits::BlockWeights::simple_max(1024); 28 | } 29 | impl frame_system::Config for TestRuntime { 30 | type BaseCallFilter = (); 31 | type BlockWeights = (); 32 | type BlockLength = (); 33 | type Origin = Origin; 34 | type Index = u64; 35 | type Call = Call; 36 | type BlockNumber = u64; 37 | type Hash = H256; 38 | type Hashing = BlakeTwo256; 39 | type AccountId = u64; 40 | type Lookup = IdentityLookup; 41 | type Header = Header; 42 | type Event = Event; 43 | type BlockHashCount = BlockHashCount; 44 | type DbWeight = (); 45 | type Version = (); 46 | type PalletInfo = PalletInfo; 47 | type AccountData = (); 48 | type OnNewAccount = (); 49 | type OnKilledAccount = (); 50 | type SystemWeightInfo = (); 51 | type SS58Prefix = (); 52 | } 53 | 54 | impl Config for TestRuntime { 55 | type Event = Event; 56 | } 57 | 58 | // This function basically just builds a genesis storage key/value store according to 59 | // our desired mockup. 60 | fn new_test_ext() -> sp_io::TestExternalities { 61 | frame_system::GenesisConfig::default() 62 | .build_storage::() 63 | .unwrap() 64 | .into() 65 | } 66 | 67 | #[test] 68 | fn default_sum_zero() { 69 | new_test_ext().execute_with(|| { 70 | assert_eq!(SumStorage::get_sum(), 0); 71 | }); 72 | } 73 | 74 | #[test] 75 | fn sums_thing_one() { 76 | new_test_ext().execute_with(|| { 77 | assert_ok!(SumStorage::set_thing_1(Origin::signed(1), 42)); 78 | assert_eq!(SumStorage::get_sum(), 42); 79 | }); 80 | } 81 | 82 | #[test] 83 | fn sums_thing_two() { 84 | new_test_ext().execute_with(|| { 85 | assert_ok!(SumStorage::set_thing_2(Origin::signed(1), 42)); 86 | assert_eq!(SumStorage::get_sum(), 42); 87 | }); 88 | } 89 | 90 | #[test] 91 | fn sums_both_values() { 92 | new_test_ext().execute_with(|| { 93 | assert_ok!(SumStorage::set_thing_1(Origin::signed(1), 42)); 94 | assert_ok!(SumStorage::set_thing_2(Origin::signed(1), 43)); 95 | assert_eq!(SumStorage::get_sum(), 85); 96 | }); 97 | } 98 | -------------------------------------------------------------------------------- /pallets/sum-storage/types.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /pallets/vec-set/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "vec-set" 3 | version = "3.0.0" 4 | edition = "2018" 5 | repository = 'https://github.com/substrate-developer-hub/recipes' 6 | authors = ['Substrate DevHub '] 7 | description = "A pallet that implements a storage Set on top of a Vec" 8 | license = "GPL-3.0-or-later" 9 | 10 | [dependencies] 11 | parity-scale-codec = { version = "2.0", features = ["derive"], default-features = false } 12 | 13 | # Substrate packages 14 | 15 | frame-support = { version = '3.0', default-features = false } 16 | frame-system = { version = '3.0', default-features = false } 17 | sp-runtime = { version = '3.0', default-features = false } 18 | sp-std = { version = '3.0', default-features = false } 19 | 20 | # local packages 21 | account-set = { path = '../../traits/account-set', default-features = false } 22 | 23 | [dev-dependencies] 24 | sp-core = { version = '3.0', default-features = false } 25 | sp-io = { version = '3.0', default-features = false } 26 | serde = '1.0' 27 | 28 | [features] 29 | default = ['std'] 30 | std = [ 31 | 'account-set/std', 32 | 'frame-support/std', 33 | 'frame-system/std', 34 | 'parity-scale-codec/std', 35 | 'sp-runtime/std', 36 | ] 37 | -------------------------------------------------------------------------------- /pallets/vec-set/src/tests.rs: -------------------------------------------------------------------------------- 1 | use crate::{self as vec_set, Config, Error}; 2 | use frame_support::{assert_noop, assert_ok, construct_runtime, parameter_types}; 3 | use frame_system as system; 4 | use sp_core::H256; 5 | use sp_io::TestExternalities; 6 | use sp_runtime::{ 7 | testing::Header, 8 | traits::{BlakeTwo256, IdentityLookup}, 9 | }; 10 | 11 | type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; 12 | type Block = frame_system::mocking::MockBlock; 13 | 14 | construct_runtime!( 15 | pub enum TestRuntime where 16 | Block = Block, 17 | NodeBlock = Block, 18 | UncheckedExtrinsic = UncheckedExtrinsic, 19 | { 20 | System: frame_system::{Module, Call, Config, Storage, Event}, 21 | VecSet: vec_set::{Module, Call, Storage, Event}, 22 | } 23 | ); 24 | 25 | parameter_types! { 26 | pub const BlockHashCount: u64 = 250; 27 | pub BlockWeights: frame_system::limits::BlockWeights = 28 | frame_system::limits::BlockWeights::simple_max(1024); 29 | } 30 | impl frame_system::Config for TestRuntime { 31 | type BaseCallFilter = (); 32 | type BlockWeights = (); 33 | type BlockLength = (); 34 | type Origin = Origin; 35 | type Index = u64; 36 | type Call = Call; 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 DbWeight = (); 46 | type Version = (); 47 | type PalletInfo = PalletInfo; 48 | type AccountData = (); 49 | type OnNewAccount = (); 50 | type OnKilledAccount = (); 51 | type SystemWeightInfo = (); 52 | type SS58Prefix = (); 53 | } 54 | 55 | impl Config for TestRuntime { 56 | type Event = Event; 57 | } 58 | 59 | struct ExternalityBuilder; 60 | 61 | impl ExternalityBuilder { 62 | pub fn build() -> TestExternalities { 63 | let storage = system::GenesisConfig::default() 64 | .build_storage::() 65 | .unwrap(); 66 | let mut ext = TestExternalities::from(storage); 67 | ext.execute_with(|| System::set_block_number(1)); 68 | ext 69 | } 70 | } 71 | 72 | #[test] 73 | fn add_member_works() { 74 | ExternalityBuilder::build().execute_with(|| { 75 | assert_ok!(VecSet::add_member(Origin::signed(1))); 76 | 77 | let expected_event = Event::vec_set(vec_set::Event::MemberAdded(1)); 78 | 79 | assert_eq!(System::events()[0].event, expected_event,); 80 | 81 | assert_eq!(VecSet::members(), vec![1]); 82 | }) 83 | } 84 | 85 | #[test] 86 | fn cant_add_duplicate_members() { 87 | ExternalityBuilder::build().execute_with(|| { 88 | assert_ok!(VecSet::add_member(Origin::signed(1))); 89 | 90 | assert_noop!( 91 | VecSet::add_member(Origin::signed(1)), 92 | Error::::AlreadyMember 93 | ); 94 | }) 95 | } 96 | 97 | #[test] 98 | fn cant_exceed_max_members() { 99 | ExternalityBuilder::build().execute_with(|| { 100 | // Add 16 members, reaching the max 101 | for i in 0..16 { 102 | assert_ok!(VecSet::add_member(Origin::signed(i))); 103 | } 104 | 105 | // Try to add the 17th member exceeding the max 106 | assert_noop!( 107 | VecSet::add_member(Origin::signed(16)), 108 | Error::::MembershipLimitReached 109 | ); 110 | }) 111 | } 112 | 113 | #[test] 114 | fn remove_member_works() { 115 | ExternalityBuilder::build().execute_with(|| { 116 | assert_ok!(VecSet::add_member(Origin::signed(1))); 117 | assert_ok!(VecSet::remove_member(Origin::signed(1))); 118 | 119 | // check correct event emission 120 | let expected_event = Event::vec_set(vec_set::Event::MemberRemoved(1)); 121 | assert!(System::events().iter().any(|a| a.event == expected_event)); 122 | 123 | // check storage changes 124 | assert_eq!(VecSet::members(), Vec::::new()); 125 | }) 126 | } 127 | 128 | #[test] 129 | fn remove_member_handles_errors() { 130 | ExternalityBuilder::build().execute_with(|| { 131 | // 2 is NOT previously added as a member 132 | assert_noop!( 133 | VecSet::remove_member(Origin::signed(2)), 134 | Error::::NotMember 135 | ); 136 | }) 137 | } 138 | -------------------------------------------------------------------------------- /pallets/vec-set/types.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /pallets/weights/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "weights" 3 | version = "3.0.0" 4 | edition = "2018" 5 | authors = ['Substrate DevHub '] 6 | repository = 'https://github.com/substrate-developer-hub/recipes' 7 | description = "A pallet that demonstrates weight annotations on dispatchable calls" 8 | license = "GPL-3.0-or-later" 9 | 10 | [dependencies] 11 | parity-scale-codec = { version = "2.0", features = ["derive"], default-features = false } 12 | 13 | # Substrate packages 14 | frame-support = { version = '3.0', default-features = false } 15 | frame-system = { version = '3.0', default-features = false } 16 | sp-runtime = { version = '3.0', default-features = false } 17 | 18 | [dev-dependencies] 19 | sp-core = { version = '3.0', default-features = false } 20 | 21 | [features] 22 | default = ['std'] 23 | std = [ 24 | 'frame-support/std', 25 | 'frame-system/std', 26 | 'parity-scale-codec/std', 27 | 'sp-runtime/std', 28 | ] 29 | -------------------------------------------------------------------------------- /pallets/weights/types.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /runtimes/api-runtime/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "api-runtime" 3 | version = "3.0.0" 4 | edition = "2018" 5 | authors = ['Substrate DevHub '] 6 | repository = 'https://github.com/substrate-developer-hub/recipes' 7 | description = "A runtime that features a custom runtime API that calls into a pallet" 8 | license = "GPL-3.0-or-later" 9 | 10 | [dependencies] 11 | parity-scale-codec = { version = "2.0", default-features = false, features = ["derive"] } 12 | serde = { version = "1.0", optional = true, features = ["derive"] } 13 | 14 | # Substrate packages 15 | frame-executive = { version = '3.0', default-features = false} 16 | frame-support = { version = '3.0', default-features = false } 17 | frame-system = { version = '3.0', default-features = false } 18 | pallet-balances = { version = '3.0', default-features = false } 19 | pallet-randomness-collective-flip = { version = '3.0', default-features = false } 20 | pallet-sudo = { version = '3.0', default-features = false } 21 | pallet-timestamp = { version = '3.0', default-features = false } 22 | pallet-transaction-payment = { version = '3.0', default-features = false } 23 | sp-api = { version = '3.0', default-features = false } 24 | sp-block-builder = { version = '3.0', default-features = false } 25 | sp-core = { version = '3.0', default-features = false } 26 | sp-inherents = { version = '3.0', default-features = false } 27 | sp-io = { version = '3.0', default-features = false } 28 | sp-offchain = { version = '3.0', default-features = false } 29 | sp-runtime = { version = '3.0', default-features = false } 30 | sp-session = { version = '3.0', default-features = false } 31 | sp-std = { version = '3.0', default-features = false } 32 | sp-transaction-pool = { version = '3.0', default-features = false } 33 | sp-version = { version = '3.0', default-features = false } 34 | 35 | # local packages 36 | sum-storage = { default-features = false, path = "../../pallets/sum-storage" } 37 | sum-storage-runtime-api = { default-features = false, path = "../../pallets/sum-storage/runtime-api" } 38 | 39 | [build-dependencies] 40 | substrate-wasm-builder = "4.0.0" 41 | 42 | [features] 43 | default = ["std"] 44 | std = [ 45 | "frame-executive/std", 46 | "frame-support/std", 47 | "frame-system/std", 48 | "pallet-balances/std", 49 | "pallet-randomness-collective-flip/std", 50 | "pallet-sudo/std", 51 | "pallet-timestamp/std", 52 | "pallet-transaction-payment/std", 53 | "parity-scale-codec/std", 54 | "serde", 55 | "sp-api/std", 56 | "sp-block-builder/std", 57 | "sp-core/std", 58 | "sp-inherents/std", 59 | "sp-io/std", 60 | "sp-offchain/std", 61 | "sp-runtime/std", 62 | "sp-session/std", 63 | "sp-std/std", 64 | "sp-transaction-pool/std", 65 | "sp-version/std", 66 | "sum-storage-runtime-api/std", 67 | "sum-storage/std", 68 | ] 69 | -------------------------------------------------------------------------------- /runtimes/api-runtime/aggregate_types.js: -------------------------------------------------------------------------------- 1 | // Reads in the type definitions from all pallets in the runtime and the runtime's own tpes 2 | // Naively aggregates types and writes them to disk. 3 | 4 | const fs = require('fs'); 5 | 6 | // A list of all the installed recipe pallets' folder names. 7 | // Does not include system pallets because Apps already supports them. 8 | // Redundant with construct_runtime! 9 | const pallets = [ 10 | "sum-storage", 11 | ] 12 | 13 | // Types that are native to the runtime itself (ie come from lib.rs) 14 | // These specifics are from https://polkadot.js.org/api/start/types.extend.html#impact-on-extrinsics 15 | const runtimeOwnTypes = { 16 | "AccountInfo": "AccountInfoWithTripleRefCount", 17 | "Address": "AccountId", 18 | "LookupSource": "AccountId" 19 | } 20 | 21 | // Loop through all pallets aggregating types 22 | let finalTypes = runtimeOwnTypes; 23 | let palletTypes; 24 | for (let dirname of pallets) { 25 | let path = `../../pallets/${dirname}/types.json`; 26 | palletTypes = JSON.parse(fs.readFileSync(path, 'utf8')); 27 | finalTypes = {...finalTypes, ...palletTypes}; 28 | } 29 | 30 | // Write output to disk 31 | fs.writeFileSync("types.json", JSON.stringify(finalTypes, null, 2), 'utf8'); 32 | -------------------------------------------------------------------------------- /runtimes/api-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 | -------------------------------------------------------------------------------- /runtimes/api-runtime/src/genesis.rs: -------------------------------------------------------------------------------- 1 | //! Helper module to build a genesis configuration for the api-runtime 2 | 3 | use super::{AccountId, BalancesConfig, GenesisConfig, Signature, SudoConfig, SystemConfig}; 4 | use sp_core::{sr25519, Pair}; 5 | use sp_runtime::traits::{IdentifyAccount, Verify}; 6 | 7 | /// Helper function to generate a crypto pair from seed 8 | fn get_from_seed(seed: &str) -> TPair::Public { 9 | TPair::from_string(&format!("//{}", seed), None) 10 | .expect("static values are valid; qed") 11 | .public() 12 | } 13 | 14 | type AccountPublic = ::Signer; 15 | 16 | /// Helper function to generate an account ID from seed 17 | pub fn account_id_from_seed(seed: &str) -> AccountId 18 | where 19 | AccountPublic: From, 20 | { 21 | AccountPublic::from(get_from_seed::(seed)).into_account() 22 | } 23 | 24 | pub fn dev_genesis(wasm_binary: &[u8]) -> GenesisConfig { 25 | testnet_genesis( 26 | wasm_binary, 27 | // Root Key 28 | account_id_from_seed::("Alice"), 29 | // Endowed Accounts 30 | vec![ 31 | account_id_from_seed::("Alice"), 32 | account_id_from_seed::("Bob"), 33 | account_id_from_seed::("Alice//stash"), 34 | account_id_from_seed::("Bob//stash"), 35 | ], 36 | ) 37 | } 38 | 39 | /// Helper function to build a genesis configuration 40 | pub fn testnet_genesis( 41 | wasm_binary: &[u8], 42 | root_key: AccountId, 43 | endowed_accounts: Vec, 44 | ) -> GenesisConfig { 45 | GenesisConfig { 46 | frame_system: Some(SystemConfig { 47 | code: wasm_binary.to_vec(), 48 | changes_trie_config: Default::default(), 49 | }), 50 | pallet_balances: Some(BalancesConfig { 51 | balances: endowed_accounts 52 | .iter() 53 | .cloned() 54 | .map(|k| (k, 1 << 60)) 55 | .collect(), 56 | }), 57 | pallet_sudo: Some(SudoConfig { key: root_key }), 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /runtimes/api-runtime/types.json: -------------------------------------------------------------------------------- 1 | { 2 | "AccountInfo": "AccountInfoWithTripleRefCount", 3 | "Address": "AccountId", 4 | "LookupSource": "AccountId", 5 | "AccountInfo": "AccountInfoWithDualRefCount" 6 | } 7 | -------------------------------------------------------------------------------- /runtimes/minimal-grandpa-runtime/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "minimal-grandpa-runtime" 3 | version = "3.0.0" 4 | edition = "2018" 5 | authors = ['Substrate DevHub '] 6 | repository = 'https://github.com/substrate-developer-hub/recipes' 7 | description = "A runtime that manages a set of grandpa authorities and supplies them to the client" 8 | license = "GPL-3.0-or-later" 9 | 10 | [dependencies] 11 | parity-scale-codec = { version = "2.0", features = ["derive"], default-features = false } 12 | serde = { version = "1.0", optional = true, features = ["derive"] } 13 | 14 | # Substrate packages 15 | pallet-balances = { version = '3.0', default-features = false } 16 | frame-executive = { version = '3.0', default-features = false } 17 | frame-support = { version = '3.0', default-features = false } 18 | frame-system = { version = '3.0', default-features = false } 19 | pallet-grandpa = { version = '3.0', default-features = false } 20 | pallet-randomness-collective-flip = { version = '3.0', default-features = false } 21 | sp-api = { version = '3.0', default-features = false } 22 | sp-block-builder = { version = '3.0', default-features = false } 23 | sp-core = { version = '3.0', default-features = false } 24 | sp-finality-grandpa = { version = '3.0', default-features = false } 25 | sp-inherents = { version = '3.0', default-features = false } 26 | sp-io = { version = '3.0', default-features = false } 27 | sp-offchain = { version = '3.0', default-features = false } 28 | sp-runtime = { version = '3.0', default-features = false } 29 | sp-session = { version = '3.0', default-features = false } 30 | sp-std = { version = '3.0', default-features = false } 31 | sp-transaction-pool = { version = '3.0', default-features = false } 32 | sp-version = { version = '3.0', default-features = false } 33 | pallet-sudo = { version = '3.0', default-features = false } 34 | pallet-timestamp = { version = '3.0', default-features = false } 35 | pallet-transaction-payment = { version = '3.0', default-features = false } 36 | 37 | [build-dependencies] 38 | substrate-wasm-builder = "4.0.0" 39 | 40 | [features] 41 | default = ["std"] 42 | std = [ 43 | "pallet-balances/std", 44 | "frame-executive/std", 45 | "frame-support/std", 46 | "frame-system/std", 47 | "pallet-grandpa/std", 48 | "parity-scale-codec/std", 49 | "pallet-randomness-collective-flip/std", 50 | "serde", 51 | "sp-api/std", 52 | "sp-block-builder/std", 53 | "sp-core/std", 54 | "sp-finality-grandpa/std", 55 | "sp-inherents/std", 56 | "sp-io/std", 57 | "sp-offchain/std", 58 | "sp-runtime/std", 59 | "sp-session/std", 60 | "sp-std/std", 61 | "sp-transaction-pool/std", 62 | "sp-version/std", 63 | "pallet-sudo/std", 64 | "pallet-timestamp/std", 65 | "pallet-transaction-payment/std", 66 | ] 67 | -------------------------------------------------------------------------------- /runtimes/minimal-grandpa-runtime/aggregate_types.js: -------------------------------------------------------------------------------- 1 | // Reads in the type definitions from all pallets in the runtime and the runtime's own tpes 2 | // Naively aggregates types and writes them to disk. 3 | 4 | const fs = require('fs'); 5 | 6 | // A list of all the installed recipe pallets' folder names. 7 | // Does not include system pallets because Apps already supports them. 8 | // Redundant with construct_runtime! 9 | const pallets = [ 10 | "weights", 11 | ] 12 | 13 | // Types that are native to the runtime itself (ie come from lib.rs) 14 | // These specifics are from https://polkadot.js.org/api/start/types.extend.html#impact-on-extrinsics 15 | const runtimeOwnTypes = { 16 | "AccountInfo": "AccountInfoWithTripleRefCount", 17 | "Address": "AccountId", 18 | "LookupSource": "AccountId", 19 | "Weight": "u32" 20 | } 21 | 22 | // Loop through all pallets aggregating types 23 | let finalTypes = runtimeOwnTypes; 24 | let palletTypes; 25 | for (let dirname of pallets) { 26 | let path = `../../pallets/${dirname}/types.json`; 27 | palletTypes = JSON.parse(fs.readFileSync(path, 'utf8')); 28 | finalTypes = {...finalTypes, ...palletTypes}; 29 | } 30 | 31 | // Write output to disk 32 | fs.writeFileSync("types.json", JSON.stringify(finalTypes, null, 2), 'utf8'); 33 | -------------------------------------------------------------------------------- /runtimes/minimal-grandpa-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 | -------------------------------------------------------------------------------- /runtimes/minimal-grandpa-runtime/src/genesis.rs: -------------------------------------------------------------------------------- 1 | //! Helper module to build a genesis configuration for the weight-fee-runtime 2 | 3 | use super::{ 4 | AccountId, BalancesConfig, GenesisConfig, GrandpaConfig, Signature, SudoConfig, SystemConfig, 5 | }; 6 | use sp_core::{sr25519, Pair, Public}; 7 | use sp_finality_grandpa::AuthorityId as GrandpaId; 8 | use sp_runtime::traits::{IdentifyAccount, Verify}; 9 | 10 | /// Helper function to generate a crypto pair from seed 11 | fn get_from_seed(seed: &str) -> ::Public { 12 | TPublic::Pair::from_string(&format!("//{}", seed), None) 13 | .expect("static values are valid; qed") 14 | .public() 15 | } 16 | 17 | type AccountPublic = ::Signer; 18 | 19 | /// Helper function to generate an account ID from seed 20 | pub fn account_id_from_seed(seed: &str) -> AccountId 21 | where 22 | AccountPublic: From<::Public>, 23 | { 24 | AccountPublic::from(get_from_seed::(seed)).into_account() 25 | } 26 | 27 | /// Helper function to generate session key from seed 28 | pub fn authority_keys_from_seed(seed: &str) -> GrandpaId { 29 | get_from_seed::(seed) 30 | } 31 | 32 | pub fn dev_genesis(wasm_binary: &[u8]) -> GenesisConfig { 33 | testnet_genesis( 34 | wasm_binary, 35 | // Initial Authorities 36 | vec![authority_keys_from_seed("Alice")], 37 | // Root Key 38 | account_id_from_seed::("Alice"), 39 | // Endowed Accounts 40 | vec![ 41 | account_id_from_seed::("Alice"), 42 | account_id_from_seed::("Bob"), 43 | account_id_from_seed::("Alice//stash"), 44 | account_id_from_seed::("Bob//stash"), 45 | ], 46 | ) 47 | } 48 | 49 | /// Helper function to build a genesis configuration 50 | pub fn testnet_genesis( 51 | wasm_binary: &[u8], 52 | initial_authorities: Vec, 53 | root_key: AccountId, 54 | endowed_accounts: Vec, 55 | ) -> GenesisConfig { 56 | GenesisConfig { 57 | frame_system: Some(SystemConfig { 58 | code: wasm_binary.to_vec(), 59 | changes_trie_config: Default::default(), 60 | }), 61 | pallet_balances: Some(BalancesConfig { 62 | balances: endowed_accounts 63 | .iter() 64 | .cloned() 65 | .map(|k| (k, 1 << 60)) 66 | .collect(), 67 | }), 68 | pallet_sudo: Some(SudoConfig { key: root_key }), 69 | pallet_grandpa: Some(GrandpaConfig { 70 | authorities: initial_authorities.iter().map(|x| (x.clone(), 1)).collect(), 71 | }), 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /runtimes/minimal-grandpa-runtime/types.json: -------------------------------------------------------------------------------- 1 | { 2 | "AccountInfo": "AccountInfoWithTripleRefCount", 3 | "Address": "AccountId", 4 | "LookupSource": "AccountId", 5 | "Weight": "u32", 6 | "AccountInfo": "AccountInfoWithDualRefCount" 7 | } 8 | -------------------------------------------------------------------------------- /runtimes/ocw-runtime/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "ocw-runtime" 3 | version = "3.0.0" 4 | edition = "2018" 5 | authors = ['Substrate DevHub '] 6 | repository = 'https://github.com/substrate-developer-hub/recipes' 7 | description = "A runtime that demonstrates using offchain workers" 8 | license = "GPL-3.0-or-later" 9 | 10 | [dependencies] 11 | parity-scale-codec = { version = '2.0', default-features = false, features = ['derive'] } 12 | serde = { version = '1.0', optional = true, features = ['derive'] } 13 | 14 | # Substrate packages 15 | frame-executive = { version = '3.0', default-features = false } 16 | frame-support = { version = '3.0', default-features = false } 17 | frame-system = { version = '3.0', default-features = false } 18 | pallet-balances = { version = '3.0', default-features = false } 19 | pallet-indices = { version = '3.0', default-features = false } 20 | pallet-randomness-collective-flip = { version = '3.0', default-features = false } 21 | pallet-sudo = { version = '3.0', default-features = false } 22 | pallet-timestamp = { version = '3.0', default-features = false } 23 | pallet-transaction-payment = { version = '3.0', default-features = false } 24 | sp-api = { version = '3.0', default-features = false } 25 | sp-block-builder = { version = '3.0', default-features = false } 26 | sp-core = { version = '3.0', default-features = false } 27 | sp-inherents = { version = '3.0', default-features = false } 28 | sp-io = { version = '3.0', default-features = false } 29 | sp-offchain = { version = '3.0', default-features = false } 30 | sp-runtime = { version = '3.0', default-features = false } 31 | sp-session = { version = '3.0', default-features = false } 32 | sp-std = { version = '3.0', default-features = false } 33 | sp-transaction-pool = { version = '3.0', default-features = false } 34 | sp-version = { version = '3.0', default-features = false } 35 | 36 | # local packages 37 | ocw-demo = { path = "../../pallets/ocw-demo", default-features = false } 38 | 39 | [build-dependencies] 40 | substrate-wasm-builder = "4.0.0" 41 | 42 | [features] 43 | default = ["std"] 44 | std = [ 45 | "frame-executive/std", 46 | "frame-support/std", 47 | "frame-system/std", 48 | "ocw-demo/std", 49 | "pallet-balances/std", 50 | "pallet-indices/std", 51 | "pallet-randomness-collective-flip/std", 52 | "pallet-sudo/std", 53 | "pallet-timestamp/std", 54 | "pallet-transaction-payment/std", 55 | "parity-scale-codec/std", 56 | "serde", 57 | "sp-api/std", 58 | "sp-block-builder/std", 59 | "sp-core/std", 60 | "sp-inherents/std", 61 | "sp-io/std", 62 | "sp-offchain/std", 63 | "sp-runtime/std", 64 | "sp-session/std", 65 | "sp-std/std", 66 | "sp-transaction-pool/std", 67 | "sp-version/std", 68 | ] 69 | -------------------------------------------------------------------------------- /runtimes/ocw-runtime/aggregate_types.js: -------------------------------------------------------------------------------- 1 | // Reads in the type definitions from all pallets in the runtime and the runtime's own tpes 2 | // Naively aggregates types and writes them to disk. 3 | 4 | const fs = require('fs'); 5 | 6 | // A list of all the installed recipe pallets' folder names. 7 | // Does not include system pallets because Apps already supports them. 8 | // Redundant with construct_runtime! 9 | const pallets = [ 10 | "offchain-demo" 11 | ] 12 | 13 | // Types that are native to the runtime itself (ie come from lib.rs) 14 | // These specifics are from https://polkadot.js.org/api/start/types.extend.html#impact-on-extrinsics 15 | const runtimeOwnTypes = { 16 | "AccountInfo": "AccountInfoWithTripleRefCount", 17 | "Address": "AccountId", 18 | "LookupSource": "AccountId" 19 | } 20 | 21 | // Loop through all pallets aggregating types 22 | let finalTypes = runtimeOwnTypes; 23 | let palletTypes; 24 | for (let dirname of pallets) { 25 | let path = `../../pallets/${dirname}/types.json`; 26 | palletTypes = JSON.parse(fs.readFileSync(path, 'utf8')); 27 | finalTypes = {...finalTypes, ...palletTypes}; 28 | } 29 | 30 | // Write output to disk 31 | fs.writeFileSync("types.json", JSON.stringify(finalTypes, null, 2), 'utf8'); 32 | -------------------------------------------------------------------------------- /runtimes/ocw-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 | -------------------------------------------------------------------------------- /runtimes/ocw-runtime/src/genesis.rs: -------------------------------------------------------------------------------- 1 | //! Helper module to build a genesis configuration for the Offchain Worker 2 | 3 | use super::{AccountId, BalancesConfig, GenesisConfig, Signature, SudoConfig, SystemConfig}; 4 | use sp_core::{sr25519, Pair}; 5 | use sp_runtime::traits::{IdentifyAccount, Verify}; 6 | 7 | /// Helper function to generate a crypto pair from seed 8 | fn get_from_seed(seed: &str) -> TPair::Public { 9 | TPair::from_string(&format!("//{}", seed), None) 10 | .expect("static values are valid; qed") 11 | .public() 12 | } 13 | 14 | type AccountPublic = ::Signer; 15 | 16 | /// Helper function to generate an account ID from seed 17 | pub fn account_id_from_seed(seed: &str) -> AccountId 18 | where 19 | AccountPublic: From, 20 | { 21 | AccountPublic::from(get_from_seed::(seed)).into_account() 22 | } 23 | 24 | pub fn dev_genesis(wasm_binary: &[u8]) -> GenesisConfig { 25 | testnet_genesis( 26 | wasm_binary, 27 | // Root Key 28 | account_id_from_seed::("Alice"), 29 | // Endowed Accounts 30 | vec![ 31 | account_id_from_seed::("Alice"), 32 | account_id_from_seed::("Bob"), 33 | account_id_from_seed::("Alice//stash"), 34 | account_id_from_seed::("Bob//stash"), 35 | ], 36 | ) 37 | } 38 | 39 | /// Helper function to build a genesis configuration 40 | pub fn testnet_genesis( 41 | wasm_binary: &[u8], 42 | root_key: AccountId, 43 | endowed_accounts: Vec, 44 | ) -> GenesisConfig { 45 | GenesisConfig { 46 | frame_system: Some(SystemConfig { 47 | code: wasm_binary.to_vec(), 48 | changes_trie_config: Default::default(), 49 | }), 50 | pallet_balances: Some(BalancesConfig { 51 | balances: endowed_accounts 52 | .iter() 53 | .cloned() 54 | .map(|k| (k, 1 << 60)) 55 | .collect(), 56 | }), 57 | pallet_sudo: Some(SudoConfig { key: root_key }), 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /runtimes/ocw-runtime/types.json: -------------------------------------------------------------------------------- 1 | { 2 | "AccountInfo": "AccountInfoWithTripleRefCount", 3 | "Address": "AccountId", 4 | "LookupSource": "AccountId", 5 | "AccountInfo": "AccountInfoWithDualRefCount" 6 | } 7 | -------------------------------------------------------------------------------- /runtimes/super-runtime/aggregate_types.js: -------------------------------------------------------------------------------- 1 | // Reads in the type definitions from all pallets in the runtime and the runtime's own tpes 2 | // Naively aggregates types and writes them to disk. 3 | 4 | const fs = require('fs'); 5 | 6 | // A list of all the installed recipe pallets' folder names. 7 | // Does not include system pallets because Apps already supports them. 8 | // Redundant with construct_runtime! 9 | const pallets = [ 10 | "basic-token", 11 | "charity", 12 | "check-membership", 13 | "compounding-interest", 14 | "constant-config", 15 | "default-instance", 16 | "double-map", 17 | "fixed-point", 18 | "generic-event", 19 | "hello-substrate", 20 | "last-caller", 21 | "offchain-demo", 22 | "randomness", 23 | "ringbuffer-queue", 24 | "randomness", 25 | "simple-crowdfund", 26 | "simple-event", 27 | "simple-map", 28 | "storage-cache", 29 | "struct-storage", 30 | "vec-set", 31 | ] 32 | 33 | // Types that are native to the runtime itself (ie come from lib.rs) 34 | // These specifics are from https://polkadot.js.org/api/start/types.extend.html#impact-on-extrinsics 35 | const runtimeOwnTypes = { 36 | "AccountInfo": "AccountInfoWithTripleRefCount", 37 | "Address": "AccountId", 38 | "LookupSource": "AccountId" 39 | } 40 | 41 | // Loop through all pallets aggregating types 42 | let finalTypes = runtimeOwnTypes; 43 | let palletTypes; 44 | for (let dirname of pallets) { 45 | let path = `../../pallets/${dirname}/types.json`; 46 | palletTypes = JSON.parse(fs.readFileSync(path, 'utf8')); 47 | finalTypes = {...finalTypes, ...palletTypes}; 48 | } 49 | 50 | // Write output to disk 51 | fs.writeFileSync("types.json", JSON.stringify(finalTypes, null, 2), 'utf8'); 52 | -------------------------------------------------------------------------------- /runtimes/super-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 | -------------------------------------------------------------------------------- /runtimes/super-runtime/src/genesis.rs: -------------------------------------------------------------------------------- 1 | //! Helper module to build a genesis configuration for the super-runtime 2 | 3 | use super::{AccountId, BalancesConfig, GenesisConfig, Signature, SudoConfig, SystemConfig}; 4 | use sp_core::{sr25519, Pair}; 5 | use sp_runtime::traits::{IdentifyAccount, Verify}; 6 | 7 | /// Helper function to generate a crypto pair from seed 8 | fn get_from_seed(seed: &str) -> TPair::Public { 9 | TPair::from_string(&format!("//{}", seed), None) 10 | .expect("static values are valid; qed") 11 | .public() 12 | } 13 | 14 | type AccountPublic = ::Signer; 15 | 16 | /// Helper function to generate an account ID from seed 17 | pub fn account_id_from_seed(seed: &str) -> AccountId 18 | where 19 | AccountPublic: From, 20 | { 21 | AccountPublic::from(get_from_seed::(seed)).into_account() 22 | } 23 | 24 | pub fn dev_genesis(wasm_binary: &[u8]) -> GenesisConfig { 25 | testnet_genesis( 26 | wasm_binary, 27 | // Root Key 28 | account_id_from_seed::("Alice"), 29 | // Endowed Accounts 30 | vec![ 31 | account_id_from_seed::("Alice"), 32 | account_id_from_seed::("Bob"), 33 | account_id_from_seed::("Alice//stash"), 34 | account_id_from_seed::("Bob//stash"), 35 | ], 36 | ) 37 | } 38 | 39 | /// Helper function to build a genesis configuration 40 | pub fn testnet_genesis( 41 | wasm_binary: &[u8], 42 | root_key: AccountId, 43 | endowed_accounts: Vec, 44 | ) -> GenesisConfig { 45 | GenesisConfig { 46 | system: Some(SystemConfig { 47 | code: wasm_binary.to_vec(), 48 | changes_trie_config: Default::default(), 49 | }), 50 | pallet_balances: Some(BalancesConfig { 51 | balances: endowed_accounts 52 | .iter() 53 | .cloned() 54 | .map(|k| (k, 1 << 60)) 55 | .collect(), 56 | }), 57 | pallet_sudo: Some(SudoConfig { key: root_key }), 58 | charity: Some(Default::default()), 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /runtimes/super-runtime/types.json: -------------------------------------------------------------------------------- 1 | { 2 | "AccountInfo": "AccountInfoWithTripleRefCount", 3 | "Address": "AccountId", 4 | "LookupSource": "AccountId", 5 | "AccountInfo": "AccountInfoWithDualRefCount", 6 | "ContinuousAccountData": { 7 | "principal": "u64", 8 | "deposit_date": "BlockNumber" 9 | }, 10 | "U16F16": "[u8; 4]", 11 | "GroupIndex": "u32", 12 | "ValueStruct": { 13 | "integer": "i32", 14 | "boolean": "bool" 15 | }, 16 | "BufferIndex": "u8", 17 | "AccountIdOf": "AccountId", 18 | "BalanceOf": "Balance", 19 | "FundInfoOf": "FundInfo", 20 | "FundInfo": { 21 | "beneficiary": "AccountId", 22 | "deposit": "Balance", 23 | "raised": "Balance", 24 | "end": "BlockNumber", 25 | "goal": "Balance" 26 | }, 27 | "FundIndex": "u32", 28 | "InnerThing": { 29 | "number": "u32", 30 | "hash": "Hash", 31 | "balance": "Balance" 32 | }, 33 | "SuperThing": { 34 | "super_number": "u32", 35 | "inner_thing": "InnerThing" 36 | }, 37 | "InnerThingOf": "InnerThing" 38 | } 39 | -------------------------------------------------------------------------------- /runtimes/weight-fee-runtime/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "weight-fee-runtime" 3 | version = "3.0.0" 4 | edition = "2018" 5 | authors = ['Substrate DevHub '] 6 | repository = 'https://github.com/substrate-developer-hub/recipes' 7 | description = "A runtime that demonstrate converting weights to fees and charging fees in multiple assets" 8 | license = "GPL-3.0-or-later" 9 | 10 | [dependencies] 11 | parity-scale-codec = { version = "2.0", features = ["derive"], default-features = false } 12 | serde = { version = "1.0", optional = true, features = ["derive"] } 13 | smallvec = "1.4" 14 | 15 | # Substrate packages 16 | pallet-balances = { version = '3.0', default-features = false } 17 | frame-executive = { version = '3.0', default-features = false } 18 | frame-support = { version = '3.0', default-features = false } 19 | frame-system = { version = '3.0', default-features = false } 20 | pallet-randomness-collective-flip = { version = '3.0', default-features = false } 21 | sp-api = { version = '3.0', default-features = false } 22 | sp-block-builder = { version = '3.0', default-features = false } 23 | sp-core = { version = '3.0', default-features = false } 24 | sp-inherents = { version = '3.0', default-features = false } 25 | sp-io = { version = '3.0', default-features = false } 26 | sp-offchain = { version = '3.0', default-features = false } 27 | sp-runtime = { version = '3.0', default-features = false } 28 | sp-session = { version = '3.0', default-features = false } 29 | sp-std = { version = '3.0', default-features = false } 30 | sp-transaction-pool = { version = '3.0', default-features = false } 31 | sp-version = { version = '3.0', default-features = false } 32 | pallet-sudo = { version = '3.0', default-features = false } 33 | pallet-timestamp = { version = '3.0', default-features = false } 34 | pallet-transaction-payment = { version = '3.0', default-features = false } 35 | 36 | # local packages 37 | weights = { path = "../../pallets/weights", default-features = false } 38 | 39 | [build-dependencies] 40 | substrate-wasm-builder = "4.0.0" 41 | 42 | [features] 43 | default = ["std"] 44 | std = [ 45 | "pallet-balances/std", 46 | "frame-executive/std", 47 | "frame-support/std", 48 | "frame-system/std", 49 | "parity-scale-codec/std", 50 | "pallet-randomness-collective-flip/std", 51 | "serde", 52 | "sp-api/std", 53 | "sp-block-builder/std", 54 | "sp-core/std", 55 | "sp-inherents/std", 56 | "sp-io/std", 57 | "sp-offchain/std", 58 | "sp-runtime/std", 59 | "sp-session/std", 60 | "sp-std/std", 61 | "sp-transaction-pool/std", 62 | "sp-version/std", 63 | "pallet-sudo/std", 64 | "pallet-timestamp/std", 65 | "pallet-transaction-payment/std", 66 | "weights/std", 67 | ] 68 | -------------------------------------------------------------------------------- /runtimes/weight-fee-runtime/aggregate_types.js: -------------------------------------------------------------------------------- 1 | // Reads in the type definitions from all pallets in the runtime and the runtime's own tpes 2 | // Naively aggregates types and writes them to disk. 3 | 4 | const fs = require('fs'); 5 | 6 | // A list of all the installed recipe pallets' folder names. 7 | // Does not include system pallets because Apps already supports them. 8 | // Redundant with construct_runtime! 9 | const pallets = [ 10 | "weights", 11 | ] 12 | 13 | // Types that are native to the runtime itself (ie come from lib.rs) 14 | // These specifics are from https://polkadot.js.org/api/start/types.extend.html#impact-on-extrinsics 15 | const runtimeOwnTypes = { 16 | "AccountInfo": "AccountInfoWithTripleRefCount", 17 | "Address": "AccountId", 18 | "LookupSource": "AccountId" 19 | } 20 | 21 | // Loop through all pallets aggregating types 22 | let finalTypes = runtimeOwnTypes; 23 | let palletTypes; 24 | for (let dirname of pallets) { 25 | let path = `../../pallets/${dirname}/types.json`; 26 | palletTypes = JSON.parse(fs.readFileSync(path, 'utf8')); 27 | finalTypes = {...finalTypes, ...palletTypes}; 28 | } 29 | 30 | // Write output to disk 31 | fs.writeFileSync("types.json", JSON.stringify(finalTypes, null, 2), 'utf8'); 32 | -------------------------------------------------------------------------------- /runtimes/weight-fee-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 | -------------------------------------------------------------------------------- /runtimes/weight-fee-runtime/src/genesis.rs: -------------------------------------------------------------------------------- 1 | //! Helper module to build a genesis configuration for the weight-fee-runtime 2 | 3 | use super::{AccountId, BalancesConfig, GenesisConfig, Signature, SudoConfig, SystemConfig}; 4 | use sp_core::{sr25519, Pair}; 5 | use sp_runtime::traits::{IdentifyAccount, Verify}; 6 | 7 | /// Helper function to generate a crypto pair from seed 8 | fn get_from_seed(seed: &str) -> TPair::Public { 9 | TPair::from_string(&format!("//{}", seed), None) 10 | .expect("static values are valid; qed") 11 | .public() 12 | } 13 | 14 | type AccountPublic = ::Signer; 15 | 16 | /// Helper function to generate an account ID from seed 17 | pub fn account_id_from_seed(seed: &str) -> AccountId 18 | where 19 | AccountPublic: From, 20 | { 21 | AccountPublic::from(get_from_seed::(seed)).into_account() 22 | } 23 | 24 | pub fn dev_genesis(wasm_binary: &[u8]) -> GenesisConfig { 25 | testnet_genesis( 26 | wasm_binary, 27 | // Root Key 28 | account_id_from_seed::("Alice"), 29 | // Endowed Accounts 30 | vec![ 31 | account_id_from_seed::("Alice"), 32 | account_id_from_seed::("Bob"), 33 | account_id_from_seed::("Alice//stash"), 34 | account_id_from_seed::("Bob//stash"), 35 | ], 36 | ) 37 | } 38 | 39 | /// Helper function to build a genesis configuration 40 | pub fn testnet_genesis( 41 | wasm_binary: &[u8], 42 | root_key: AccountId, 43 | endowed_accounts: Vec, 44 | ) -> GenesisConfig { 45 | GenesisConfig { 46 | frame_system: Some(SystemConfig { 47 | code: wasm_binary.to_vec(), 48 | changes_trie_config: Default::default(), 49 | }), 50 | pallet_balances: Some(BalancesConfig { 51 | balances: endowed_accounts 52 | .iter() 53 | .cloned() 54 | .map(|k| (k, 1 << 60)) 55 | .collect(), 56 | }), 57 | pallet_sudo: Some(SudoConfig { key: root_key }), 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /runtimes/weight-fee-runtime/types.json: -------------------------------------------------------------------------------- 1 | { 2 | "AccountInfo": "AccountInfoWithTripleRefCount", 3 | "Address": "AccountId", 4 | "LookupSource": "AccountId", 5 | "AccountInfo": "AccountInfoWithDualRefCount" 6 | } 7 | -------------------------------------------------------------------------------- /rustfmt.toml: -------------------------------------------------------------------------------- 1 | hard_tabs = true 2 | -------------------------------------------------------------------------------- /text/SUMMARY.md: -------------------------------------------------------------------------------- 1 | # Summary 2 | 3 | [Introduction](./introduction.md) 4 | - [Pallets](./pallets-intro.md) 5 | - [Printing to the Node Log](./runtime-printing.md) 6 | - [Emitting Events](./events.md) 7 | - [Storage Maps](./storage-maps.md) 8 | - [Cache Locally > Storage Calls](./cache.md) 9 | - [Using Vectors as Sets](./vec-set.md) 10 | - [Using Maps as Sets](./map-set.md) 11 | - [Subgroup Removal by Subkey: Double Maps](./double.md) 12 | - [Storing custom structs](./structs.md) 13 | - [Ringbuffer Queue](./ringbuffer.md) 14 | - [Basic Token](./basic-token.md) 15 | - [Configurable Constants](./constants.md) 16 | - [Simple Crowdfund](./crowdfund.md) 17 | - [Instantiable Pallets](./instantiable.md) 18 | - [Weights for Resource Accounting](./weights.md) 19 | - [Charity and Imbalances](./charity.md) 20 | - [Fixed Point Arithmetic](./fixed-point.md) 21 | - [Off-chain Workers](./off-chain-workers/index.md) 22 | - [Transactions](./off-chain-workers/transactions.md) 23 | - [HTTP Fetching & JSON Parsing](./off-chain-workers/http-json.md) 24 | - [Local Storage](./off-chain-workers/storage.md) 25 | - [Off-chain Indexing](./off-chain-workers/indexing.md) 26 | - [Currency Types](./currency.md) 27 | - [Currency and Imbalances](./currency-imbalances.md) 28 | - [Generating Randomness](./randomness.md) 29 | - [Tightly- and Loosely-Coupled Pallets](./pallet-coupling.md) 30 | - [Runtimes](./runtimes-intro.md) 31 | - [Runtime APIs](./runtime-api.md) 32 | - [Transaction Fees for Economic Security](./fees.md) 33 | - [Consensus](./consensus-intro.md) 34 | - [Sha3 Pow Consensus Algorithms](./sha3-pow-consensus.md) 35 | - [Nodes](./nodes-intro.md) 36 | - [Kitchen Node - An reusable instant seal node](./kitchen-node.md) 37 | - [Custom RPCs](./custom-rpc.md) 38 | - [Basic Proof of Work Node](./basic-pow.md) 39 | - [Hybrid PoW/PoS Consensus Node](./hybrid-consensus.md) 40 | -------------------------------------------------------------------------------- /text/consensus-intro.md: -------------------------------------------------------------------------------- 1 | # Consensus 2 | 3 | Consensus is the part of the outer node that decides which blocks are in the real blockchain. Learn about it in this section of the cookbook. 4 | -------------------------------------------------------------------------------- /text/currency-imbalances.md: -------------------------------------------------------------------------------- 1 | # Currency Imbalances 2 | 3 | `pallets/currency-imbalances` 4 | 5 | Try on playground 6 | 7 | 8 | View on GitHub 9 | 10 | 11 | [`Imbalance`](https://substrate.dev/rustdocs/v3.0.0/frame_support/traits/trait.Imbalance.html) 12 | is used when tokens are burned or minted. In order to execute `imbalance` implement the 13 | [`OnUnbalanced`](https://substrate.dev/rustdocs/v3.0.0/frame_support/traits/trait.OnUnbalanced.html)trait. 14 | In this pallet a specific amount of funds will be slashed from an account and award a specific 15 | amount of funds to said specific account. 16 | 17 | ## Slash funds 18 | 19 | ```rust, ignore 20 | pub fn slash_funds(origin, to_punish: T::AccountId, collateral: BalanceOf) { 21 | let _ = ensure_signed(origin)?; 22 | 23 | let imbalance = T::Currency::slash_reserved(&to_punish, collateral).0; 24 | T::Slash::on_unbalanced(imbalance); 25 | 26 | let now = >::block_number(); 27 | Self::deposit_event(RawEvent::SlashFunds(to_punish, collateral, now)); 28 | } 29 | ``` 30 | 31 | ## Reward funds 32 | 33 | ```rust, ignore 34 | pub fn reward_funds(origin, to_reward: T::AccountId, reward: BalanceOf) { 35 | 36 | let _ = ensure_signed(origin)?; 37 | 38 | let mut total_imbalance = >::zero(); 39 | 40 | let r = T::Currency::deposit_into_existing(&to_reward, reward).ok(); 41 | total_imbalance.maybe_subsume(r); 42 | T::Reward::on_unbalanced(total_imbalance); 43 | 44 | let now = >::block_number(); 45 | Self::deposit_event(RawEvent::RewardFunds(to_reward, reward, now)); 46 | } 47 | ``` 48 | -------------------------------------------------------------------------------- /text/double.md: -------------------------------------------------------------------------------- 1 | # Efficent Subgroup Removal by Subkey: Double Maps 2 | 3 | `pallets/double-map` 4 | 5 | Try on playground 6 | 7 | 8 | View on GitHub 9 | 10 | 11 | For some runtimes, it may be necessary to remove a subset of values in a key-value mapping. If the 12 | subset maintain an associated identifier type, this can be done in a clean way with the 13 | [`double_map`](https://substrate.dev/rustdocs/latest/frame_support/storage/trait.StorageDoubleMap.html) via the 14 | `remove_prefix` api. 15 | 16 | ```rust, ignore 17 | pub type GroupIndex = u32; // this is Encode (which is necessary for double_map) 18 | 19 | decl_storage! { 20 | trait Store for Module as Dmap { 21 | /// Member score (double map) 22 | MemberScore get(fn member_score): 23 | double_map hasher(blake2_128_concat) GroupIndex, hasher(blake2_128_concat) T::AccountId => u32; 24 | /// Get group ID for member 25 | GroupMembership get(fn group_membership): map hasher(blake2_128_concat) T::AccountId => GroupIndex; 26 | /// For fast membership checks, see check-membership recipe for more details 27 | AllMembers get(fn all_members): Vec; 28 | } 29 | } 30 | ``` 31 | 32 | For the purposes of this example, store the scores of each member in a map that associates this 33 | `u32` value with two keys: (1) a `GroupIndex` identifier, and (2) the member's `AccountId`. This 34 | allows for efficient removal of all values associated with a specific `GroupIndex` identifier. 35 | 36 | ```rust, ignore 37 | fn remove_group_score(origin, group: GroupIndex) -> DispatchResult { 38 | let member = ensure_signed(origin)?; 39 | 40 | let group_id = >::get(member); 41 | // check that the member is in the group 42 | ensure!(group_id == group, "member isn't in the group, can't remove it"); 43 | 44 | // remove all group members from MemberScore at once 45 | >::remove_prefix(&group_id); 46 | 47 | Self::deposit_event(RawEvent::RemoveGroup(group_id)); 48 | Ok(()) 49 | } 50 | ``` 51 | -------------------------------------------------------------------------------- /text/img/apps-manual-seal-create-block.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/techwizard210/Substrate_Recipes/03b7a0657727705faa5f840c73bcf15ffdd81f2b/text/img/apps-manual-seal-create-block.png -------------------------------------------------------------------------------- /text/img/apps-select-network.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/techwizard210/Substrate_Recipes/03b7a0657727705faa5f840c73bcf15ffdd81f2b/text/img/apps-select-network.png -------------------------------------------------------------------------------- /text/img/apps-types.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/techwizard210/Substrate_Recipes/03b7a0657727705faa5f840c73bcf15ffdd81f2b/text/img/apps-types.png -------------------------------------------------------------------------------- /text/img/multiple-ocws.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/techwizard210/Substrate_Recipes/03b7a0657727705faa5f840c73bcf15ffdd81f2b/text/img/multiple-ocws.png -------------------------------------------------------------------------------- /text/img/substrate-architecture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/techwizard210/Substrate_Recipes/03b7a0657727705faa5f840c73bcf15ffdd81f2b/text/img/substrate-architecture.png -------------------------------------------------------------------------------- /text/nodes-intro.md: -------------------------------------------------------------------------------- 1 | # Nodes 2 | 3 | The "outer node" is the part of a Substrate chain that is not in the runtime. It handles networking, gossip, transaction queueing, and consensus. Learn about it in this section of the cookbook. 4 | -------------------------------------------------------------------------------- /text/off-chain-workers/index.md: -------------------------------------------------------------------------------- 1 | # Off-chain Workers 2 | 3 | > Here we focus on building off-chain workers in Substrate. To read more about what off-chain 4 | > workers are, why you want to use them, and what kinds of problems they solve best. Please goto 5 | > [our guide](https://substrate.dev/docs/en/knowledgebase/learn-substrate/off-chain-features#off-chain-workers). 6 | 7 | Off-chain workers allow your Substrate node to offload tasks that take too long or too much CPU / 8 | memory resources to compute, or have non-deterministic result. In particular there are a set of 9 | helpers allowing fetching of HTTP requests and parsing for JSON. It also provides storage that is 10 | specific to the particular Substrate node and not shared across the network. Off-chain workers can 11 | also submit either signed or unsigned transactions back on-chain. 12 | 13 | We will deep-dive into each of the topics below. 14 | 15 | - [Signed and Unsigned Transactions](./transactions.md) 16 | - [HTTP fetching and JSON parsing](./http-json.md) 17 | - [Local storage in Off-chain Workers](./storage.md) 18 | - [Off-chain Indexing](./indexing.md) 19 | -------------------------------------------------------------------------------- /text/pallets-intro.md: -------------------------------------------------------------------------------- 1 | # Pallets 2 | 3 | Pallets are individual pieces of runtime logic for use in FRAME runtimes. Learn about them in this section of the cookbook. 4 | -------------------------------------------------------------------------------- /text/runtimes-intro.md: -------------------------------------------------------------------------------- 1 | # Runtimes 2 | 3 | A runtime represents the onchain application logic of a blockchain. They are typically written by composing FRAME pallets, but they can also be written directly. Learn about them in this section of the cookbook. 4 | -------------------------------------------------------------------------------- /text/weights.md: -------------------------------------------------------------------------------- 1 | # Computational Resources and Weights 2 | 3 | `pallets/weights` 4 | 5 | Try on playground 6 | 7 | 8 | View on GitHub 9 | 10 | 11 | Any computational resources used by a transaction must be accounted for so that appropriate fees can 12 | be applied, and it is a pallet author's job to ensure that this accounting happens. Substrate 13 | provides a mechanism known as transaction weighting to quantify the resources consumed while 14 | executing a transaction. 15 | 16 | _Indeed, mispriced EVM operations have shown how operations that underestimate cost can provide 17 | economic DOS attack vectors: [Onwards; Underpriced EVM Operations](https://www.parity.io/onwards/)_ 18 | 19 | ## Assigning Transaction Weights 20 | 21 | Pallet authors can annotate their dispatchable function with a weight using syntax like this, 22 | 23 | ```rust, ignore 24 | #[weight = ] 25 | fn some_call(...) -> Result { 26 | // --snip-- 27 | } 28 | ``` 29 | 30 | For simple transactions a fixed weight will do. Substrate allows simply specifying a constant 31 | integer in cases situations like this. 32 | 33 | ```rust, ignore 34 | decl_module! { 35 | pub struct Module for enum Call { 36 | 37 | #[weight = 10_000] 38 | fn store_value(_origin, entry: u32) -> DispatchResult { 39 | StoredValue::put(entry); 40 | Ok(()) 41 | } 42 | ``` 43 | 44 | For more complex transactions, custom weight calculations can be performed that consider the 45 | parameters passed to the call. This snippet shows a weighting struct that weighs transactions where 46 | the first parameter is a `bool`. If the first parameter is `true`, then the weight is linear in the 47 | second parameter. Otherwise the weight is constant. A transaction where this weighting scheme makes 48 | sense is demonstrated in the kitchen. 49 | 50 | ```rust, ignore 51 | pub struct Conditional(u32); 52 | 53 | impl WeighData<(&bool, &u32)> for Conditional { 54 | fn weigh_data(&self, (switch, val): (&bool, &u32)) -> Weight { 55 | 56 | if *switch { 57 | val.saturating_mul(self.0) 58 | } 59 | else { 60 | self.0 61 | } 62 | } 63 | } 64 | ``` 65 | 66 | In addition to the 67 | [`WeightData` Trait](https://substrate.dev/rustdocs/v3.0.0/frame_support/weights/trait.WeighData.html), shown 68 | above, types that are used to calculate transaction weights must also implement 69 | [`ClassifyDispatch`](https://substrate.dev/rustdocs/v3.0.0/frame_support/weights/trait.ClassifyDispatch.html), 70 | and [`PaysFee`](https://substrate.dev/rustdocs/v3.0.0/frame_support/weights/trait.PaysFee.html). 71 | 72 | ```rust, ignore 73 | impl ClassifyDispatch for Conditional { 74 | fn classify_dispatch(&self, _: T) -> DispatchClass { 75 | // Classify all calls as Normal (which is the default) 76 | Default::default() 77 | } 78 | } 79 | ``` 80 | 81 | ```rust, ignore 82 | impl PaysFee for Conditional { 83 | fn pays_fee(&self) -> bool { 84 | true 85 | } 86 | } 87 | ``` 88 | 89 | The complete code for this example as well as several others can be found in the kitchen. 90 | 91 | ## Cautions 92 | 93 | While you can make reasonable estimates of resource consumption at design time, it is always best to 94 | actually measure the resources required of your functions through an empirical process. Failure to 95 | perform such rigorous measurement may result in an economically insecure chain. 96 | 97 | While it isn't enforced, calculating a transaction's weight should itself be a cheap operation. If 98 | the weight calculation itself is expensive, your chain will be insecure. 99 | 100 | ## What About Fees? 101 | 102 | Weights are used only to describe the computational resources consumed by a transaction, and enable 103 | accounting of these resources. To learn how to turn these weights into actual fees charged to 104 | transactors, continue to the recipe on [Fees](./fees.md). 105 | -------------------------------------------------------------------------------- /traits/account-set/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "account-set" 3 | version = "3.0.0" 4 | edition = "2018" 5 | authors = ['Substrate DevHub '] 6 | repository = 'https://github.com/substrate-developer-hub/recipes' 7 | description = "A trait that supplies a set of accounts for use in a Substrate runtime" 8 | license = "GPL-3.0-or-later" 9 | 10 | [features] 11 | default = ['std'] 12 | std = [ 13 | 'sp-std/std', 14 | ] 15 | 16 | [dependencies] 17 | # Substrate packages 18 | sp-std = { version = '3.0', default-features = false } 19 | -------------------------------------------------------------------------------- /traits/account-set/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![cfg_attr(not(feature = "std"), no_std)] 2 | 3 | use sp_std::collections::btree_set::BTreeSet; 4 | 5 | /// Types that implement the AccountSet trait are able to supply a set of accounts 6 | /// The trait is generic over the notion of Account used. 7 | pub trait AccountSet { 8 | type AccountId; 9 | 10 | fn accounts() -> BTreeSet; 11 | } 12 | --------------------------------------------------------------------------------