├── .gitignore ├── .github ├── mergify.yml └── workflows │ ├── rustdoc.yml │ ├── docker.yml │ └── ci.yml ├── primitives ├── poa │ ├── Cargo.toml │ └── src │ │ └── lib.rs ├── permastore │ ├── Cargo.toml │ └── src │ │ └── lib.rs ├── Cargo.toml ├── consensus │ └── poa │ │ ├── Cargo.toml │ │ └── src │ │ └── lib.rs └── src │ └── lib.rs ├── client ├── rpc-api │ ├── Cargo.toml │ └── src │ │ ├── lib.rs │ │ └── permastore │ │ ├── mod.rs │ │ └── error.rs ├── rpc │ ├── src │ │ ├── lib.rs │ │ └── permastore │ │ │ ├── mod.rs │ │ │ └── tests.rs │ └── Cargo.toml ├── datastore │ ├── Cargo.toml │ └── src │ │ ├── tests.rs │ │ └── lib.rs └── consensus │ └── poa │ ├── benches │ └── benchmark.rs │ ├── src │ ├── trie.rs │ ├── inherent.rs │ ├── chunk_proof.rs │ └── tx_proof.rs │ └── Cargo.toml ├── scripts ├── run_benches.sh └── pallet-weights-template.hbs ├── src └── main.rs ├── runtime ├── build.rs ├── src │ ├── impls.rs │ ├── constants.rs │ └── voter_bags.rs └── Cargo.toml ├── inspect ├── Cargo.toml └── src │ ├── cli.rs │ ├── command.rs │ └── lib.rs ├── Cargo.toml ├── cli ├── src │ ├── lib.rs │ ├── cli.rs │ └── command.rs ├── build.rs └── Cargo.toml ├── README.md ├── executor ├── src │ └── lib.rs └── Cargo.toml ├── pallets ├── permastore │ ├── src │ │ ├── benchmarking.rs │ │ ├── tests.rs │ │ ├── weights.rs │ │ └── mock.rs │ └── Cargo.toml └── poa │ ├── Cargo.toml │ └── src │ ├── benchmarking.rs │ ├── weights.rs │ ├── mock.rs │ ├── tests.rs │ └── lib.rs ├── Dockerfile └── rpc ├── Cargo.toml └── src └── lib.rs /.gitignore: -------------------------------------------------------------------------------- 1 | **/target/ 2 | **/*.rs.bk 3 | *.swp 4 | .wasm-binaries 5 | **/._* 6 | .vscode 7 | .DS_Store 8 | .idea/ 9 | nohup.out 10 | rls*.log 11 | -------------------------------------------------------------------------------- /.github/mergify.yml: -------------------------------------------------------------------------------- 1 | pull_request_rules: 2 | - name: merge automatically when CI passes on master 3 | conditions: 4 | - check-success=all-ci 5 | - label=ready-to-merge 6 | - base=master 7 | - "#changes-requested-reviews-by=0" 8 | actions: 9 | merge: 10 | strict: true 11 | method: squash 12 | -------------------------------------------------------------------------------- /primitives/poa/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "cp-poa" 3 | version = "0.1.0" 4 | authors = ["Canyon Labs "] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | sp-api = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" } 9 | 10 | cp-consensus-poa = { path = "../consensus/poa", default-features = false } 11 | 12 | [features] 13 | default = ["std"] 14 | std = [ 15 | "sp-api/std", 16 | "cp-consensus-poa/std", 17 | ] 18 | -------------------------------------------------------------------------------- /client/rpc-api/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "cc-rpc-api" 3 | version = "0.1.0" 4 | authors = ["Canyon Labs "] 5 | edition = "2018" 6 | license = "GPL-3.0" 7 | homepage = "https://canyon-network.io" 8 | repository = "https://github.com/canyon-network/canyon/" 9 | 10 | [package.metadata.docs.rs] 11 | targets = ["x86_64-unknown-linux-gnu"] 12 | 13 | [dependencies] 14 | jsonrpc-core = "18.0.0" 15 | jsonrpc-core-client = "18.0.0" 16 | jsonrpc-derive = "18.0.0" 17 | thiserror = "1.0" 18 | 19 | sc-rpc-api = { git = "https://github.com/paritytech/substrate", branch = "master" } 20 | 21 | sp-core = { git = "https://github.com/paritytech/substrate", branch = "master" } 22 | -------------------------------------------------------------------------------- /scripts/run_benches.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | 5 | cd "$(dirname "$0")" 6 | 7 | cd .. 8 | 9 | cargo build --release --features=runtime-benchmarks 10 | 11 | bin=./target/release/canyon 12 | 13 | pallets=( 14 | permastore 15 | poa 16 | ) 17 | 18 | for pallet in "${pallets[@]}"; do 19 | output="./pallets/$pallet/src/weights.rs" 20 | 21 | "$bin" benchmark \ 22 | --chain "dev" \ 23 | --execution=wasm \ 24 | --wasm-execution=compiled \ 25 | --pallet "pallet_$pallet" \ 26 | --extrinsic "*" \ 27 | --steps=50 \ 28 | --heap-pages=4096 \ 29 | --repeat 20 \ 30 | --template=./scripts/pallet-weights-template.hbs \ 31 | --output="$output" 32 | 33 | if [ -f "$output" ]; then 34 | rustfmt "$output" 35 | fi 36 | done 37 | -------------------------------------------------------------------------------- /client/rpc/src/lib.rs: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | // This file is part of Canyon. 3 | // 4 | // Copyright (c) 2021 Canyon Labs. 5 | // 6 | // Canyon is free software: you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published 8 | // by the Free Software Foundation, either version 3 of the License, 9 | // or (at your option) any later version. 10 | // 11 | // Canyon is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with Canyon. If not, see . 18 | 19 | //! Canyon specific RPCs. 20 | 21 | pub mod permastore; 22 | -------------------------------------------------------------------------------- /client/rpc-api/src/lib.rs: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | // This file is part of Canyon. 3 | // 4 | // Copyright (c) 2021 Canyon Labs. 5 | // 6 | // Canyon is free software: you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published 8 | // by the Free Software Foundation, either version 3 of the License, 9 | // or (at your option) any later version. 10 | // 11 | // Canyon is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with Canyon. If not, see . 18 | 19 | //! RPC api for Canyon RPC. 20 | 21 | pub mod permastore; 22 | -------------------------------------------------------------------------------- /primitives/permastore/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "cp-permastore" 3 | version = "0.1.0" 4 | authors = ["Canyon Labs "] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | codec = { package = "parity-scale-codec", version = "2.3", default-features = false, features = ["derive"] } 9 | 10 | sp-api = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" } 11 | sp-core = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" } 12 | sp-std = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" } 13 | sp-trie = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" } 14 | 15 | [features] 16 | default = ["std"] 17 | std = [ 18 | "codec/std", 19 | "sp-api/std", 20 | "sp-core/std", 21 | "sp-std/std", 22 | "sp-trie/std", 23 | ] 24 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | // This file is part of Canyon. 3 | // 4 | // Copyright (c) 2021 Canyon Labs. 5 | // 6 | // Canyon is free software: you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published 8 | // by the Free Software Foundation, either version 3 of the License, 9 | // or (at your option) any later version. 10 | // 11 | // Canyon is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with Canyon. If not, see . 18 | 19 | //! Canyon Node CLI 20 | 21 | #![warn(missing_docs)] 22 | 23 | fn main() -> sc_cli::Result<()> { 24 | canyon_cli::run() 25 | } 26 | -------------------------------------------------------------------------------- /runtime/build.rs: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | // This file is part of Canyon. 3 | // 4 | // Copyright (c) 2021 Canyon Labs. 5 | // 6 | // Canyon is free software: you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published 8 | // by the Free Software Foundation, either version 3 of the License, 9 | // or (at your option) any later version. 10 | // 11 | // Canyon is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with Canyon. If not, see . 18 | 19 | use substrate_wasm_builder::WasmBuilder; 20 | 21 | fn main() { 22 | WasmBuilder::new() 23 | .with_current_project() 24 | .export_heap_base() 25 | .import_memory() 26 | .build() 27 | } 28 | -------------------------------------------------------------------------------- /inspect/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "canyon-inspect" 3 | version = "0.1.0" 4 | authors = ["Canyon Labs "] 5 | edition = "2018" 6 | 7 | [package.metadata.docs.rs] 8 | targets = ["x86_64-unknown-linux-gnu"] 9 | 10 | [dependencies] 11 | codec = { package = "parity-scale-codec", version = "2.3" } 12 | derive_more = "0.99" 13 | log = "0.4.8" 14 | structopt = "0.3.8" 15 | 16 | sc-cli = { git = "https://github.com/paritytech/substrate", branch = "master" } 17 | sc-client-api = { git = "https://github.com/paritytech/substrate", branch = "master" } 18 | sc-executor = { git = "https://github.com/paritytech/substrate", branch = "master" } 19 | sc-service = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" } 20 | 21 | sp-blockchain = { git = "https://github.com/paritytech/substrate", branch = "master" } 22 | sp-core = { git = "https://github.com/paritytech/substrate", branch = "master" } 23 | sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master" } 24 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "canyon" 3 | description = "Implementation of https://canyon-network.io node in Rust based on the Substrate framework." 4 | license = "GPL-3.0" 5 | version = "0.1.0" 6 | authors = ["Canyon Labs "] 7 | edition = "2018" 8 | readme = "README.md" 9 | 10 | [workspace] 11 | resolver = "2" 12 | 13 | members = [ 14 | "cli", 15 | "client/consensus/poa", 16 | "client/datastore", 17 | "client/rpc", 18 | "client/rpc-api", 19 | "executor", 20 | "inspect", 21 | "pallets/permastore", 22 | "pallets/poa", 23 | "primitives", 24 | "primitives/consensus/poa", 25 | "primitives/permastore", 26 | "primitives/poa", 27 | "rpc", 28 | "runtime", 29 | ] 30 | 31 | [profile.release] 32 | panic = "unwind" 33 | 34 | [[bin]] 35 | name = "canyon" 36 | path = "src/main.rs" 37 | required-features = ["canyon-cli/cli"] 38 | 39 | [dependencies] 40 | sc-cli = { git = "https://github.com/paritytech/substrate", branch = "master" } 41 | 42 | canyon-cli = { path = "cli" } 43 | 44 | [features] 45 | runtime-benchmarks = ["canyon-cli/runtime-benchmarks"] 46 | try-runtime = ["canyon-cli/try-runtime"] 47 | -------------------------------------------------------------------------------- /primitives/poa/src/lib.rs: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | // This file is part of Canyon. 3 | // 4 | // Copyright (c) 2021 Canyon Labs. 5 | // 6 | // Canyon is free software: you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published 8 | // by the Free Software Foundation, either version 3 of the License, 9 | // or (at your option) any later version. 10 | // 11 | // Canyon is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with Canyon. If not, see . 18 | 19 | #![cfg_attr(not(feature = "std"), no_std)] 20 | #![allow(clippy::too_many_arguments)] 21 | 22 | pub use cp_consensus_poa::PoaConfiguration; 23 | 24 | sp_api::decl_runtime_apis! { 25 | /// The poa API. 26 | pub trait PoaApi { 27 | /// Returns the configuration of PoA consensus. 28 | fn poa_config() -> PoaConfiguration; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /client/datastore/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "cc-datastore" 3 | version = "0.1.0" 4 | authors = ["Canyon Labs "] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | codec = { package = "parity-scale-codec", version = "2.3", features = ["derive"] } 9 | log = "0.4" 10 | thiserror = "1.0" 11 | 12 | sp-api = { git = "https://github.com/paritytech/substrate", branch = "master" } 13 | sp-blockchain = { git = "https://github.com/paritytech/substrate", branch = "master" } 14 | sp-core = { git = "https://github.com/paritytech/substrate", branch = "master" } 15 | sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master" } 16 | sp-offchain = { git = "https://github.com/paritytech/substrate", branch = "master" } 17 | 18 | sc-client-db = { git = "https://github.com/paritytech/substrate", branch = "master" } 19 | 20 | canyon-primitives = { path = "../../primitives" } 21 | cp-permastore = { path = "../../primitives/permastore" } 22 | 23 | [dev-dependencies] 24 | sp-keystore = { git = "https://github.com/paritytech/substrate", branch = "master" } 25 | substrate-test-runtime-client = { git = "https://github.com/paritytech/substrate", branch = "master" } 26 | 27 | [features] 28 | test-helpers = [] 29 | -------------------------------------------------------------------------------- /primitives/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "canyon-primitives" 3 | version = "0.1.0" 4 | authors = ["Canyon Labs "] 5 | edition = "2018" 6 | 7 | [package.metadata.docs.rs] 8 | targets = ["x86_64-unknown-linux-gnu"] 9 | 10 | [dependencies] 11 | codec = { package = "parity-scale-codec", version = "2.3", default-features = false, features = ["derive"] } 12 | scale-info = { version = "1.0", default-features = false, features = ["derive"] } 13 | 14 | sp-application-crypto = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" } 15 | sp-core = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" } 16 | sp-inherents = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" } 17 | sp-runtime = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" } 18 | 19 | frame-system = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" } 20 | 21 | [features] 22 | default = ["std"] 23 | std = [ 24 | "codec/std", 25 | "scale-info/std", 26 | "sp-application-crypto/std", 27 | "sp-core/std", 28 | "sp-inherents/std", 29 | "sp-runtime/std", 30 | "frame-system/std", 31 | ] 32 | -------------------------------------------------------------------------------- /cli/src/lib.rs: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | // This file is part of Canyon. 3 | // 4 | // Copyright (c) 2021 Canyon Labs. 5 | // 6 | // Canyon is free software: you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published 8 | // by the Free Software Foundation, either version 3 of the License, 9 | // or (at your option) any later version. 10 | // 11 | // Canyon is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with Canyon. If not, see . 18 | 19 | //! Substrate CLI library. 20 | //! 21 | //! This package has two Cargo features: 22 | //! 23 | //! - `cli` (default): exposes functions that parse command-line options, then start and run the 24 | //! node as a CLI application. 25 | 26 | #![warn(missing_docs)] 27 | 28 | pub mod chain_spec; 29 | 30 | #[macro_use] 31 | mod service; 32 | #[cfg(feature = "cli")] 33 | mod cli; 34 | #[cfg(feature = "cli")] 35 | mod command; 36 | 37 | #[cfg(feature = "cli")] 38 | pub use cli::*; 39 | #[cfg(feature = "cli")] 40 | pub use command::*; 41 | -------------------------------------------------------------------------------- /.github/workflows/rustdoc.yml: -------------------------------------------------------------------------------- 1 | name: rustdoc 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | 8 | env: 9 | CARGO_INCREMENTAL: 0 10 | CARGO_NET_RETRY: 10 11 | # RUSTFLAGS: "-D warnings -W unreachable-pub" 12 | RUSTFLAGS: "-W unreachable-pub" 13 | RUSTUP_MAX_RETRIES: 10 14 | 15 | jobs: 16 | rustdoc: 17 | runs-on: ubuntu-latest 18 | 19 | steps: 20 | - name: Checkout repository 21 | uses: actions/checkout@v2 22 | 23 | - name: Install Rust toolchain 24 | uses: actions-rs/toolchain@v1 25 | with: 26 | toolchain: nightly 27 | target: wasm32-unknown-unknown 28 | profile: minimal 29 | override: true 30 | components: rustfmt, rust-src 31 | 32 | # Build the rust crate docs 33 | # Use `RUSTC_BOOTSTRAP` in order to use the `--enable-index-page` flag of rustdoc 34 | # This is needed in order to generate a landing page `index.html` for workspaces 35 | - name: Build Documentation 36 | run: cargo doc --all --no-deps --lib 37 | env: 38 | RUSTC_BOOTSTRAP: 1 39 | RUSTDOCFLAGS: "-Z unstable-options --enable-index-page" 40 | 41 | - name: Deploy Docs 42 | uses: JamesIves/github-pages-deploy-action@releases/v3 43 | with: 44 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 45 | BRANCH: gh-pages 46 | FOLDER: target/doc 47 | -------------------------------------------------------------------------------- /client/consensus/poa/benches/benchmark.rs: -------------------------------------------------------------------------------- 1 | use criterion::{black_box, criterion_group, criterion_main, Criterion}; 2 | use rand::Rng; 3 | 4 | use cc_consensus_poa::{ChunkProof, ChunkProofBuilder}; 5 | use cp_permastore::CHUNK_SIZE; 6 | 7 | fn generate_chunk_proof(data: Vec, offset: u32) -> ChunkProof { 8 | ChunkProofBuilder::new(data, CHUNK_SIZE, offset) 9 | .build() 10 | .expect("failed to build chunk proof") 11 | } 12 | 13 | fn random_data(data_size: usize) -> Vec { 14 | let mut rng = rand::thread_rng(); 15 | (0..data_size).map(|_| rng.gen::()).collect() 16 | } 17 | 18 | fn chunk_proof_benchmark(c: &mut Criterion) { 19 | let data = random_data(10 * 1024 * 1024); 20 | c.bench_function("chunk proof generation 10MiB", |b| { 21 | b.iter(|| generate_chunk_proof(black_box(data.clone()), black_box(20))) 22 | }); 23 | 24 | let data = random_data(100 * 1024 * 1024); 25 | c.bench_function("chunk proof generation 100MiB", |b| { 26 | b.iter(|| generate_chunk_proof(black_box(data.clone()), black_box(20))) 27 | }); 28 | 29 | let data = random_data(1024 * 1024 * 1024); 30 | c.bench_function("chunk proof generation 1GiB", |b| { 31 | b.iter(|| generate_chunk_proof(black_box(data.clone()), black_box(20))) 32 | }); 33 | } 34 | 35 | criterion_group!(benches, chunk_proof_benchmark); 36 | criterion_main!(benches); 37 | -------------------------------------------------------------------------------- /primitives/consensus/poa/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "cp-consensus-poa" 3 | version = "0.1.0" 4 | authors = ["Canyon Labs "] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | codec = { package = "parity-scale-codec", version = "2.3", default-features = false, features = ["derive"] } 9 | scale-info = { version = "1.0", default-features = false, features = ["derive"] } 10 | serde = { version = "1.0.101", optional = true } 11 | 12 | sp-api = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" } 13 | sp-core = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" } 14 | sp-inherents = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" } 15 | sp-io = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" } 16 | sp-runtime = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" } 17 | sp-std = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" } 18 | sp-trie = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" } 19 | 20 | [features] 21 | default = ["std"] 22 | std = [ 23 | "codec/std", 24 | "scale-info/std", 25 | "serde", 26 | "sp-api/std", 27 | "sp-core/std", 28 | "sp-inherents/std", 29 | "sp-io/std", 30 | "sp-runtime/std", 31 | "sp-std/std", 32 | "sp-trie/std", 33 | ] 34 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 |

Canyon Network

3 | 4 | [![Continuous integration](https://github.com/canyon-network/canyon/actions/workflows/ci.yml/badge.svg)](https://github.com/canyon-network/canyon/actions/workflows/ci.yml) 5 | [![License: GPL v3](https://img.shields.io/badge/License-GPL%20v3-blue.svg)](http://www.gnu.org/licenses/gpl-3.0) 6 | [![Telegram](https://img.shields.io/badge/Telegram-gray?logo=telegram)](https://t.me/CanyonNetwork) 7 | [![Rustdoc](https://img.shields.io/badge/Rustdoc-blue?logo=rust)](https://canyon-network.io/canyon) 8 | 9 |
10 | 11 | 12 | 13 | Canyon network aims to be a permanent storage layer for Web3.0 built on Substrate framework, focusing on lightweight storage consensus as well as the high usability of data retrieval. Find more in the [white paper](https://canyon-network.github.io/canyon-white-paper/canyon_network.pdf). 14 | 15 | Please be aware of that the project is now at a fairly early stage and nothing is production ready. 16 | 17 | ## Build 18 | 19 | ```bash 20 | $ git clone https://github.com/canyon-network/canyon 21 | $ cd canyon 22 | # The built release binary can be found in target/release/canyon. 23 | $ cargo build --release 24 | ``` 25 | 26 | ## Contribution 27 | 28 | We highly appreciate any kind of contributions, feel free to reach out if you have any ideas about our design and are interested in our vision. 29 | 30 | ## License 31 | 32 | [GPL v3](./LICENSE) 33 | -------------------------------------------------------------------------------- /executor/src/lib.rs: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | // This file is part of Canyon. 3 | // 4 | // Copyright (c) 2021 Canyon Labs. 5 | // 6 | // Canyon is free software: you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published 8 | // by the Free Software Foundation, either version 3 of the License, 9 | // or (at your option) any later version. 10 | // 11 | // Canyon is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with Canyon. If not, see . 18 | 19 | //! A `CodeExecutor` specialization which uses natively compiled runtime when the wasm to be 20 | //! executed is equivalent to the natively compiled code. 21 | 22 | pub use sc_executor::NativeElseWasmExecutor; 23 | 24 | // Declare an instance of the native executor named `Executor`. Include the wasm binary as the 25 | // equivalent wasm code. 26 | pub struct ExecutorDispatch; 27 | 28 | impl sc_executor::NativeExecutionDispatch for ExecutorDispatch { 29 | type ExtendHostFunctions = frame_benchmarking::benchmarking::HostFunctions; 30 | 31 | fn dispatch(method: &str, data: &[u8]) -> Option> { 32 | canyon_runtime::api::dispatch(method, data) 33 | } 34 | 35 | fn native_version() -> sc_executor::NativeVersion { 36 | canyon_runtime::native_version() 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /client/rpc/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "cc-rpc" 3 | version = "0.1.0" 4 | authors = ["Canyon Labs "] 5 | edition = "2018" 6 | license = "GPL-3.0" 7 | homepage = "https://canyon-network.io" 8 | repository = "https://github.com/canyon-network/canyon/" 9 | 10 | [package.metadata.docs.rs] 11 | targets = ["x86_64-unknown-linux-gnu"] 12 | 13 | [dependencies] 14 | futures = "0.3.16" 15 | jsonrpc-core = "18.0.0" 16 | jsonrpc-core-client = "18.0.0" 17 | jsonrpc-derive = "18.0.0" 18 | log = "0.4" 19 | parking_lot = "0.11" 20 | 21 | sc-rpc-api = { git = "https://github.com/paritytech/substrate", branch = "master" } 22 | sc-transaction-pool-api = { git = "https://github.com/paritytech/substrate", branch = "master" } 23 | 24 | sp-core = { git = "https://github.com/paritytech/substrate", branch = "master" } 25 | sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master" } 26 | 27 | cc-rpc-api = { path = "../rpc-api" } 28 | cp-permastore = { path = "../../primitives/permastore" } 29 | 30 | [dev-dependencies] 31 | assert_matches = "1.3.0" 32 | codec = { package = "parity-scale-codec", version = "2.3" } 33 | jsonrpc-pubsub = "18.0.0" 34 | 35 | sc-rpc = { git = "https://github.com/paritytech/substrate", features = ["test-helpers"] , branch = "master" } 36 | sc-transaction-pool = { git = "https://github.com/paritytech/substrate", branch = "master" } 37 | sp-keystore = { git = "https://github.com/paritytech/substrate", branch = "master" } 38 | substrate-test-runtime-client = { git = "https://github.com/paritytech/substrate", branch = "master" } 39 | 40 | cc-datastore = { path = "../datastore", features = ["test-helpers"] } 41 | -------------------------------------------------------------------------------- /.github/workflows/docker.yml: -------------------------------------------------------------------------------- 1 | name: docker 2 | 3 | on: 4 | push: 5 | branches: 6 | - 'master' 7 | tags: 8 | - 'v*' 9 | pull_request: 10 | branches: 11 | - 'master' 12 | 13 | jobs: 14 | docker: 15 | runs-on: ubuntu-latest 16 | steps: 17 | - name: Checkout 18 | uses: actions/checkout@v2 19 | 20 | - name: Set up Docker Buildx 21 | uses: docker/setup-buildx-action@v1 22 | 23 | - name: Cache Docker layers 24 | uses: actions/cache@v2 25 | with: 26 | path: /tmp/.buildx-cache 27 | key: ${{ runner.os }}-buildx-${{ github.sha }} 28 | restore-keys: | 29 | ${{ runner.os }}-buildx- 30 | 31 | - name: Docker meta 32 | id: meta 33 | uses: docker/metadata-action@v3 34 | with: 35 | images: canyonlabs/canyon 36 | 37 | - name: Login to DockerHub 38 | if: github.event_name != 'pull_request' 39 | uses: docker/login-action@v1 40 | with: 41 | username: ${{ secrets.DOCKERHUB_USERNAME }} 42 | password: ${{ secrets.DOCKERHUB_ACCESS_TOKEN }} 43 | 44 | - name: Build and push 45 | id: docker_build 46 | uses: docker/build-push-action@v2 47 | with: 48 | context: . 49 | push: ${{ github.event_name != 'pull_request' }} 50 | tags: ${{ steps.meta.outputs.tags }} 51 | labels: ${{ steps.meta.outputs.labels }} 52 | cache-from: type=local,src=/tmp/.buildx-cache 53 | cache-to: type=local,dest=/tmp/.buildx-cache 54 | 55 | - name: Image digest 56 | run: echo ${{ steps.docker_build.outputs.digest }} 57 | -------------------------------------------------------------------------------- /pallets/permastore/src/benchmarking.rs: -------------------------------------------------------------------------------- 1 | use codec::Encode; 2 | 3 | use frame_benchmarking::{benchmarks, impl_benchmark_test_suite, whitelisted_caller}; 4 | use frame_support::traits::Currency; 5 | use frame_system::RawOrigin; 6 | use sp_runtime::traits::Hash; 7 | 8 | use crate::{Call, Config, Pallet}; 9 | 10 | benchmarks! { 11 | store { 12 | let caller = whitelisted_caller(); 13 | let balance = 10_000u32; 14 | let data = b"transaction data"; 15 | let min = T::Currency::minimum_balance().max(1u32.into()); 16 | T::Currency::make_free_balance_be(&caller, min * balance.into()); 17 | let chunk_root = T::Hashing::hash(&data.encode()[..]); 18 | }: store (RawOrigin::Signed(caller), data.len() as u32, chunk_root) 19 | verify { 20 | // TODO 21 | } 22 | 23 | forget { 24 | let caller: T::AccountId = whitelisted_caller(); 25 | let balance = 10_000u32; 26 | let min = T::Currency::minimum_balance().max(1u32.into()); 27 | T::Currency::make_free_balance_be(&caller, min * balance.into()); 28 | let block_number: T::BlockNumber = 100u32.into(); 29 | frame_system::Pallet::::set_block_number(block_number); 30 | let data = b"transaction data"; 31 | let chunk_root = T::Hashing::hash(&data.encode()[..]); 32 | Pallet::::store(RawOrigin::Signed(caller.clone()).into(), data.len() as u32, chunk_root)?; 33 | let extrinsic_index = 0u32; 34 | }: forget (RawOrigin::Signed(caller), block_number, extrinsic_index) 35 | verify { 36 | // TODO 37 | } 38 | } 39 | 40 | impl_benchmark_test_suite!(Pallet, crate::mock::new_test_ext(), crate::mock::Test); 41 | -------------------------------------------------------------------------------- /client/datastore/src/tests.rs: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | // This file is part of Canyon. 3 | // 4 | // Copyright (c) 2021 Canyon Labs. 5 | // 6 | // Canyon is free software: you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published 8 | // by the Free Software Foundation, either version 3 of the License, 9 | // or (at your option) any later version. 10 | // 11 | // Canyon is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with Canyon. If not, see . 18 | 19 | use std::sync::Arc; 20 | 21 | use sp_keystore::testing::KeyStore; 22 | use substrate_test_runtime_client::DefaultTestClientBuilderExt; 23 | use substrate_test_runtime_client::TestClientBuilderExt; 24 | 25 | use cp_permastore::PermaStorage; 26 | 27 | use crate::PermanentStorage; 28 | 29 | #[test] 30 | fn basic_operations_should_work() { 31 | let keystore = Arc::new(KeyStore::new()); 32 | let client_builder = substrate_test_runtime_client::TestClientBuilder::new(); 33 | let client = Arc::new(client_builder.set_keystore(keystore.clone()).build()); 34 | 35 | let mut perma_storage = PermanentStorage::new_test(client.clone()); 36 | 37 | perma_storage.submit(b"key", b"value"); 38 | 39 | assert!(perma_storage.exists(b"key")); 40 | assert_eq!(perma_storage.retrieve(b"key"), Some(b"value".to_vec())); 41 | 42 | perma_storage.remove(b"key"); 43 | assert!(!perma_storage.exists(b"key")); 44 | assert_eq!(perma_storage.retrieve(b"key"), None); 45 | } 46 | -------------------------------------------------------------------------------- /inspect/src/cli.rs: -------------------------------------------------------------------------------- 1 | // This file is part of Canyon. 2 | 3 | // Copyright (C) 2021 Canyon Network. 4 | // License: GPL-3.0 5 | 6 | //! Structs to easily compose inspect sub-command for CLI. 7 | 8 | use std::fmt::Debug; 9 | 10 | use structopt::StructOpt; 11 | 12 | use sc_cli::{ImportParams, SharedParams}; 13 | 14 | /// The `inspect` command used to print decoded chain data. 15 | #[derive(Debug, StructOpt)] 16 | pub struct InspectCmd { 17 | #[allow(missing_docs)] 18 | #[structopt(flatten)] 19 | pub command: InspectSubCmd, 20 | 21 | #[allow(missing_docs)] 22 | #[structopt(flatten)] 23 | pub shared_params: SharedParams, 24 | 25 | #[allow(missing_docs)] 26 | #[structopt(flatten)] 27 | pub import_params: ImportParams, 28 | } 29 | 30 | /// A possible inspect sub-commands. 31 | #[derive(Debug, StructOpt)] 32 | pub enum InspectSubCmd { 33 | /// Decode block with native version of runtime and print out the details. 34 | Block { 35 | /// Address of the block to print out. 36 | /// 37 | /// Can be either a block hash (no 0x prefix) or a number to retrieve existing block, 38 | /// or a 0x-prefixed bytes hex string, representing SCALE encoding of 39 | /// a block. 40 | #[structopt(value_name = "HASH or NUMBER or BYTES")] 41 | input: String, 42 | }, 43 | /// Decode extrinsic with native version of runtime and print out the details. 44 | Extrinsic { 45 | /// Address of an extrinsic to print out. 46 | /// 47 | /// Can be either a block hash (no 0x prefix) or number and the index, in the form 48 | /// of `{block}:{index}` or a 0x-prefixed bytes hex string, 49 | /// representing SCALE encoding of an extrinsic. 50 | #[structopt(value_name = "BLOCK:INDEX or BYTES")] 51 | input: String, 52 | }, 53 | } 54 | -------------------------------------------------------------------------------- /pallets/permastore/src/tests.rs: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | // This file is part of Canyon. 3 | // 4 | // Copyright (c) 2021 Canyon Labs. 5 | // 6 | // Canyon is free software: you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published 8 | // by the Free Software Foundation, either version 3 of the License, 9 | // or (at your option) any later version. 10 | // 11 | // Canyon is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with Canyon. If not, see . 18 | 19 | use frame_support::traits::OnFinalize; 20 | 21 | use crate::{ 22 | mock::{new_test_ext, Permastore, Test}, 23 | *, 24 | }; 25 | 26 | #[test] 27 | fn find_recall_block_should_work() { 28 | new_test_ext().execute_with(|| { 29 | BlockDataSize::::put(5); 30 | >::put(5); 31 | 32 | // [5] 33 | // [1] 34 | >::on_finalize(1); 35 | 36 | BlockDataSize::::put(7); 37 | >::put(5 + 7); 38 | 39 | // [5, 12] 40 | // [1, 4] 41 | >::on_finalize(4); 42 | 43 | BlockDataSize::::put(10); 44 | >::put(5 + 7 + 10); 45 | 46 | // [5, 12, 22] 47 | // [1, 4, 10] 48 | >::on_finalize(10); 49 | 50 | assert_eq!(Pallet::::find_recall_block(3), Some(1)); 51 | assert_eq!(Pallet::::find_recall_block(12), Some(4)); 52 | assert_eq!(Pallet::::find_recall_block(13), Some(10)); 53 | assert_eq!(Pallet::::find_recall_block(15), Some(10)); 54 | }); 55 | } 56 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # Forked from https://github.com/paritytech/substrate/blob/efd54879ecbf8aac41fe809d31c7215ea3101241/.maintain/Dockerfile 2 | # 3 | # Note: We don't use Alpine and its packaged Rust/Cargo because they're too often out of date, 4 | # preventing them from being used to build canyon/Polkadot. 5 | 6 | FROM phusion/baseimage:0.11 as builder 7 | LABEL maintainer="xuliuchengxlc@gmail.com" 8 | LABEL description="This is the build stage for Canyon. Here we create the binary." 9 | 10 | ENV DEBIAN_FRONTEND=noninteractive 11 | 12 | ARG PROFILE=release 13 | WORKDIR /canyon 14 | 15 | COPY . /canyon 16 | 17 | RUN apt-get update && \ 18 | apt-get dist-upgrade -y -o Dpkg::Options::="--force-confold" && \ 19 | apt-get install -y cmake pkg-config libssl-dev git clang 20 | 21 | RUN curl https://sh.rustup.rs -sSf | sh -s -- -y && \ 22 | export PATH="$PATH:$HOME/.cargo/bin" && \ 23 | rustup toolchain install nightly && \ 24 | rustup target add wasm32-unknown-unknown --toolchain nightly && \ 25 | rustup default stable && \ 26 | cargo build "--$PROFILE" 27 | 28 | # ===== SECOND STAGE ====== 29 | 30 | FROM phusion/baseimage:0.11 31 | LABEL maintainer="xuliuchengxlc@gmail.com" 32 | LABEL description="This is the 2nd stage: a very small image where we copy the canyon binary." 33 | ARG PROFILE=release 34 | 35 | RUN mv /usr/share/ca* /tmp && \ 36 | rm -rf /usr/share/* && \ 37 | mv /tmp/ca-certificates /usr/share/ && \ 38 | useradd -m -u 1000 -U -s /bin/sh -d /canyon canyon && \ 39 | mkdir -p /canyon/.local/share/canyon && \ 40 | chown -R canyon:canyon /canyon/.local && \ 41 | ln -s /canyon/.local/share/canyon /data 42 | 43 | COPY --from=builder /canyon/target/$PROFILE/canyon /usr/local/bin 44 | 45 | # checks 46 | RUN ldd /usr/local/bin/canyon && \ 47 | /usr/local/bin/canyon --version 48 | 49 | # Shrinking 50 | RUN rm -rf /usr/lib/python* && \ 51 | rm -rf /usr/bin /usr/sbin /usr/share/man 52 | 53 | USER canyon 54 | EXPOSE 30333 9933 9944 9615 55 | VOLUME ["/data"] 56 | 57 | CMD ["/usr/local/bin/canyon"] 58 | -------------------------------------------------------------------------------- /inspect/src/command.rs: -------------------------------------------------------------------------------- 1 | // This file is part of Canyon. 2 | 3 | // Copyright (C) 2021 Canyon Network. 4 | // License: GPL-3.0 5 | 6 | //! Command ran by the CLI 7 | 8 | use std::str::FromStr; 9 | 10 | use sc_cli::{CliConfiguration, ImportParams, Result, SharedParams}; 11 | use sc_executor::NativeElseWasmExecutor; 12 | use sc_service::{new_full_client, Configuration, NativeExecutionDispatch}; 13 | use sp_runtime::traits::Block; 14 | 15 | use crate::cli::{InspectCmd, InspectSubCmd}; 16 | use crate::Inspector; 17 | 18 | impl InspectCmd { 19 | /// Run the inspect command, passing the inspector. 20 | pub fn run(&self, config: Configuration) -> Result<()> 21 | where 22 | B: Block, 23 | B::Hash: FromStr, 24 | RA: Send + Sync + 'static, 25 | EX: NativeExecutionDispatch + 'static, 26 | { 27 | let executor = NativeElseWasmExecutor::::new( 28 | config.wasm_method, 29 | config.default_heap_pages, 30 | config.max_runtime_instances, 31 | ); 32 | 33 | let client = new_full_client::(&config, None, executor)?; 34 | let inspect = Inspector::::new(client); 35 | 36 | match &self.command { 37 | InspectSubCmd::Block { input } => { 38 | let input = input.parse()?; 39 | let res = inspect.block(input).map_err(|e| format!("{}", e))?; 40 | println!("{}", res); 41 | Ok(()) 42 | } 43 | InspectSubCmd::Extrinsic { input } => { 44 | let input = input.parse()?; 45 | let res = inspect.extrinsic(input).map_err(|e| format!("{}", e))?; 46 | println!("{}", res); 47 | Ok(()) 48 | } 49 | } 50 | } 51 | } 52 | 53 | impl CliConfiguration for InspectCmd { 54 | fn shared_params(&self) -> &SharedParams { 55 | &self.shared_params 56 | } 57 | 58 | fn import_params(&self) -> Option<&ImportParams> { 59 | Some(&self.import_params) 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /client/consensus/poa/src/trie.rs: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | // This file is part of Canyon. 3 | // 4 | // Copyright (c) 2021 Canyon Labs. 5 | // 6 | // Canyon is free software: you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published 8 | // by the Free Software Foundation, either version 3 of the License, 9 | // or (at your option) any later version. 10 | // 11 | // Canyon is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with Canyon. If not, see . 18 | 19 | use sp_trie::{empty_trie_root, MemoryDB, TrieDBMut, TrieMut}; 20 | 21 | use cp_consensus_poa::encode_index; 22 | use cp_permastore::{Hasher, TrieLayout}; 23 | 24 | /// Error type for building a trie proof. 25 | #[derive(Debug, thiserror::Error)] 26 | pub enum TrieError { 27 | /// Trie error. 28 | #[error(transparent)] 29 | Trie(#[from] Box), 30 | } 31 | 32 | /// Prepares the components for building a trie proof given the final leaf nodes. 33 | /// 34 | /// # Panics 35 | /// 36 | /// Panics if the insertion of trie node failed. 37 | pub fn prepare_trie_proof(leaves: Vec>) -> (MemoryDB, sp_core::H256) { 38 | let mut db = MemoryDB::::default(); 39 | let mut root = empty_trie_root::(); 40 | 41 | { 42 | let mut trie = TrieDBMut::::new(&mut db, &mut root); 43 | 44 | for (index, leaf) in leaves.iter().enumerate() { 45 | trie.insert(&encode_index(index as u32), leaf) 46 | .unwrap_or_else(|e| { 47 | panic!("Failed to insert the trie node: {:?}, index: {}", e, index) 48 | }); 49 | } 50 | 51 | trie.commit(); 52 | } 53 | 54 | (db, root) 55 | } 56 | -------------------------------------------------------------------------------- /runtime/src/impls.rs: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | // This file is part of Canyon. 3 | // 4 | // Copyright (c) 2021 Canyon Labs. 5 | // 6 | // Canyon is free software: you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published 8 | // by the Free Software Foundation, either version 3 of the License, 9 | // or (at your option) any later version. 10 | // 11 | // Canyon is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with Canyon. If not, see . 18 | 19 | //! Some configurable implementations as associated type for the substrate runtime. 20 | 21 | use crate::{AccountId, Authorship, Balances, Treasury}; 22 | use frame_support::traits::{Currency, Imbalance, OnUnbalanced}; 23 | 24 | type NegativeImbalance = >::NegativeImbalance; 25 | 26 | pub struct Author; 27 | impl OnUnbalanced for Author { 28 | fn on_nonzero_unbalanced(amount: NegativeImbalance) { 29 | Balances::resolve_creating(&Authorship::author(), amount); 30 | } 31 | } 32 | 33 | pub struct DealWithFees; 34 | impl OnUnbalanced for DealWithFees { 35 | fn on_unbalanceds(mut fees_then_tips: impl Iterator) { 36 | if let Some(fees) = fees_then_tips.next() { 37 | // for fees, 80% to treasury, 20% to author 38 | let mut split = fees.ration(80, 20); 39 | if let Some(tips) = fees_then_tips.next() { 40 | // for tips, if any, 80% to treasury, 20% to author (though this can be anything) 41 | tips.ration_merge_into(80, 20, &mut split); 42 | } 43 | Treasury::on_unbalanced(split.0); 44 | Author::on_unbalanced(split.1); 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /pallets/permastore/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "pallet-permastore" 3 | version = "0.1.0" 4 | authors = ["Canyon Labs "] 5 | edition = "2018" 6 | 7 | [package.metadata.docs.rs] 8 | targets = ["x86_64-unknown-linux-gnu"] 9 | 10 | [dependencies] 11 | codec = { package = "parity-scale-codec", version = "2.3", default-features = false, features = ["derive", "max-encoded-len"] } 12 | scale-info = { version = "1.0", default-features = false, features = ["derive"] } 13 | serde = { version = "1.0.101", optional = true } 14 | 15 | sp-io = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" } 16 | sp-runtime = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" } 17 | sp-std = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" } 18 | 19 | frame-benchmarking = { git = "https://github.com/paritytech/substrate", default-features = false, optional = true , branch = "master" } 20 | frame-support = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" } 21 | frame-system = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" } 22 | pallet-balances = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" } 23 | 24 | canyon-primitives = { path = "../../primitives/", default-features = false } 25 | cp-consensus-poa = { path = "../../primitives/consensus/poa", default-features = false } 26 | 27 | [dev-dependencies] 28 | sp-core = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" } 29 | 30 | [features] 31 | default = ["std"] 32 | std = [ 33 | "codec/std", 34 | "scale-info/std", 35 | "serde", 36 | "sp-io/std", 37 | "sp-runtime/std", 38 | "sp-std/std", 39 | "frame-benchmarking/std", 40 | "frame-support/std", 41 | "frame-system/std", 42 | "pallet-balances/std", 43 | "canyon-primitives/std", 44 | "cp-consensus-poa/std", 45 | ] 46 | runtime-benchmarks = ["frame-benchmarking"] 47 | try-runtime = ["frame-support/try-runtime"] 48 | -------------------------------------------------------------------------------- /client/rpc-api/src/permastore/mod.rs: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | // This file is part of Canyon. 3 | // 4 | // Copyright (c) 2021 Canyon Labs. 5 | // 6 | // Canyon is free software: you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published 8 | // by the Free Software Foundation, either version 3 of the License, 9 | // or (at your option) any later version. 10 | // 11 | // Canyon is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with Canyon. If not, see . 18 | 19 | pub mod error; 20 | 21 | use jsonrpc_derive::rpc; 22 | 23 | use sc_rpc_api::author::{error::FutureResult, hash::ExtrinsicOrHash}; 24 | 25 | use sp_core::{Bytes, H256}; 26 | 27 | use self::error::Result; 28 | 29 | pub use self::gen_client::Client as OffchainClient; 30 | 31 | /// Canyon perma storage RPC API. 32 | #[rpc] 33 | pub trait PermastoreApi { 34 | /// Sepecialized `submit_extrinsic` for submitting the store extrinsic and transaction data. 35 | #[rpc(name = "permastore_submitExtrinsic")] 36 | fn submit_extrinsic(&self, ext: Bytes, data: Bytes) -> FutureResult; 37 | 38 | /// Sepecialized `remove_extrinsic` for removing the extrinsic and data if any. 39 | #[rpc(name = "permastore_removeExtrinsic")] 40 | fn remove_extrinsic(&self, bytes_or_hash: Vec>) -> Result>; 41 | 42 | /// Remove the data of a transaction. 43 | #[rpc(name = "permastore_removeData")] 44 | fn remove_data(&self, chunk_root: BlockHash) -> Result; 45 | 46 | /// Submit the whole data of a transaction. 47 | #[rpc(name = "permastore_submit")] 48 | fn submit(&self, value: Bytes) -> Result; 49 | 50 | /// Fetch storage under given key. 51 | #[rpc(name = "permastore_retrieve")] 52 | fn retrieve(&self, key: Bytes) -> Result>; 53 | } 54 | -------------------------------------------------------------------------------- /client/consensus/poa/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "cc-consensus-poa" 3 | version = "0.1.0" 4 | authors = ["Canyon Labs "] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | async-trait = "0.1.47" 9 | codec = { package = "parity-scale-codec", version = "2.3" } 10 | log = "0.4" 11 | thiserror = "1.0" 12 | 13 | sp-api = { git = "https://github.com/paritytech/substrate", branch = "master" } 14 | sp-blockchain = { git = "https://github.com/paritytech/substrate", branch = "master" } 15 | sp-block-builder = { git = "https://github.com/paritytech/substrate", branch = "master" } 16 | sp-consensus = { git = "https://github.com/paritytech/substrate", branch = "master" } 17 | sp-core = { git = "https://github.com/paritytech/substrate", branch = "master" } 18 | sp-inherents = { git = "https://github.com/paritytech/substrate", branch = "master" } 19 | sp-io = { git = "https://github.com/paritytech/substrate", branch = "master" } 20 | sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master" } 21 | sp-trie = { git = "https://github.com/paritytech/substrate", branch = "master" } 22 | 23 | sc-client-api = { git = "https://github.com/paritytech/substrate", branch = "master" } 24 | sc-consensus = { git = "https://github.com/paritytech/substrate", branch = "master" } 25 | 26 | canyon-primitives = { path = "../../../primitives" } 27 | cc-datastore = { path = "../../datastore" } 28 | cp-consensus-poa = { path = "../../../primitives/consensus/poa" } 29 | cp-permastore = { path = "../../../primitives/permastore" } 30 | cp-poa = { path = "../../../primitives/poa" } 31 | 32 | [dev-dependencies] 33 | criterion = "0.3" 34 | rand = "0.8" 35 | 36 | sc-block-builder = { git = "https://github.com/paritytech/substrate", branch = "master" } 37 | sp-keyring = { git = "https://github.com/paritytech/substrate", branch = "master" } 38 | sp-state-machine = { git = "https://github.com/paritytech/substrate", branch = "master" } 39 | substrate-test-runtime = { git = "https://github.com/paritytech/substrate", branch = "master" } 40 | substrate-test-runtime-client = { git = "https://github.com/paritytech/substrate", branch = "master" } 41 | 42 | [[bench]] 43 | name = "benchmark" 44 | harness = false 45 | -------------------------------------------------------------------------------- /cli/build.rs: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | // This file is part of Canyon. 3 | // 4 | // Copyright (c) 2021 Canyon Labs. 5 | // 6 | // Canyon is free software: you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published 8 | // by the Free Software Foundation, either version 3 of the License, 9 | // or (at your option) any later version. 10 | // 11 | // Canyon is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with Canyon. If not, see . 18 | 19 | fn main() { 20 | #[cfg(feature = "cli")] 21 | cli::main(); 22 | } 23 | 24 | #[cfg(feature = "cli")] 25 | mod cli { 26 | include!("src/cli.rs"); 27 | 28 | use sc_cli::structopt::clap::Shell; 29 | use std::{env, fs, path::Path}; 30 | use substrate_build_script_utils::{generate_cargo_keys, rerun_if_git_head_changed}; 31 | 32 | pub fn main() { 33 | build_shell_completion(); 34 | generate_cargo_keys(); 35 | 36 | rerun_if_git_head_changed(); 37 | } 38 | 39 | /// Build shell completion scripts for all known shells 40 | /// Full list in https://github.com/kbknapp/clap-rs/blob/e9d0562a1dc5dfe731ed7c767e6cee0af08f0cf9/src/app/parser.rs#L123 41 | fn build_shell_completion() { 42 | for shell in &[ 43 | Shell::Bash, 44 | Shell::Fish, 45 | Shell::Zsh, 46 | Shell::Elvish, 47 | Shell::PowerShell, 48 | ] { 49 | build_completion(shell); 50 | } 51 | } 52 | 53 | /// Build the shell auto-completion for a given Shell 54 | fn build_completion(shell: &Shell) { 55 | let outdir = match env::var_os("OUT_DIR") { 56 | None => return, 57 | Some(dir) => dir, 58 | }; 59 | let path = Path::new(&outdir) 60 | .parent() 61 | .unwrap() 62 | .parent() 63 | .unwrap() 64 | .parent() 65 | .unwrap() 66 | .join("completion-scripts"); 67 | 68 | fs::create_dir(&path).ok(); 69 | 70 | Cli::clap().gen_completions("substrate-node", *shell, &path); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | on: [push, pull_request] 2 | 3 | name: Continuous integration 4 | 5 | jobs: 6 | fmt: 7 | name: Rustfmt 8 | runs-on: ubuntu-latest 9 | steps: 10 | - uses: actions/checkout@v2 11 | - uses: actions-rs/toolchain@v1 12 | with: 13 | profile: minimal 14 | toolchain: stable 15 | override: true 16 | components: rust-src, rustfmt 17 | - uses: Swatinem/rust-cache@v1 18 | - uses: actions-rs/cargo@v1 19 | with: 20 | command: fmt 21 | args: --all -- --check 22 | 23 | clippy: 24 | name: Clippy 25 | runs-on: ubuntu-latest 26 | steps: 27 | - uses: actions/checkout@v2 28 | - uses: actions-rs/toolchain@v1 29 | with: 30 | profile: minimal 31 | target: wasm32-unknown-unknown 32 | toolchain: nightly-2021-09-07 33 | override: true 34 | components: rust-src, clippy 35 | - uses: Swatinem/rust-cache@v1 36 | # args: -- -D warnings 37 | - run: cargo +nightly-2021-09-07 clippy 38 | 39 | check: 40 | name: Check 41 | runs-on: ubuntu-latest 42 | steps: 43 | - uses: actions/checkout@v2 44 | - uses: actions-rs/toolchain@v1 45 | with: 46 | profile: minimal 47 | target: wasm32-unknown-unknown 48 | toolchain: nightly 49 | override: true 50 | - uses: Swatinem/rust-cache@v1 51 | - run: cargo +stable check 52 | 53 | test: 54 | name: Test Suite 55 | runs-on: ubuntu-latest 56 | steps: 57 | - uses: actions/checkout@v2 58 | - uses: actions-rs/toolchain@v1 59 | with: 60 | profile: minimal 61 | target: wasm32-unknown-unknown 62 | toolchain: nightly-2021-09-30 63 | override: true 64 | - run: cargo +stable test --workspace 65 | 66 | benchmarks: 67 | name: Runtime Benchmarks 68 | runs-on: ubuntu-latest 69 | steps: 70 | - uses: actions/checkout@v2 71 | - uses: actions-rs/toolchain@v1 72 | with: 73 | profile: minimal 74 | target: wasm32-unknown-unknown 75 | toolchain: nightly-2021-09-30 76 | override: true 77 | - run: cargo +stable build --features runtime-benchmarks 78 | 79 | all-ci: 80 | # This dummy job depends on all the mandatory checks. 81 | # It succeeds if and only if all checks are successful. 82 | needs: [fmt, clippy, check, test, benchmarks] 83 | runs-on: ubuntu-latest 84 | steps: 85 | - run: echo Success 86 | -------------------------------------------------------------------------------- /pallets/poa/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "pallet-poa" 3 | version = "0.1.0" 4 | authors = ["Canyon Labs "] 5 | edition = "2018" 6 | 7 | [package.metadata.docs.rs] 8 | targets = ["x86_64-unknown-linux-gnu"] 9 | 10 | [dependencies] 11 | codec = { package = "parity-scale-codec", version = "2.3", default-features = false, features = ["derive", "max-encoded-len"] } 12 | scale-info = { version = "1.0", default-features = false, features = ["derive"] } 13 | serde = { version = "1.0.101", optional = true } 14 | 15 | sp-io = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" } 16 | sp-runtime = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" } 17 | sp-std = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" } 18 | 19 | frame-benchmarking = { git = "https://github.com/paritytech/substrate", default-features = false, optional = true , branch = "master" } 20 | frame-support = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" } 21 | frame-system = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" } 22 | 23 | canyon-primitives = { path = "../../primitives/", default-features = false } 24 | cp-consensus-poa = { path = "../../primitives/consensus/poa", default-features = false } 25 | 26 | [dev-dependencies] 27 | sc-block-builder = { git = "https://github.com/paritytech/substrate", branch = "master" } 28 | sc-client-db = { git = "https://github.com/paritytech/substrate", branch = "master" } 29 | sp-blockchain = { git = "https://github.com/paritytech/substrate", branch = "master" } 30 | sp-core = { git = "https://github.com/paritytech/substrate", branch = "master" } 31 | sp-keyring = { git = "https://github.com/paritytech/substrate", branch = "master" } 32 | pallet-balances = { git = "https://github.com/paritytech/substrate", branch = "master" } 33 | substrate-test-runtime = { git = "https://github.com/paritytech/substrate", branch = "master" } 34 | substrate-test-runtime-client = { git = "https://github.com/paritytech/substrate", branch = "master" } 35 | 36 | cc-consensus-poa = { path = "../../client/consensus/poa" } 37 | cp-permastore = { path = "../../primitives/permastore" } 38 | 39 | [features] 40 | default = ["std"] 41 | std = [ 42 | "codec/std", 43 | "scale-info/std", 44 | "serde", 45 | "sp-io/std", 46 | "sp-runtime/std", 47 | "sp-std/std", 48 | "frame-benchmarking/std", 49 | "frame-support/std", 50 | "frame-system/std", 51 | "canyon-primitives/std", 52 | "cp-consensus-poa/std", 53 | ] 54 | runtime-benchmarks = ["frame-benchmarking"] 55 | try-runtime = ["frame-support/try-runtime"] 56 | -------------------------------------------------------------------------------- /rpc/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "canyon-rpc" 3 | version = "0.1.0" 4 | authors = ["Canyon Labs "] 5 | edition = "2018" 6 | license = "GPL-3.0" 7 | homepage = "https://canyon-network.io" 8 | repository = "https://github.com/canyon-network/canyon/" 9 | 10 | [package.metadata.docs.rs] 11 | targets = ["x86_64-unknown-linux-gnu"] 12 | 13 | [dependencies] 14 | jsonrpc-core = "18.0.0" 15 | serde = { version = "1.0.102", features = ["derive"] } 16 | 17 | sc-client-api = { git = "https://github.com/paritytech/substrate", branch = "master" } 18 | sc-consensus-babe = { git = "https://github.com/paritytech/substrate", branch = "master" } 19 | sc-consensus-babe-rpc = { git = "https://github.com/paritytech/substrate", branch = "master" } 20 | sc-consensus-epochs = { git = "https://github.com/paritytech/substrate", branch = "master" } 21 | sc-chain-spec = { git = "https://github.com/paritytech/substrate", branch = "master" } 22 | sc-finality-grandpa = { git = "https://github.com/paritytech/substrate", branch = "master" } 23 | sc-finality-grandpa-rpc = { git = "https://github.com/paritytech/substrate", branch = "master" } 24 | sc-keystore = { git = "https://github.com/paritytech/substrate", branch = "master" } 25 | sc-rpc = { git = "https://github.com/paritytech/substrate", branch = "master" } 26 | sc-rpc-api = { git = "https://github.com/paritytech/substrate", branch = "master" } 27 | sc-sync-state-rpc = { git = "https://github.com/paritytech/substrate", branch = "master" } 28 | sc-transaction-pool-api = { git = "https://github.com/paritytech/substrate", branch = "master" } 29 | sp-api = { git = "https://github.com/paritytech/substrate", branch = "master" } 30 | sp-block-builder = { git = "https://github.com/paritytech/substrate", branch = "master" } 31 | sp-blockchain = { git = "https://github.com/paritytech/substrate", branch = "master" } 32 | sp-core = { git = "https://github.com/paritytech/substrate", branch = "master" } 33 | sp-keystore = { git = "https://github.com/paritytech/substrate", branch = "master" } 34 | sp-consensus = { git = "https://github.com/paritytech/substrate", branch = "master" } 35 | sp-consensus-babe = { git = "https://github.com/paritytech/substrate", branch = "master" } 36 | sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master" } 37 | 38 | pallet-transaction-payment-rpc = { git = "https://github.com/paritytech/substrate", branch = "master" } 39 | substrate-frame-rpc-system = { git = "https://github.com/paritytech/substrate", branch = "master" } 40 | 41 | canyon-primitives = { path = "../primitives" } 42 | canyon-runtime = { path = "../runtime" } 43 | cp-permastore = { path = "../primitives/permastore" } 44 | 45 | cc-rpc = { path = "../client/rpc" } 46 | cc-rpc-api = { path = "../client/rpc-api" } 47 | -------------------------------------------------------------------------------- /pallets/poa/src/benchmarking.rs: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | // This file is part of Canyon. 3 | // 4 | // Copyright (c) 2021 Canyon Labs. 5 | // 6 | // Canyon is free software: you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published 8 | // by the Free Software Foundation, either version 3 of the License, 9 | // or (at your option) any later version. 10 | // 11 | // Canyon is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with Canyon. If not, see . 18 | 19 | use super::*; 20 | use cp_consensus_poa::{ChunkProof, PoaConfiguration, ProofOfAccess}; 21 | use frame_benchmarking::{benchmarks, impl_benchmark_test_suite}; 22 | use frame_system::RawOrigin; 23 | use sp_std::vec; 24 | 25 | pub(crate) fn mock_a_data_chunk() -> Vec { 26 | const ALPHABET: [u8; 32] = [ 27 | b'q', b'w', b'e', b'r', b't', b'y', b'u', b'i', b'o', b'p', b'[', b']', b'a', b's', b'd', 28 | b'f', b'g', b'h', b'j', b'k', b'l', b';', b'z', b'x', b'c', b'v', b'b', b'n', b'm', b',', 29 | b'.', b' ', 30 | ]; 31 | 32 | ALPHABET.repeat(8192) 33 | } 34 | 35 | benchmarks! { 36 | // This will measure the execution time of `deposit` for b in [1..1000] range. 37 | deposit { 38 | let chunk = mock_a_data_chunk(); 39 | 40 | // Generated by test_generate_proof_of_access() 41 | let chunk_index = 216u32; 42 | let proof = vec![vec![66, 0, 128, 180, 130, 227, 5, 251, 16, 249, 197, 243, 141, 167, 120, 84, 226, 47, 93, 191, 61, 61, 139, 214, 144, 4, 221, 111, 249, 57, 4, 88, 83, 133, 227]]; 43 | let chunk_proof = ChunkProof::new(proof, chunk, chunk_index); 44 | 45 | let tx_proof = vec![vec![129, 0, 17, 0, 0, 128, 191, 236, 85, 168, 163, 63, 16, 240, 207, 104, 174, 210, 70, 212, 151, 198, 14, 105, 220, 35, 135, 214, 71, 225, 65, 94, 149, 78, 123, 147, 77, 21], vec![64, 0]]; 46 | 47 | let poa = ProofOfAccess::new(1, tx_proof, chunk_proof); 48 | let poa_outcome = PoaOutcome::Justification(poa); 49 | }: deposit (RawOrigin::None, poa_outcome) 50 | verify { 51 | // TODO: verify deposit 52 | } 53 | 54 | set_config { 55 | let new = PoaConfiguration { 56 | max_depth: 1u32, 57 | max_tx_path: 100u32, 58 | max_chunk_path: 100u32 59 | }; 60 | }: set_config (RawOrigin::Root, new.clone()) 61 | verify { 62 | assert_eq!(new, Pallet::::poa_config()); 63 | } 64 | } 65 | 66 | impl_benchmark_test_suite!(Pallet, crate::mock::new_test_ext(), crate::mock::Test); 67 | -------------------------------------------------------------------------------- /executor/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "canyon-executor" 3 | version = "0.1.0" 4 | authors = ["Canyon Labs "] 5 | description = "Canyon node implementation in Rust." 6 | edition = "2018" 7 | license = "GPL-3.0" 8 | homepage = "https://canyon-network.io" 9 | repository = "https://github.com/canyon-network/canyon/" 10 | 11 | [package.metadata.docs.rs] 12 | targets = ["x86_64-unknown-linux-gnu"] 13 | 14 | [dependencies] 15 | codec = { package = "parity-scale-codec", version = "2.3" } 16 | trie-root = "0.16.0" 17 | 18 | sc-executor = { git = "https://github.com/paritytech/substrate", branch = "master" } 19 | sp-core = { git = "https://github.com/paritytech/substrate", branch = "master" } 20 | sp-keystore = { git = "https://github.com/paritytech/substrate", branch = "master" } 21 | sp-io = { git = "https://github.com/paritytech/substrate", branch = "master" } 22 | sp-state-machine = { git = "https://github.com/paritytech/substrate", branch = "master" } 23 | sp-trie = { git = "https://github.com/paritytech/substrate", branch = "master" } 24 | frame-benchmarking = { git = "https://github.com/paritytech/substrate", branch = "master" } 25 | 26 | canyon-primitives = { path = "../primitives" } 27 | canyon-runtime = { path = "../runtime" } 28 | 29 | [dev-dependencies] 30 | criterion = "0.3.0" 31 | wat = "1.0" 32 | 33 | sp-application-crypto = { git = "https://github.com/paritytech/substrate", branch = "master" } 34 | sp-consensus-babe = { git = "https://github.com/paritytech/substrate", branch = "master" } 35 | sp-externalities = { git = "https://github.com/paritytech/substrate", branch = "master" } 36 | sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master" } 37 | frame-support = { git = "https://github.com/paritytech/substrate", branch = "master" } 38 | frame-system = { git = "https://github.com/paritytech/substrate", branch = "master" } 39 | pallet-balances = { git = "https://github.com/paritytech/substrate", branch = "master" } 40 | pallet-contracts = { git = "https://github.com/paritytech/substrate", branch = "master" } 41 | pallet-grandpa = { git = "https://github.com/paritytech/substrate", branch = "master" } 42 | pallet-im-online = { git = "https://github.com/paritytech/substrate", branch = "master" } 43 | pallet-indices = { git = "https://github.com/paritytech/substrate", branch = "master" } 44 | pallet-session = { git = "https://github.com/paritytech/substrate", branch = "master" } 45 | pallet-timestamp = { git = "https://github.com/paritytech/substrate", branch = "master" } 46 | pallet-transaction-payment = { git = "https://github.com/paritytech/substrate", branch = "master" } 47 | pallet-treasury = { git = "https://github.com/paritytech/substrate", branch = "master" } 48 | substrate-test-client = { git = "https://github.com/paritytech/substrate", branch = "master" } 49 | 50 | [features] 51 | wasmtime = [ 52 | "sc-executor/wasmtime", 53 | ] 54 | wasmi-errno = [ 55 | "sc-executor/wasmi-errno", 56 | ] 57 | stress-test = [] 58 | -------------------------------------------------------------------------------- /cli/src/cli.rs: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | // This file is part of Canyon. 3 | // 4 | // Copyright (c) 2021 Canyon Labs. 5 | // 6 | // Canyon is free software: you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published 8 | // by the Free Software Foundation, either version 3 of the License, 9 | // or (at your option) any later version. 10 | // 11 | // Canyon is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with Canyon. If not, see . 18 | 19 | use structopt::StructOpt; 20 | 21 | use sc_cli::{KeySubcommand, RunCmd, SignCmd, VanityCmd, VerifyCmd}; 22 | 23 | /// An overarching CLI command definition. 24 | #[derive(Debug, StructOpt)] 25 | pub struct Cli { 26 | /// Possible subcommand with parameters. 27 | #[structopt(subcommand)] 28 | pub subcommand: Option, 29 | #[allow(missing_docs)] 30 | #[structopt(flatten)] 31 | pub run: RunCmd, 32 | } 33 | 34 | /// Possible subcommands of the main binary. 35 | #[derive(Debug, StructOpt)] 36 | pub enum Subcommand { 37 | /// Key management cli utilities 38 | Key(KeySubcommand), 39 | 40 | /// The custom inspect subcommmand for decoding blocks and extrinsics. 41 | #[structopt( 42 | name = "inspect", 43 | about = "Decode given block or extrinsic using current native runtime." 44 | )] 45 | Inspect(canyon_inspect::cli::InspectCmd), 46 | 47 | /// The custom benchmark subcommmand benchmarking runtime pallets. 48 | #[structopt(name = "benchmark", about = "Benchmark runtime pallets.")] 49 | Benchmark(frame_benchmarking_cli::BenchmarkCmd), 50 | 51 | /// Try some experimental command on the runtime. This includes migration and runtime-upgrade 52 | /// testing. 53 | #[cfg(feature = "try-runtime")] 54 | TryRuntime(try_runtime_cli::TryRuntimeCmd), 55 | 56 | /// Verify a signature for a message, provided on STDIN, with a given (public or secret) key. 57 | Verify(VerifyCmd), 58 | 59 | /// Generate a seed that provides a vanity address. 60 | Vanity(VanityCmd), 61 | 62 | /// Sign a message, with a given (secret) key. 63 | Sign(SignCmd), 64 | 65 | /// Build a chain specification. 66 | BuildSpec(sc_cli::BuildSpecCmd), 67 | 68 | /// Validate blocks. 69 | CheckBlock(sc_cli::CheckBlockCmd), 70 | 71 | /// Export blocks. 72 | ExportBlocks(sc_cli::ExportBlocksCmd), 73 | 74 | /// Export the state of a given block into a chain spec. 75 | ExportState(sc_cli::ExportStateCmd), 76 | 77 | /// Import blocks. 78 | ImportBlocks(sc_cli::ImportBlocksCmd), 79 | 80 | /// Remove the whole chain. 81 | PurgeChain(sc_cli::PurgeChainCmd), 82 | 83 | /// Revert the chain to a previous state. 84 | Revert(sc_cli::RevertCmd), 85 | } 86 | -------------------------------------------------------------------------------- /primitives/permastore/src/lib.rs: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | // This file is part of Canyon. 3 | // 4 | // Copyright (c) 2021 Canyon Labs. 5 | // 6 | // Canyon is free software: you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published 8 | // by the Free Software Foundation, either version 3 of the License, 9 | // or (at your option) any later version. 10 | // 11 | // Canyon is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with Canyon. If not, see . 18 | 19 | #![cfg_attr(not(feature = "std"), no_std)] 20 | #![allow(clippy::too_many_arguments)] 21 | 22 | use sp_std::vec::Vec; 23 | 24 | /// 256B per chunk. 25 | pub const CHUNK_SIZE: u32 = 256 * 1024; 26 | 27 | /// Hasher type for permastore. 28 | #[cfg(feature = "std")] 29 | pub type Hasher = sp_core::Blake2Hasher; 30 | 31 | /// Trie layout used for permastore. 32 | #[cfg(feature = "std")] 33 | pub type TrieLayout = sp_trie::Layout; 34 | 35 | /// Error type of chunk proof verification. 36 | pub type VerifyError = sp_trie::VerifyError; 37 | 38 | /// Low level APIs for manipulating the persistent transaction data storage. 39 | /// No data validation performed. 40 | pub trait PermaStorage: Send + Sync { 41 | /// Persist a value in storage under given key. 42 | fn submit(&mut self, key: &[u8], value: &[u8]); 43 | 44 | /// Remove the value under given key. 45 | fn remove(&mut self, key: &[u8]); 46 | 47 | /// Retrieve a value from storage under given key. 48 | fn retrieve(&self, key: &[u8]) -> Option>; 49 | 50 | /// Checks if the storage exists under given key. 51 | fn exists(&self, key: &[u8]) -> bool { 52 | self.retrieve(key).is_some() 53 | } 54 | } 55 | 56 | sp_api::decl_runtime_apis! { 57 | /// The permastore API. 58 | pub trait PermastoreApi where 59 | BlockNumber: codec::Codec, 60 | ExtrinsicIndex: codec::Codec, 61 | Hash: codec::Codec, 62 | { 63 | /// Returns the chunk root given `block_number` and `extrinsic_index`. 64 | fn chunk_root(block_number: BlockNumber, extrinsic_index: ExtrinsicIndex) -> Option; 65 | 66 | /// Returns the number of block in which the recall byte is included. 67 | fn find_recall_block(recall_byte: u64) -> Option; 68 | 69 | /// Returns the size of transaction data given `block_number` and `extrinsic_index`. 70 | fn data_size(block_number: BlockNumber, extrinsic_index: ExtrinsicIndex) -> u32; 71 | 72 | /// Returns `true` if the proof of access is required for the block. 73 | fn require_proof_of_access() -> bool; 74 | 75 | /// Returns the size of current block. 76 | fn block_size() -> u64; 77 | 78 | /// Returns the size of entire weave. 79 | fn weave_size() -> u64; 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /client/consensus/poa/src/inherent.rs: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | // This file is part of Canyon. 3 | // 4 | // Copyright (c) 2021 Canyon Labs. 5 | // 6 | // Canyon is free software: you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published 8 | // by the Free Software Foundation, either version 3 of the License, 9 | // or (at your option) any later version. 10 | // 11 | // Canyon is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with Canyon. If not, see . 18 | 19 | use std::sync::Arc; 20 | 21 | use sp_api::ProvideRuntimeApi; 22 | use sp_blockchain::HeaderBackend; 23 | use sp_runtime::traits::{Block as BlockT, NumberFor}; 24 | 25 | use sc_client_api::BlockBackend; 26 | 27 | use cc_datastore::TransactionDataBackend as TransactionDataBackendT; 28 | use cp_consensus_poa::{PoaOutcome, POA_INHERENT_IDENTIFIER}; 29 | 30 | /// A type for creating the inherent data for pallet poa. 31 | pub struct PoaInherentDataProvider { 32 | /// Outcome of creating a proof of access. 33 | pub poa_outcome: PoaOutcome, 34 | } 35 | 36 | impl PoaInherentDataProvider { 37 | /// Creates a new instance of [`PoaInherentDataProvider`]. 38 | pub fn create( 39 | client: Arc, 40 | parent: Block::Hash, 41 | transaction_data_backend: TransactionDataBackend, 42 | ) -> Result> 43 | where 44 | Block: BlockT + 'static, 45 | Client: BlockBackend 46 | + HeaderBackend 47 | + ProvideRuntimeApi 48 | + Send 49 | + Sync 50 | + 'static, 51 | Client::Api: cp_permastore::PermastoreApi, u32, Block::Hash> 52 | + cp_poa::PoaApi, 53 | TransactionDataBackend: TransactionDataBackendT, 54 | { 55 | let poa_outcome = match crate::construct_poa(client, parent, transaction_data_backend) { 56 | Ok(outcome) => outcome, 57 | Err(e) => { 58 | log::error!(target: "poa", "Failed to construct poa: {:?}", e); 59 | return Err(e); 60 | } 61 | }; 62 | Ok(Self { poa_outcome }) 63 | } 64 | } 65 | 66 | #[async_trait::async_trait] 67 | impl sp_inherents::InherentDataProvider for PoaInherentDataProvider { 68 | fn provide_inherent_data( 69 | &self, 70 | inherent_data: &mut sp_inherents::InherentData, 71 | ) -> Result<(), sp_inherents::Error> { 72 | inherent_data.put_data(POA_INHERENT_IDENTIFIER, &self.poa_outcome) 73 | } 74 | 75 | async fn try_handle_error( 76 | &self, 77 | _: &sp_inherents::InherentIdentifier, 78 | _: &[u8], 79 | ) -> Option> { 80 | // Inherent isn't checked and can not return any error 81 | None 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /pallets/poa/src/weights.rs: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | // This file is part of Canyon. 3 | // 4 | // Copyright (c) 2021 Canyon Labs. 5 | // 6 | // Canyon is free software: you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published 8 | // by the Free Software Foundation, either version 3 of the License, 9 | // or (at your option) any later version. 10 | // 11 | // Canyon is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with Canyon. If not, see . 18 | 19 | //! Autogenerated weights for pallet_poa 20 | //! 21 | //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev 22 | //! DATE: 2021-08-05, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` 23 | //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 128 24 | 25 | // Executed Command: 26 | // ./target/release/canyon 27 | // benchmark 28 | // --chain 29 | // dev 30 | // --execution=wasm 31 | // --wasm-execution=compiled 32 | // --pallet 33 | // pallet_poa 34 | // --extrinsic 35 | // * 36 | // --steps=50 37 | // --heap-pages=4096 38 | // --repeat 39 | // 20 40 | // --template=./scripts/pallet-weights-template.hbs 41 | // --output=./pallets/poa/src/weights.rs 42 | 43 | #![allow(clippy::all)] 44 | #![allow(unused_parens)] 45 | #![allow(unused_imports)] 46 | 47 | use frame_support::{ 48 | traits::Get, 49 | weights::{constants::RocksDbWeight, Weight}, 50 | }; 51 | use sp_std::marker::PhantomData; 52 | 53 | /// Weight functions needed for pallet_poa. 54 | pub trait WeightInfo { 55 | fn deposit() -> Weight; 56 | fn set_config() -> Weight; 57 | } 58 | 59 | /// Weights for pallet_poa using the Substrate node and recommended hardware. 60 | pub struct SubstrateWeight(PhantomData); 61 | impl WeightInfo for SubstrateWeight { 62 | // Storage: Poa HistoryDepth (r:1 w:1) 63 | // Storage: Poa PoaConfig (r:1 w:0) 64 | // Storage: System Digest (r:1 w:1) 65 | // Storage: Authorship Author (r:1 w:0) 66 | fn deposit() -> Weight { 67 | (563_445_000 as Weight) 68 | .saturating_add(T::DbWeight::get().reads(4 as Weight)) 69 | .saturating_add(T::DbWeight::get().writes(2 as Weight)) 70 | } 71 | // Storage: Poa PoaConfig (r:0 w:1) 72 | fn set_config() -> Weight { 73 | (16_173_000 as Weight).saturating_add(T::DbWeight::get().writes(1 as Weight)) 74 | } 75 | } 76 | 77 | // For backwards compatibility and tests 78 | impl WeightInfo for () { 79 | // Storage: Poa HistoryDepth (r:1 w:1) 80 | // Storage: Poa PoaConfig (r:1 w:0) 81 | // Storage: System Digest (r:1 w:1) 82 | // Storage: Authorship Author (r:1 w:0) 83 | fn deposit() -> Weight { 84 | (563_445_000 as Weight) 85 | .saturating_add(RocksDbWeight::get().reads(4 as Weight)) 86 | .saturating_add(RocksDbWeight::get().writes(2 as Weight)) 87 | } 88 | // Storage: Poa PoaConfig (r:0 w:1) 89 | fn set_config() -> Weight { 90 | (16_173_000 as Weight).saturating_add(RocksDbWeight::get().writes(1 as Weight)) 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /runtime/src/constants.rs: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | // This file is part of Canyon. 3 | // 4 | // Copyright (c) 2021 Canyon Labs. 5 | // 6 | // Canyon is free software: you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published 8 | // by the Free Software Foundation, either version 3 of the License, 9 | // or (at your option) any later version. 10 | // 11 | // Canyon is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with Canyon. If not, see . 18 | 19 | //! A set of constant values used in substrate runtime. 20 | 21 | /// Money matters. 22 | pub mod currency { 23 | use canyon_primitives::Balance; 24 | 25 | pub const MILLICENTS: Balance = 1_000_000_000; 26 | pub const CENTS: Balance = 1_000 * MILLICENTS; // assume this is worth about a cent. 27 | pub const DOLLARS: Balance = 100 * CENTS; 28 | 29 | pub const fn deposit(items: u32, bytes: u32) -> Balance { 30 | items as Balance * 15 * CENTS + (bytes as Balance) * 6 * CENTS 31 | } 32 | } 33 | 34 | /// Time. 35 | pub mod time { 36 | use canyon_primitives::{BlockNumber, Moment}; 37 | 38 | /// Since BABE is probabilistic this is the average expected block time that 39 | /// we are targeting. Blocks will be produced at a minimum duration defined 40 | /// by `SLOT_DURATION`, but some slots will not be allocated to any 41 | /// authority and hence no block will be produced. We expect to have this 42 | /// block time on average following the defined slot duration and the value 43 | /// of `c` configured for BABE (where `1 - c` represents the probability of 44 | /// a slot being empty). 45 | /// This value is only used indirectly to define the unit constants below 46 | /// that are expressed in blocks. The rest of the code should use 47 | /// `SLOT_DURATION` instead (like the Timestamp pallet for calculating the 48 | /// minimum period). 49 | /// 50 | /// If using BABE with secondary slots (default) then all of the slots will 51 | /// always be assigned, in which case `MILLISECS_PER_BLOCK` and 52 | /// `SLOT_DURATION` should have the same value. 53 | /// 54 | /// 55 | pub const MILLISECS_PER_BLOCK: Moment = 6000; 56 | pub const SECS_PER_BLOCK: Moment = MILLISECS_PER_BLOCK / 1000; 57 | 58 | pub const SLOT_DURATION: Moment = MILLISECS_PER_BLOCK; 59 | 60 | // 1 in 4 blocks (on average, not counting collisions) will be primary BABE blocks. 61 | pub const PRIMARY_PROBABILITY: (u64, u64) = (1, 4); 62 | 63 | pub const EPOCH_DURATION_IN_BLOCKS: BlockNumber = 10 * MINUTES; 64 | pub const EPOCH_DURATION_IN_SLOTS: u64 = { 65 | const SLOT_FILL_RATE: f64 = MILLISECS_PER_BLOCK as f64 / SLOT_DURATION as f64; 66 | 67 | (EPOCH_DURATION_IN_BLOCKS as f64 * SLOT_FILL_RATE) as u64 68 | }; 69 | 70 | // These time units are defined in number of blocks. 71 | pub const MINUTES: BlockNumber = 60 / (SECS_PER_BLOCK as BlockNumber); 72 | pub const HOURS: BlockNumber = MINUTES * 60; 73 | pub const DAYS: BlockNumber = HOURS * 24; 74 | } 75 | -------------------------------------------------------------------------------- /pallets/permastore/src/weights.rs: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | // This file is part of Canyon. 3 | // 4 | // Copyright (c) 2021 Canyon Labs. 5 | // 6 | // Canyon is free software: you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published 8 | // by the Free Software Foundation, either version 3 of the License, 9 | // or (at your option) any later version. 10 | // 11 | // Canyon is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with Canyon. If not, see . 18 | 19 | //! Autogenerated weights for pallet_permastore 20 | //! 21 | //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev 22 | //! DATE: 2021-08-05, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` 23 | //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 128 24 | 25 | // Executed Command: 26 | // ./target/release/canyon 27 | // benchmark 28 | // --chain 29 | // dev 30 | // --execution=wasm 31 | // --wasm-execution=compiled 32 | // --pallet 33 | // pallet_permastore 34 | // --extrinsic 35 | // * 36 | // --steps=50 37 | // --heap-pages=4096 38 | // --repeat 39 | // 20 40 | // --template=./scripts/pallet-weights-template.hbs 41 | // --output=./pallets/permastore/src/weights.rs 42 | 43 | #![allow(clippy::all)] 44 | #![allow(unused_parens)] 45 | #![allow(unused_imports)] 46 | 47 | use frame_support::{ 48 | traits::Get, 49 | weights::{constants::RocksDbWeight, Weight}, 50 | }; 51 | use sp_std::marker::PhantomData; 52 | 53 | /// Weight functions needed for pallet_permastore. 54 | pub trait WeightInfo { 55 | fn store() -> Weight; 56 | fn forget() -> Weight; 57 | } 58 | 59 | /// Weights for pallet_permastore using the Substrate node and recommended hardware. 60 | pub struct SubstrateWeight(PhantomData); 61 | impl WeightInfo for SubstrateWeight { 62 | // Storage: Permastore ChunkRootIndex (r:0 w:1) 63 | // Storage: Permastore Orders (r:0 w:1) 64 | // Storage: unknown [0x3a65787472696e7369635f696e646578] (r:1 w:0) 65 | // Storage: Permastore BlockDataSize (r:1 w:1) 66 | // Storage: Permastore WeaveSize (r:1 w:1) 67 | // Storage: Permastore TransactionDataSize (r:0 w:1) 68 | fn store() -> Weight { 69 | (64_430_000 as Weight) 70 | .saturating_add(T::DbWeight::get().reads(3 as Weight)) 71 | .saturating_add(T::DbWeight::get().writes(5 as Weight)) 72 | } 73 | // Storage: Permastore Orders (r:1 w:1) 74 | fn forget() -> Weight { 75 | (24_665_000 as Weight) 76 | .saturating_add(T::DbWeight::get().reads(1 as Weight)) 77 | .saturating_add(T::DbWeight::get().writes(1 as Weight)) 78 | } 79 | } 80 | 81 | // For backwards compatibility and tests 82 | impl WeightInfo for () { 83 | // Storage: Permastore ChunkRootIndex (r:0 w:1) 84 | // Storage: Permastore Orders (r:0 w:1) 85 | // Storage: unknown [0x3a65787472696e7369635f696e646578] (r:1 w:0) 86 | // Storage: Permastore BlockDataSize (r:1 w:1) 87 | // Storage: Permastore WeaveSize (r:1 w:1) 88 | // Storage: Permastore TransactionDataSize (r:0 w:1) 89 | fn store() -> Weight { 90 | (64_430_000 as Weight) 91 | .saturating_add(RocksDbWeight::get().reads(3 as Weight)) 92 | .saturating_add(RocksDbWeight::get().writes(5 as Weight)) 93 | } 94 | // Storage: Permastore Orders (r:1 w:1) 95 | fn forget() -> Weight { 96 | (24_665_000 as Weight) 97 | .saturating_add(RocksDbWeight::get().reads(1 as Weight)) 98 | .saturating_add(RocksDbWeight::get().writes(1 as Weight)) 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /primitives/src/lib.rs: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | // This file is part of Canyon. 3 | // 4 | // Copyright (c) 2021 Canyon Labs. 5 | // 6 | // Canyon is free software: you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published 8 | // by the Free Software Foundation, either version 3 of the License, 9 | // or (at your option) any later version. 10 | // 11 | // Canyon is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with Canyon. If not, see . 18 | 19 | //! Low-level types used throughout the Canyon code. 20 | 21 | #![warn(missing_docs)] 22 | #![cfg_attr(not(feature = "std"), no_std)] 23 | 24 | use sp_runtime::{ 25 | generic, 26 | traits::{BlakeTwo256, IdentifyAccount, Verify}, 27 | MultiSignature, OpaqueExtrinsic, 28 | }; 29 | 30 | /// An index to a block. 31 | pub type BlockNumber = u32; 32 | 33 | /// Alias to 512-bit hash when used in the context of a transaction signature on the chain. 34 | pub type Signature = MultiSignature; 35 | 36 | /// Some way of identifying an account on the chain. We intentionally make it equivalent 37 | /// to the public key of our transaction signing scheme. 38 | pub type AccountId = <::Signer as IdentifyAccount>::AccountId; 39 | 40 | /// The type for looking up accounts. We don't expect more than 4 billion of them. 41 | pub type AccountIndex = u32; 42 | 43 | /// Number of the attempts of PoA generation. 44 | pub type Depth = u32; 45 | 46 | /// The type for indexing the perma storage. The upper limit is around 16 EiB. 47 | pub type DataIndex = u64; 48 | 49 | /// Type used for extrinsic. 50 | pub type ExtrinsicIndex = u32; 51 | 52 | /// Balance of an account. 53 | pub type Balance = u128; 54 | 55 | /// Type used for expressing timestamp. 56 | pub type Moment = u64; 57 | 58 | /// Index of a transaction in the chain. 59 | pub type Index = u32; 60 | 61 | /// A hash of some data used by the chain. 62 | pub type Hash = sp_core::H256; 63 | 64 | /// A timestamp: milliseconds since the unix epoch. 65 | /// `u64` is enough to represent a duration of half a billion years, when the 66 | /// time scale is milliseconds. 67 | pub type Timestamp = u64; 68 | 69 | /// Digest item type. 70 | pub type DigestItem = generic::DigestItem; 71 | 72 | /// Header type. 73 | pub type Header = generic::Header; 74 | 75 | /// Block type. 76 | pub type Block = generic::Block; 77 | 78 | /// Block ID. 79 | pub type BlockId = generic::BlockId; 80 | 81 | /// App-specific crypto used for reporting equivocation/misbehavior in BABE and 82 | /// GRANDPA. Any rewards for misbehavior reporting will be paid out to this 83 | /// account. 84 | pub mod report { 85 | use super::{Signature, Verify}; 86 | use frame_system::offchain::AppCrypto; 87 | use sp_core::crypto::{key_types, KeyTypeId}; 88 | 89 | /// Key type for the reporting module. Used for reporting BABE and GRANDPA 90 | /// equivocations. 91 | pub const KEY_TYPE: KeyTypeId = key_types::REPORTING; 92 | 93 | mod app { 94 | use sp_application_crypto::{app_crypto, sr25519}; 95 | app_crypto!(sr25519, super::KEY_TYPE); 96 | } 97 | 98 | /// Identity of the equivocation/misbehavior reporter. 99 | pub type ReporterId = app::Public; 100 | 101 | /// An `AppCrypto` type to allow submitting signed transactions using the reporting 102 | /// application key as signer. 103 | pub struct ReporterAppCrypto; 104 | 105 | impl AppCrypto<::Signer, Signature> for ReporterAppCrypto { 106 | type RuntimeAppPublic = ReporterId; 107 | type GenericSignature = sp_core::sr25519::Signature; 108 | type GenericPublic = sp_core::sr25519::Public; 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /pallets/poa/src/mock.rs: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | // This file is part of Canyon. 3 | // 4 | // Copyright (c) 2021 Canyon Labs. 5 | // 6 | // Canyon is free software: you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published 8 | // by the Free Software Foundation, either version 3 of the License, 9 | // or (at your option) any later version. 10 | // 11 | // Canyon is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with Canyon. If not, see . 18 | 19 | use super::*; 20 | 21 | use frame_support::{parameter_types, traits::Everything}; 22 | use sp_core::H256; 23 | // The testing primitives are very useful for avoiding having to work with signatures 24 | // or public keys. `u64` is used as the `AccountId` and no `Signature`s are required. 25 | use sp_runtime::{ 26 | testing::Header, 27 | traits::{BlakeTwo256, IdentityLookup}, 28 | BuildStorage, 29 | }; 30 | // Reexport crate as its pallet name for construct_runtime. 31 | use crate as pallet_poa; 32 | 33 | type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; 34 | type Block = frame_system::mocking::MockBlock; 35 | 36 | // For testing the pallet, we construct a mock runtime. 37 | frame_support::construct_runtime!( 38 | pub enum Test where 39 | Block = Block, 40 | NodeBlock = Block, 41 | UncheckedExtrinsic = UncheckedExtrinsic, 42 | { 43 | System: frame_system::{Pallet, Call, Config, Storage, Event}, 44 | Balances: pallet_balances::{Pallet, Call, Storage, Config, Event}, 45 | Poa: pallet_poa::{Pallet, Call, Storage, Event}, 46 | } 47 | ); 48 | 49 | parameter_types! { 50 | pub const BlockHashCount: u64 = 250; 51 | pub BlockWeights: frame_system::limits::BlockWeights = 52 | frame_system::limits::BlockWeights::simple_max(1024); 53 | } 54 | impl frame_system::Config for Test { 55 | type BaseCallFilter = Everything; 56 | type BlockWeights = (); 57 | type BlockLength = (); 58 | type DbWeight = (); 59 | type Origin = Origin; 60 | type Index = u64; 61 | type BlockNumber = u64; 62 | type Hash = H256; 63 | type Call = Call; 64 | type Hashing = BlakeTwo256; 65 | type AccountId = u64; 66 | type Lookup = IdentityLookup; 67 | type Header = Header; 68 | type Event = Event; 69 | type BlockHashCount = BlockHashCount; 70 | type Version = (); 71 | type PalletInfo = PalletInfo; 72 | type AccountData = pallet_balances::AccountData; 73 | type OnNewAccount = (); 74 | type OnKilledAccount = (); 75 | type SystemWeightInfo = (); 76 | type SS58Prefix = (); 77 | type OnSetCode = (); 78 | } 79 | 80 | parameter_types! { 81 | pub const ExistentialDeposit: u64 = 1; 82 | pub const MaxLocks: u32 = 50; 83 | pub const MaxReserves: u32 = 50; 84 | } 85 | 86 | impl pallet_balances::Config for Test { 87 | type MaxLocks = MaxLocks; 88 | type MaxReserves = MaxReserves; 89 | type ReserveIdentifier = [u8; 8]; 90 | type Balance = u64; 91 | type DustRemoval = (); 92 | type Event = Event; 93 | type ExistentialDeposit = ExistentialDeposit; 94 | type AccountStore = System; 95 | type WeightInfo = (); 96 | } 97 | 98 | impl BlockAuthor for Test { 99 | fn author() -> u64 { 100 | TestAuthor::::get() 101 | } 102 | } 103 | 104 | impl Config for Test { 105 | type Event = Event; 106 | type BlockAuthor = Self; 107 | type WeightInfo = (); 108 | } 109 | 110 | // This function basically just builds a genesis storage key/value store according to 111 | // our desired mockup. 112 | pub fn new_test_ext() -> sp_io::TestExternalities { 113 | let t = GenesisConfig { 114 | // We use default for brevity, but you can configure as desired if needed. 115 | system: Default::default(), 116 | balances: Default::default(), 117 | } 118 | .build_storage() 119 | .unwrap(); 120 | t.into() 121 | } 122 | -------------------------------------------------------------------------------- /pallets/poa/src/tests.rs: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | // This file is part of Canyon. 3 | // 4 | // Copyright (c) 2021 Canyon Labs. 5 | // 6 | // Canyon is free software: you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published 8 | // by the Free Software Foundation, either version 3 of the License, 9 | // or (at your option) any later version. 10 | // 11 | // Canyon is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with Canyon. If not, see . 18 | 19 | use sc_block_builder::{BlockBuilder, RecordProof}; 20 | use sp_blockchain::HeaderBackend; 21 | use sp_keyring::AccountKeyring::{Alice, Bob}; 22 | use sp_runtime::traits::Block as BlockT; 23 | use substrate_test_runtime::{Block, Transfer}; 24 | use substrate_test_runtime_client::{ 25 | BlockBuilderExt, DefaultTestClientBuilderExt, TestClientBuilderExt, 26 | }; 27 | 28 | use cc_consensus_poa::{build_extrinsic_proof, ChunkProof, ChunkProofBuilder}; 29 | use cp_permastore::CHUNK_SIZE; 30 | 31 | use crate::mock::{new_test_ext, Poa, Test}; 32 | use crate::{DepthInfo, HistoryDepth, TestAuthor}; 33 | 34 | fn generate_chunk_proof(data: Vec, offset: u32) -> ChunkProof { 35 | ChunkProofBuilder::new(data, CHUNK_SIZE, offset) 36 | .build() 37 | .expect("Couldn't build chunk proof") 38 | } 39 | 40 | fn mock_extrinsic_proof() -> Vec> { 41 | let builder = substrate_test_runtime_client::TestClientBuilder::new(); 42 | let backend = builder.backend(); 43 | let client = builder.build(); 44 | 45 | let mut block_builder = BlockBuilder::new( 46 | &client, 47 | client.info().best_hash, 48 | client.info().best_number, 49 | RecordProof::No, 50 | Default::default(), 51 | &*backend, 52 | ) 53 | .unwrap(); 54 | 55 | block_builder 56 | .push_transfer(Transfer { 57 | from: Alice.into(), 58 | to: Bob.into(), 59 | amount: 123, 60 | nonce: 0, 61 | }) 62 | .unwrap(); 63 | 64 | block_builder 65 | .push_transfer(Transfer { 66 | from: Bob.into(), 67 | to: Alice.into(), 68 | amount: 1, 69 | nonce: 0, 70 | }) 71 | .unwrap(); 72 | 73 | let built_block = block_builder.build().unwrap(); 74 | 75 | let (block, extrinsics) = built_block.block.deconstruct(); 76 | 77 | let extrinsics_root = block.extrinsics_root; 78 | 79 | build_extrinsic_proof::(0, extrinsics_root, extrinsics.clone()).unwrap() 80 | } 81 | 82 | #[test] 83 | fn test_generate_proof_of_access() { 84 | let random_data = crate::benchmarking::mock_a_data_chunk(); 85 | let offset = 56_780_000; 86 | let chunk_proof = generate_chunk_proof(random_data, offset); 87 | 88 | println!("chunk_index: {:?}", chunk_proof.chunk_index); 89 | println!("chunk_proof: {:?}", chunk_proof.proof); 90 | 91 | let tx_proof = mock_extrinsic_proof(); 92 | 93 | println!("tx_proof: {:?}", tx_proof); 94 | } 95 | 96 | #[test] 97 | fn note_depth_should_work() { 98 | new_test_ext().execute_with(|| { 99 | TestAuthor::::put(6); 100 | Poa::note_depth(10); 101 | assert_eq!( 102 | HistoryDepth::::get(&6).unwrap(), 103 | DepthInfo { 104 | total_depth: 10, 105 | blocks: 1 106 | } 107 | ); 108 | 109 | TestAuthor::::put(8); 110 | Poa::note_depth(1); 111 | assert_eq!( 112 | HistoryDepth::::get(&8).unwrap(), 113 | DepthInfo { 114 | total_depth: 1, 115 | blocks: 1 116 | } 117 | ); 118 | 119 | TestAuthor::::put(6); 120 | Poa::note_depth(1); 121 | assert_eq!( 122 | HistoryDepth::::get(&6).unwrap(), 123 | DepthInfo { 124 | total_depth: 11, 125 | blocks: 2 126 | } 127 | ); 128 | }); 129 | } 130 | -------------------------------------------------------------------------------- /pallets/permastore/src/mock.rs: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | // This file is part of Canyon. 3 | // 4 | // Copyright (c) 2021 Canyon Labs. 5 | // 6 | // Canyon is free software: you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published 8 | // by the Free Software Foundation, either version 3 of the License, 9 | // or (at your option) any later version. 10 | // 11 | // Canyon is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with Canyon. If not, see . 18 | 19 | use super::*; 20 | 21 | use frame_support::{parameter_types, traits::Everything, PalletId}; 22 | use sp_core::H256; 23 | // The testing primitives are very useful for avoiding having to work with signatures 24 | // or public keys. `u64` is used as the `AccountId` and no `Signature`s are required. 25 | use sp_runtime::{ 26 | testing::Header, 27 | traits::{BlakeTwo256, IdentityLookup}, 28 | BuildStorage, 29 | }; 30 | // Reexport crate as its pallet name for construct_runtime. 31 | use crate as pallet_permastore; 32 | 33 | type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; 34 | type Block = frame_system::mocking::MockBlock; 35 | 36 | // For testing the pallet, we construct a mock runtime. 37 | frame_support::construct_runtime!( 38 | pub enum Test where 39 | Block = Block, 40 | NodeBlock = Block, 41 | UncheckedExtrinsic = UncheckedExtrinsic, 42 | { 43 | System: frame_system::{Pallet, Call, Config, Storage, Event}, 44 | Balances: pallet_balances::{Pallet, Call, Storage, Config, Event}, 45 | Permastore: pallet_permastore::{Pallet, Call, Storage, Event}, 46 | } 47 | ); 48 | 49 | parameter_types! { 50 | pub const BlockHashCount: u64 = 250; 51 | pub BlockWeights: frame_system::limits::BlockWeights = 52 | frame_system::limits::BlockWeights::simple_max(1024); 53 | } 54 | impl frame_system::Config for Test { 55 | type BaseCallFilter = Everything; 56 | type BlockWeights = (); 57 | type BlockLength = (); 58 | type DbWeight = (); 59 | type Origin = Origin; 60 | type Index = u64; 61 | type BlockNumber = u64; 62 | type Hash = H256; 63 | type Call = Call; 64 | type Hashing = BlakeTwo256; 65 | type AccountId = u64; 66 | type Lookup = IdentityLookup; 67 | type Header = Header; 68 | type Event = Event; 69 | type BlockHashCount = BlockHashCount; 70 | type Version = (); 71 | type PalletInfo = PalletInfo; 72 | type AccountData = pallet_balances::AccountData; 73 | type OnNewAccount = (); 74 | type OnKilledAccount = (); 75 | type SystemWeightInfo = (); 76 | type SS58Prefix = (); 77 | type OnSetCode = (); 78 | } 79 | parameter_types! { 80 | pub const ExistentialDeposit: u64 = 1; 81 | pub const MaxLocks: u32 = 50; 82 | pub const MaxReserves: u32 = 50; 83 | } 84 | impl pallet_balances::Config for Test { 85 | type MaxLocks = MaxLocks; 86 | type MaxReserves = MaxReserves; 87 | type ReserveIdentifier = [u8; 8]; 88 | type Balance = u64; 89 | type DustRemoval = (); 90 | type Event = Event; 91 | type ExistentialDeposit = ExistentialDeposit; 92 | type AccountStore = System; 93 | type WeightInfo = (); 94 | } 95 | parameter_types! { 96 | pub const TreasuryPalletId: PalletId = PalletId(*b"py/trsry"); 97 | pub const MaxDataSize: u32 = 1024 * 1024 * 1024; 98 | } 99 | impl Config for Test { 100 | type Event = Event; 101 | type Currency = Balances; 102 | type TreasuryPalletId = TreasuryPalletId; 103 | type MaxDataSize = MaxDataSize; 104 | type WeightInfo = (); 105 | } 106 | 107 | // This function basically just builds a genesis storage key/value store according to 108 | // our desired mockup. 109 | pub fn new_test_ext() -> sp_io::TestExternalities { 110 | let t = GenesisConfig { 111 | // We use default for brevity, but you can configure as desired if needed. 112 | system: Default::default(), 113 | balances: Default::default(), 114 | } 115 | .build_storage() 116 | .unwrap(); 117 | t.into() 118 | } 119 | -------------------------------------------------------------------------------- /client/rpc-api/src/permastore/error.rs: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | // This file is part of Canyon. 3 | // 4 | // Copyright (c) 2021 Canyon Labs. 5 | // 6 | // Canyon is free software: you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published 8 | // by the Free Software Foundation, either version 3 of the License, 9 | // or (at your option) any later version. 10 | // 11 | // Canyon is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with Canyon. If not, see . 18 | 19 | use jsonrpc_core as rpc; 20 | 21 | pub type Result = std::result::Result; 22 | 23 | /// This type describes the count that excceds the max allowed number. 24 | #[derive(Debug)] 25 | pub struct InvalidCount { 26 | /// Provided value 27 | pub provided: u32, 28 | /// Maximum allowed value 29 | pub max: u32, 30 | } 31 | 32 | impl std::fmt::Display for InvalidCount { 33 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 34 | write!(f, "provided: {}, max: {}", self.provided, self.max) 35 | } 36 | } 37 | 38 | impl InvalidCount { 39 | pub fn new(provided: u32, max: u32) -> Self { 40 | Self { provided, max } 41 | } 42 | } 43 | 44 | #[derive(Debug, thiserror::Error)] 45 | pub enum Error { 46 | #[error("transaction data already exists")] 47 | DataExists, 48 | #[error("chunk data already exists")] 49 | ChunkExists, 50 | #[error("transaction data is too large. {}", _0)] 51 | DataTooLarge(InvalidCount), 52 | #[error("chunk is too large")] 53 | ChunkTooLarge, 54 | #[error("data path is too large")] 55 | DataPathTooLarge, 56 | #[error("data size is too large")] 57 | DataSizeTooLarge, 58 | #[error("invalid proof: ")] 59 | InvalidProof, 60 | #[error("authoring api: {0}")] 61 | AuthoringApiError(#[from] sc_rpc_api::author::error::Error), 62 | /// Call to an unsafe RPC was denied. 63 | #[error("unsafe api: {0}")] 64 | UnsafeRpcCalled(#[from] sc_rpc_api::UnsafeRpcError), 65 | } 66 | 67 | const BASE_ERROR: i64 = 6000; 68 | 69 | impl From for rpc::Error { 70 | fn from(e: Error) -> Self { 71 | match e { 72 | Error::DataExists => rpc::Error { 73 | code: rpc::ErrorCode::ServerError(BASE_ERROR), 74 | message: "transaction data already exists".into(), 75 | data: None, 76 | }, 77 | Error::ChunkExists => rpc::Error { 78 | code: rpc::ErrorCode::ServerError(BASE_ERROR + 1), 79 | message: "chunk data already exists".into(), 80 | data: None, 81 | }, 82 | Error::DataTooLarge( invalid_count) => rpc::Error { 83 | code: rpc::ErrorCode::ServerError(BASE_ERROR + 2), 84 | message: format!("transaction data is too large. {}", invalid_count), 85 | data: Some("the transaction data has to be uploaded or downloaded chunk by chunk for being too large.".into()), 86 | }, 87 | Error::ChunkTooLarge => rpc::Error { 88 | code: rpc::ErrorCode::ServerError(BASE_ERROR + 3), 89 | message: "chunk data is too large".into(), 90 | data: None, 91 | }, 92 | Error::DataPathTooLarge => rpc::Error { 93 | code: rpc::ErrorCode::ServerError(BASE_ERROR + 4), 94 | message: "data path is too large".into(), 95 | data: None, 96 | }, 97 | Error::DataSizeTooLarge => rpc::Error { 98 | code: rpc::ErrorCode::ServerError(BASE_ERROR + 5), 99 | message: "data size is too large".into(), 100 | data: None, 101 | }, 102 | Error::InvalidProof => rpc::Error { 103 | code: rpc::ErrorCode::ServerError(BASE_ERROR + 6), 104 | message: "chunk proof is invalid".into(), 105 | data: None, 106 | }, 107 | Error::AuthoringApiError(e) => rpc::Error { 108 | code: rpc::ErrorCode::ServerError(BASE_ERROR + 7), 109 | message: e.to_string(), 110 | data: None, 111 | }, 112 | Error::UnsafeRpcCalled(e) => e.into(), 113 | } 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /scripts/pallet-weights-template.hbs: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | // This file is part of Canyon. 3 | // 4 | // Copyright (c) 2021 Canyon Labs. 5 | // 6 | // Canyon is free software: you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published 8 | // by the Free Software Foundation, either version 3 of the License, 9 | // or (at your option) any later version. 10 | // 11 | // Canyon is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with Canyon. If not, see . 18 | 19 | //! Autogenerated weights for {{pallet}} 20 | //! 21 | //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION {{version}} 22 | //! DATE: {{date}}, STEPS: `{{cmd.steps}}`, REPEAT: {{cmd.repeat}}, LOW RANGE: `{{cmd.lowest_range_values}}`, HIGH RANGE: `{{cmd.highest_range_values}}` 23 | //! EXECUTION: {{cmd.execution}}, WASM-EXECUTION: {{cmd.wasm_execution}}, CHAIN: {{cmd.chain}}, DB CACHE: {{cmd.db_cache}} 24 | 25 | // Executed Command: 26 | {{#each args as |arg|~}} 27 | // {{arg}} 28 | {{/each}} 29 | 30 | #![allow(clippy::all)] 31 | #![allow(unused_parens)] 32 | #![allow(unused_imports)] 33 | 34 | use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; 35 | use sp_std::marker::PhantomData; 36 | 37 | /// Weight functions needed for {{pallet}}. 38 | pub trait WeightInfo { 39 | {{~#each benchmarks as |benchmark|}} 40 | fn {{benchmark.name~}} 41 | ( 42 | {{~#each benchmark.components as |c| ~}} 43 | {{c.name}}: u32, {{/each~}} 44 | ) -> Weight; 45 | {{~/each}} 46 | } 47 | 48 | /// Weights for {{pallet}} using the Substrate node and recommended hardware. 49 | pub struct SubstrateWeight(PhantomData); 50 | impl WeightInfo for SubstrateWeight { 51 | {{~#each benchmarks as |benchmark|}} 52 | {{~#each benchmark.comments as |comment|}} 53 | // {{comment}} 54 | {{~/each}} 55 | fn {{benchmark.name~}} 56 | ( 57 | {{~#each benchmark.components as |c| ~}} 58 | {{~#if (not c.is_used)}}_{{/if}}{{c.name}}: u32, {{/each~}} 59 | ) -> Weight { 60 | ({{underscore benchmark.base_weight}} as Weight) 61 | {{~#each benchmark.component_weight as |cw|}} 62 | // Standard Error: {{underscore cw.error}} 63 | .saturating_add(({{underscore cw.slope}} as Weight).saturating_mul({{cw.name}} as Weight)) 64 | {{~/each}} 65 | {{~#if (ne benchmark.base_reads "0")}} 66 | .saturating_add(T::DbWeight::get().reads({{benchmark.base_reads}} as Weight)) 67 | {{~/if}} 68 | {{~#each benchmark.component_reads as |cr|}} 69 | .saturating_add(T::DbWeight::get().reads(({{cr.slope}} as Weight).saturating_mul({{cr.name}} as Weight))) 70 | {{~/each}} 71 | {{~#if (ne benchmark.base_writes "0")}} 72 | .saturating_add(T::DbWeight::get().writes({{benchmark.base_writes}} as Weight)) 73 | {{~/if}} 74 | {{~#each benchmark.component_writes as |cw|}} 75 | .saturating_add(T::DbWeight::get().writes(({{cw.slope}} as Weight).saturating_mul({{cw.name}} as Weight))) 76 | {{~/each}} 77 | } 78 | {{~/each}} 79 | } 80 | 81 | // For backwards compatibility and tests 82 | impl WeightInfo for () { 83 | {{~#each benchmarks as |benchmark|}} 84 | {{~#each benchmark.comments as |comment|}} 85 | // {{comment}} 86 | {{~/each}} 87 | fn {{benchmark.name~}} 88 | ( 89 | {{~#each benchmark.components as |c| ~}} 90 | {{~#if (not c.is_used)}}_{{/if}}{{c.name}}: u32, {{/each~}} 91 | ) -> Weight { 92 | ({{underscore benchmark.base_weight}} as Weight) 93 | {{~#each benchmark.component_weight as |cw|}} 94 | // Standard Error: {{underscore cw.error}} 95 | .saturating_add(({{underscore cw.slope}} as Weight).saturating_mul({{cw.name}} as Weight)) 96 | {{~/each}} 97 | {{~#if (ne benchmark.base_reads "0")}} 98 | .saturating_add(RocksDbWeight::get().reads({{benchmark.base_reads}} as Weight)) 99 | {{~/if}} 100 | {{~#each benchmark.component_reads as |cr|}} 101 | .saturating_add(RocksDbWeight::get().reads(({{cr.slope}} as Weight).saturating_mul({{cr.name}} as Weight))) 102 | {{~/each}} 103 | {{~#if (ne benchmark.base_writes "0")}} 104 | .saturating_add(RocksDbWeight::get().writes({{benchmark.base_writes}} as Weight)) 105 | {{~/if}} 106 | {{~#each benchmark.component_writes as |cw|}} 107 | .saturating_add(RocksDbWeight::get().writes(({{cw.slope}} as Weight).saturating_mul({{cw.name}} as Weight))) 108 | {{~/each}} 109 | } 110 | {{~/each}} 111 | } 112 | -------------------------------------------------------------------------------- /client/rpc/src/permastore/mod.rs: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | // This file is part of Canyon. 3 | // 4 | // Copyright (c) 2021 Canyon Labs. 5 | // 6 | // Canyon is free software: you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published 8 | // by the Free Software Foundation, either version 3 of the License, 9 | // or (at your option) any later version. 10 | // 11 | // Canyon is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with Canyon. If not, see . 18 | 19 | #[cfg(test)] 20 | mod tests; 21 | 22 | use std::marker::PhantomData; 23 | use std::ops::Deref; 24 | use std::sync::Arc; 25 | 26 | use futures::future::FutureExt; 27 | use parking_lot::RwLock; 28 | 29 | use sc_rpc_api::{ 30 | author::{error::FutureResult, hash::ExtrinsicOrHash, AuthorApi}, 31 | DenyUnsafe, 32 | }; 33 | use sc_transaction_pool_api::{TransactionPool, TxHash}; 34 | 35 | use sp_core::{Bytes, Encode, H256}; 36 | use sp_runtime::traits::{BlakeTwo256, Block as BlockT, Hash}; 37 | 38 | use cc_rpc_api::permastore::{ 39 | error::{Error, InvalidCount, Result}, 40 | PermastoreApi, 41 | }; 42 | use cp_permastore::{PermaStorage, CHUNK_SIZE}; 43 | 44 | #[derive(Debug)] 45 | pub struct Permastore { 46 | /// Permanent data storage. 47 | storage: Arc>, 48 | /// Transaction pool. 49 | pool: Arc

, 50 | /// Authoring api. 51 | author: A, 52 | /// Whether to deny unsafe calls 53 | /// 54 | /// TODO: since this is a pretty dangerous operation we might 55 | /// need a more restricted way to prevent from the risks. 56 | deny_unsafe: DenyUnsafe, 57 | /// Block. 58 | phatom: PhantomData, 59 | } 60 | 61 | impl Permastore { 62 | pub fn new(storage: T, pool: Arc

, author: A, deny_unsafe: DenyUnsafe) -> Self { 63 | Self { 64 | storage: Arc::new(RwLock::new(storage)), 65 | pool, 66 | author, 67 | deny_unsafe, 68 | phatom: PhantomData::, 69 | } 70 | } 71 | } 72 | 73 | /// Maximum byte size of uploading transaction data directly. 10MiB 74 | const MAX_UPLOAD_DATA_SIZE: u32 = 10 * 1024 * 1024; 75 | 76 | /// Maximum byte size of downloading transaction data directly. 12MiB 77 | const MAX_DOWNLOAD_DATA_SIZE: u32 = 12 * 1024 * 1024; 78 | 79 | impl PermastoreApi, ::Hash> for Permastore 80 | where 81 | T: PermaStorage + 'static, 82 | P: TransactionPool + Send + Sync + 'static, 83 | B: BlockT, 84 | A: AuthorApi, ::Hash>, 85 | { 86 | fn submit_extrinsic(&self, ext: Bytes, data: Bytes) -> FutureResult> { 87 | if let Err(e) = self.submit(data) { 88 | return async move { Err(sc_rpc_api::author::error::Error::Client(Box::new(e))) } 89 | .boxed(); 90 | } 91 | self.author.submit_extrinsic(ext) 92 | } 93 | 94 | fn remove_extrinsic( 95 | &self, 96 | bytes_or_hash: Vec>>, 97 | ) -> Result>> { 98 | // FIXME: remove the transaction data directly or later? 99 | Ok(self.author.remove_extrinsic(bytes_or_hash)?) 100 | } 101 | 102 | fn remove_data(&self, chunk_root: ::Hash) -> Result { 103 | self.deny_unsafe.check_if_safe()?; 104 | 105 | self.storage.write().remove(chunk_root.encode().as_slice()); 106 | 107 | Ok(true) 108 | } 109 | 110 | // Can this be an attack as anyone can submit arbitrary data to the node? 111 | // TODO: add tests for submit and retrieve? 112 | fn submit(&self, value: Bytes) -> Result { 113 | let data_size = value.deref().len() as u32; 114 | if data_size > MAX_UPLOAD_DATA_SIZE { 115 | return Err(Error::DataTooLarge(InvalidCount::new( 116 | data_size, 117 | MAX_UPLOAD_DATA_SIZE, 118 | ))); 119 | } 120 | 121 | let chunks = value 122 | .0 123 | .chunks(CHUNK_SIZE as usize) 124 | .map(|c| BlakeTwo256::hash(c).encode()) 125 | .collect(); 126 | 127 | let chunk_root = BlakeTwo256::ordered_trie_root(chunks); 128 | 129 | let key = chunk_root.encode(); 130 | 131 | log::debug!( 132 | target: "rpc::permastore", 133 | "Submitted chunk_root: {:?}, stored key: {:?}", 134 | chunk_root, key, 135 | ); 136 | 137 | // TODO: verify chunk_root matches the submitted data. 138 | self.storage.write().submit(key.as_slice(), &*value); 139 | 140 | Ok(chunk_root) 141 | } 142 | 143 | fn retrieve(&self, key: Bytes) -> Result> { 144 | if let Some(value) = self.storage.read().retrieve(&*key) { 145 | let data_size = value.len() as u32; 146 | if data_size > MAX_DOWNLOAD_DATA_SIZE { 147 | return Err(Error::DataTooLarge(InvalidCount::new( 148 | data_size, 149 | MAX_DOWNLOAD_DATA_SIZE, 150 | ))); 151 | } 152 | Ok(Some(value.into())) 153 | } else { 154 | Ok(None) 155 | } 156 | } 157 | } 158 | -------------------------------------------------------------------------------- /client/consensus/poa/src/chunk_proof.rs: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | // This file is part of Canyon. 3 | // 4 | // Copyright (c) 2021 Canyon Labs. 5 | // 6 | // Canyon is free software: you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published 8 | // by the Free Software Foundation, either version 3 of the License, 9 | // or (at your option) any later version. 10 | // 11 | // Canyon is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with Canyon. If not, see . 18 | 19 | use sp_core::H256; 20 | use sp_io::hashing::blake2_256; 21 | use sp_trie::TrieMut; 22 | 23 | use cp_consensus_poa::{encode_index, ChunkProof}; 24 | use cp_permastore::{Hasher, TrieLayout, VerifyError}; 25 | 26 | use crate::trie::TrieError; 27 | 28 | /// A verifier for chunk proof. 29 | #[derive(Debug, Clone)] 30 | pub struct ChunkProofVerifier(pub ChunkProof); 31 | 32 | impl ChunkProofVerifier { 33 | /// Creates a new instance of [`ChunkProofVerifier`]. 34 | pub fn new(chunk_proof: ChunkProof) -> Self { 35 | Self(chunk_proof) 36 | } 37 | 38 | /// Returns `Ok(())` if the chunk proof matches given `chunk_root`. 39 | pub fn verify(&self, chunk_root: &H256) -> Result<(), VerifyError> { 40 | verify_chunk_proof( 41 | chunk_root, 42 | self.0.chunk.clone(), 43 | self.0.chunk_index, 44 | &self.0.proof, 45 | ) 46 | } 47 | } 48 | 49 | /// Verifies the chunk matches given `chunk_root` and `proof`. 50 | pub fn verify_chunk_proof( 51 | chunk_root: &H256, 52 | chunk: Vec, 53 | chunk_index: u32, 54 | proof: &[Vec], 55 | ) -> Result<(), VerifyError> { 56 | sp_trie::verify_trie_proof::( 57 | chunk_root, 58 | proof, 59 | &[(encode_index(chunk_index), Some(blake2_256(&chunk)))], 60 | ) 61 | } 62 | 63 | /// A builder for creating a [`ChunkProof`] from the entire raw transaction data. 64 | #[derive(Debug, Clone)] 65 | pub struct ChunkProofBuilder { 66 | /// Raw bytes of entire transaction data. 67 | data: Vec, 68 | /// Size of per data chunk in bytes. 69 | chunk_size: u32, 70 | /// Index of the recall chunk. 71 | target_chunk_index: u32, 72 | } 73 | 74 | impl ChunkProofBuilder { 75 | /// Constructs an instance of [`ChunkProofBuilder`]. 76 | pub fn new(data: Vec, chunk_size: u32, transaction_data_offset: u32) -> Self { 77 | debug_assert!(chunk_size > 0); 78 | 79 | let target_chunk_index = transaction_data_offset / chunk_size; 80 | 81 | Self { 82 | data, 83 | chunk_size, 84 | target_chunk_index, 85 | } 86 | } 87 | 88 | /// Creates a [`ChunkProof`]. 89 | /// 90 | /// # Panics 91 | /// 92 | /// Panics if the building of chunks trie failed. 93 | pub fn build(&self) -> Result { 94 | let mut target_chunk = Vec::with_capacity(self.chunk_size as usize); 95 | 96 | let mut db = sp_trie::MemoryDB::::default(); 97 | let mut chunk_root = sp_trie::empty_trie_root::(); 98 | 99 | { 100 | let mut trie = sp_trie::TrieDBMut::::new(&mut db, &mut chunk_root); 101 | 102 | let chunks = self 103 | .data 104 | .chunks(self.chunk_size as usize) 105 | .map(|c| c.to_vec()); 106 | 107 | for (index, chunk) in chunks.enumerate() { 108 | // Build the trie using chunk id. 109 | trie.insert(&encode_index(index as u32), &blake2_256(&chunk)) 110 | .unwrap_or_else(|e| { 111 | panic!( 112 | "Failed to insert the trie node: {:?}, chunk index: {}", 113 | e, index 114 | ) 115 | }); 116 | 117 | if index == self.target_chunk_index as usize { 118 | target_chunk = chunk; 119 | } 120 | } 121 | 122 | trie.commit(); 123 | } 124 | 125 | let proof = sp_trie::generate_trie_proof::( 126 | &db, 127 | chunk_root, 128 | &[encode_index(self.target_chunk_index)], 129 | ) 130 | .map_err(|e| TrieError::Trie(Box::new(e)))?; 131 | 132 | Ok(ChunkProof { 133 | chunk: target_chunk, 134 | chunk_index: self.target_chunk_index, 135 | proof, 136 | }) 137 | } 138 | } 139 | 140 | #[cfg(test)] 141 | mod tests { 142 | use super::*; 143 | 144 | #[test] 145 | fn test_chunk_proof_verify() { 146 | use std::str::FromStr; 147 | 148 | let data = b"hello".to_vec(); 149 | let chunk_proof_builder = ChunkProofBuilder::new(data, 1, 3); 150 | let chunk_proof = chunk_proof_builder.build().unwrap(); 151 | let chunk_root = sp_core::H256::from_str( 152 | "0x26976dd39b2ea67e0b51f3511c394882523e91d7249a784c589da9654fbc51dc", 153 | ) 154 | .unwrap(); 155 | 156 | assert!(verify_chunk_proof(&chunk_root, b"l".to_vec(), 3, &chunk_proof.proof).is_ok()); 157 | assert!(verify_chunk_proof(&chunk_root, b"l".to_vec(), 4, &chunk_proof.proof).is_err()); 158 | } 159 | } 160 | -------------------------------------------------------------------------------- /client/consensus/poa/src/tx_proof.rs: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | // This file is part of Canyon. 3 | // 4 | // Copyright (c) 2021 Canyon Labs. 5 | // 6 | // Canyon is free software: you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published 8 | // by the Free Software Foundation, either version 3 of the License, 9 | // or (at your option) any later version. 10 | // 11 | // Canyon is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with Canyon. If not, see . 18 | 19 | use codec::Encode; 20 | 21 | use sp_core::H256; 22 | use sp_runtime::traits::Block as BlockT; 23 | 24 | use canyon_primitives::ExtrinsicIndex; 25 | use cp_consensus_poa::encode_index; 26 | use cp_permastore::{TrieLayout, VerifyError}; 27 | 28 | use crate::trie::{prepare_trie_proof, TrieError}; 29 | 30 | /// Returns the calculated merkle proof given `extrinsic_index` and `extrinsics_root`. 31 | /// 32 | /// # Panics 33 | /// 34 | /// Panics if the calculated extrinsic root mismatches. 35 | pub fn build_extrinsic_proof>( 36 | extrinsic_index: ExtrinsicIndex, 37 | extrinsics_root: Block::Hash, 38 | extrinsics: Vec, 39 | ) -> Result>, TrieError> { 40 | let leaves = extrinsics.iter().map(|xt| xt.encode()).collect::>(); 41 | 42 | let (db, root) = prepare_trie_proof(leaves); 43 | 44 | assert_eq!( 45 | extrinsics_root, root, 46 | "`extrinsics_root` mismatches the calculated root" 47 | ); 48 | 49 | let proof = sp_trie::generate_trie_proof::( 50 | &db, 51 | extrinsics_root, 52 | &[encode_index(extrinsic_index)], 53 | ) 54 | .map_err(|e| TrieError::Trie(Box::new(e)))?; 55 | 56 | Ok(proof) 57 | } 58 | 59 | /// A verifier for tx proof. 60 | #[derive(Debug, Clone)] 61 | pub struct TxProofVerifier { 62 | /// Recall extrinsic. 63 | recall_extrinsic: B::Extrinsic, 64 | /// Extrinsics root of recall block. 65 | extrinsics_root: B::Hash, 66 | /// Extrinsic index of `recall_extrinsic`. 67 | recall_extrinsic_index: ExtrinsicIndex, 68 | } 69 | 70 | impl> TxProofVerifier { 71 | /// Creates a new instance of [`TxProofVerifier`]. 72 | pub fn new( 73 | recall_extrinsic: B::Extrinsic, 74 | extrinsics_root: B::Hash, 75 | recall_extrinsic_index: ExtrinsicIndex, 76 | ) -> Self { 77 | Self { 78 | recall_extrinsic, 79 | extrinsics_root, 80 | recall_extrinsic_index, 81 | } 82 | } 83 | 84 | /// Returns Ok(()) if `tx_path` matches the inner tx proof. 85 | pub fn verify(&self, tx_path: &[Vec]) -> Result<(), VerifyError> { 86 | verify_extrinsic_proof( 87 | &self.extrinsics_root, 88 | self.recall_extrinsic_index, 89 | self.recall_extrinsic.encode(), 90 | tx_path, 91 | ) 92 | } 93 | } 94 | 95 | /// Verify the extrinsic proof against the extrinsics root and related encoded extrinsic. 96 | /// 97 | /// Returns Ok(()) if the extrinsic proof is valid. 98 | pub fn verify_extrinsic_proof( 99 | extrinsics_root: &H256, 100 | extrinsic_index: ExtrinsicIndex, 101 | encoded_extrinsic: Vec, 102 | proof: &[Vec], 103 | ) -> Result<(), VerifyError> { 104 | sp_trie::verify_trie_proof::( 105 | extrinsics_root, 106 | proof, 107 | &[(encode_index(extrinsic_index), Some(encoded_extrinsic))], 108 | ) 109 | } 110 | 111 | #[cfg(test)] 112 | mod tests { 113 | use super::*; 114 | use sc_block_builder::{BlockBuilder, RecordProof}; 115 | use sp_blockchain::HeaderBackend; 116 | use sp_keyring::AccountKeyring::{Alice, Bob}; 117 | use substrate_test_runtime::{Block, Transfer}; 118 | use substrate_test_runtime_client::{ 119 | BlockBuilderExt, DefaultTestClientBuilderExt, TestClientBuilderExt, 120 | }; 121 | 122 | #[test] 123 | fn test_extrinsic_proof() { 124 | let builder = substrate_test_runtime_client::TestClientBuilder::new(); 125 | let backend = builder.backend(); 126 | let client = builder.build(); 127 | 128 | let mut block_builder = BlockBuilder::new( 129 | &client, 130 | client.info().best_hash, 131 | client.info().best_number, 132 | RecordProof::Yes, 133 | Default::default(), 134 | &*backend, 135 | ) 136 | .unwrap(); 137 | 138 | block_builder 139 | .push_transfer(Transfer { 140 | from: Alice.into(), 141 | to: Bob.into(), 142 | amount: 123, 143 | nonce: 0, 144 | }) 145 | .unwrap(); 146 | 147 | block_builder 148 | .push_transfer(Transfer { 149 | from: Bob.into(), 150 | to: Alice.into(), 151 | amount: 1, 152 | nonce: 0, 153 | }) 154 | .unwrap(); 155 | 156 | let built_block = block_builder.build().unwrap(); 157 | 158 | let (block, extrinsics) = built_block.block.deconstruct(); 159 | 160 | let extrinsics_root = block.extrinsics_root; 161 | 162 | let proof0 = 163 | build_extrinsic_proof::(0, extrinsics_root, extrinsics.clone()).unwrap(); 164 | 165 | let proof1 = 166 | build_extrinsic_proof::(1, extrinsics_root, extrinsics.clone()).unwrap(); 167 | 168 | assert!(verify_extrinsic_proof( 169 | &extrinsics_root, 170 | 0, 171 | extrinsics[0].clone().encode(), 172 | &proof0 173 | ) 174 | .is_ok()); 175 | 176 | assert!(verify_extrinsic_proof( 177 | &extrinsics_root, 178 | 0, 179 | extrinsics[1].clone().encode(), 180 | &proof0 181 | ) 182 | .is_err()); 183 | 184 | assert!(verify_extrinsic_proof( 185 | &extrinsics_root, 186 | 1, 187 | extrinsics[1].clone().encode(), 188 | &proof1 189 | ) 190 | .is_ok()); 191 | } 192 | } 193 | -------------------------------------------------------------------------------- /client/datastore/src/lib.rs: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | // This file is part of Canyon. 3 | // 4 | // Copyright (c) 2021 Canyon Labs. 5 | // 6 | // Canyon is free software: you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published 8 | // by the Free Software Foundation, either version 3 of the License, 9 | // or (at your option) any later version. 10 | // 11 | // Canyon is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with Canyon. If not, see . 18 | 19 | #![deny(missing_docs, unused_extern_crates)] 20 | 21 | //! This crate provides the feature of persistent storage for the transaction data 22 | //! expected to exist indefinitely. 23 | //! 24 | //! Currently, it is implemented on the top of offchain storage, which is a persistent 25 | //! local storage of each node. 26 | 27 | #[cfg(test)] 28 | mod tests; 29 | 30 | use std::sync::Arc; 31 | 32 | use codec::Encode; 33 | 34 | use sc_client_db::offchain::LocalStorage; 35 | use sp_api::ProvideRuntimeApi; 36 | use sp_blockchain::HeaderBackend; 37 | use sp_runtime::{ 38 | generic::BlockId, 39 | offchain::OffchainStorage, 40 | traits::{Block as BlockT, NumberFor}, 41 | }; 42 | 43 | use cp_permastore::{PermaStorage, PermastoreApi}; 44 | 45 | /// Permanent storage backed by offchain storage. 46 | #[derive(Clone)] 47 | pub struct PermanentStorage { 48 | offchain_storage: LocalStorage, 49 | client: Arc, 50 | } 51 | 52 | impl PermanentStorage { 53 | /// Creates new perma storage for tests. 54 | #[cfg(any(feature = "test-helpers", test))] 55 | pub fn new_test(client: Arc) -> Self { 56 | Self { 57 | offchain_storage: LocalStorage::new_test(), 58 | client, 59 | } 60 | } 61 | 62 | /// Creates a new instance of [`PermaStorage`] backed by offchain storage. 63 | pub fn new(offchain_storage: LocalStorage, client: Arc) -> Self { 64 | Self { 65 | offchain_storage, 66 | client, 67 | } 68 | } 69 | } 70 | 71 | impl cp_permastore::PermaStorage for PermanentStorage 72 | where 73 | C: Send + Sync, 74 | { 75 | /// Sets the value of transaction data given `key`. 76 | /// 77 | /// # Arguments 78 | /// 79 | /// * `key`: encoded chunk root of transaction data. 80 | /// * `value`: entire data of a transaction. 81 | /// 82 | /// NOTE: the maximum size of served value is 10MiB, 83 | /// this limit should be enforced by the higher level API. 84 | fn submit(&mut self, key: &[u8], value: &[u8]) { 85 | self.offchain_storage 86 | .set(sp_offchain::STORAGE_PREFIX, key, value) 87 | } 88 | 89 | /// Returns the entire transaction data given `key`. 90 | /// 91 | /// # Arguments 92 | /// 93 | /// * `key`: chunk_root of the transaction data. 94 | fn retrieve(&self, key: &[u8]) -> Option> { 95 | self.offchain_storage.get(sp_offchain::STORAGE_PREFIX, key) 96 | } 97 | 98 | /// Removes the storage value under given key. 99 | /// 100 | /// # Arguments 101 | /// 102 | /// * `key`: encoded chunk root of transaction data. 103 | fn remove(&mut self, key: &[u8]) { 104 | self.offchain_storage 105 | .remove(sp_offchain::STORAGE_PREFIX, key) 106 | } 107 | } 108 | 109 | /// Error type for datastore. 110 | #[derive(thiserror::Error, Debug)] 111 | pub enum Error { 112 | /// Block number not found. 113 | #[error("Block number not found given block id `{0}`")] 114 | BlockNumberNotFound(BlockId), 115 | /// Chunk root does not exist. 116 | #[error("Chunk root is None at block: {0}, extrinsic index: {1}")] 117 | ChunkRootIsNone(BlockId, u32), 118 | /// Blockchain error. 119 | #[error(transparent)] 120 | Blockchain(#[from] Box), 121 | /// Runtime api error. 122 | #[error(transparent)] 123 | ApiError(#[from] sp_api::ApiError), 124 | } 125 | 126 | /// Backend for storing a map of (block_number, extrinsic_index) to chunk_root. 127 | pub trait ChunkRootBackend { 128 | /// Returns chunk root given `block_number` and `extrinsic_index`. 129 | /// 130 | /// It's fetched from the runtime now. 131 | fn chunk_root( 132 | &self, 133 | at: Option>, 134 | block_number: NumberFor, 135 | extrinsic_index: u32, 136 | ) -> Result, Error>; 137 | } 138 | 139 | /// Permanent transaction data backend. 140 | /// 141 | /// High level API for accessing the transaction data. 142 | pub trait TransactionDataBackend: PermaStorage + ChunkRootBackend { 143 | /// Get transaction data. Returns `None` if data is not found. 144 | fn transaction_data( 145 | &self, 146 | id: BlockId, 147 | extrinsic_index: u32, 148 | ) -> Result>, Error>; 149 | } 150 | 151 | impl TransactionDataBackend for PermanentStorage 152 | where 153 | Block: BlockT, 154 | C: HeaderBackend + ProvideRuntimeApi + Send + Sync, 155 | C::Api: cp_permastore::PermastoreApi, u32, Block::Hash>, 156 | { 157 | fn transaction_data( 158 | &self, 159 | block_id: BlockId, 160 | extrinsic_index: u32, 161 | ) -> Result>, Error> { 162 | log::debug!( 163 | target: "datastore", 164 | "Fetching chunk root at block_id: {}, extrinsic_index: {}", 165 | block_id, extrinsic_index, 166 | ); 167 | 168 | let block_number = self 169 | .client 170 | .block_number_from_id(&block_id) 171 | .map_err(Box::new)? 172 | .ok_or(Error::BlockNumberNotFound(block_id))?; 173 | 174 | let chunk_root = self 175 | .chunk_root(None, block_number, extrinsic_index)? 176 | .ok_or(Error::ChunkRootIsNone(block_id, extrinsic_index))?; 177 | 178 | let key = chunk_root.encode(); 179 | log::debug!( 180 | target: "datastore", 181 | "Fetching the transaction data, chunk root: {:?}, database key: {:?}", 182 | chunk_root, key, 183 | ); 184 | 185 | Ok(self.retrieve(&key)) 186 | } 187 | } 188 | 189 | impl ChunkRootBackend for PermanentStorage 190 | where 191 | Block: BlockT, 192 | C: HeaderBackend + ProvideRuntimeApi + Send + Sync, 193 | C::Api: cp_permastore::PermastoreApi, u32, Block::Hash>, 194 | { 195 | fn chunk_root( 196 | &self, 197 | at: Option>, 198 | block_number: NumberFor, 199 | extrinsic_index: u32, 200 | ) -> Result, Error> { 201 | let at = at.unwrap_or_else(|| BlockId::hash(self.client.info().best_hash)); 202 | self.client 203 | .runtime_api() 204 | .chunk_root(&at, block_number, extrinsic_index) 205 | .map_err(Error::ApiError) 206 | } 207 | } 208 | -------------------------------------------------------------------------------- /cli/src/command.rs: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | // This file is part of Canyon. 3 | // 4 | // Copyright (c) 2021 Canyon Labs. 5 | // 6 | // Canyon is free software: you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published 8 | // by the Free Software Foundation, either version 3 of the License, 9 | // or (at your option) any later version. 10 | // 11 | // Canyon is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with Canyon. If not, see . 18 | 19 | use sc_cli::{ChainSpec, Result, Role, RuntimeVersion, SubstrateCli}; 20 | use sc_service::PartialComponents; 21 | 22 | use canyon_executor::ExecutorDispatch; 23 | use canyon_runtime::{Block, RuntimeApi}; 24 | 25 | use crate::service::new_partial; 26 | use crate::{chain_spec, service, Cli, Subcommand}; 27 | 28 | impl SubstrateCli for Cli { 29 | fn impl_name() -> String { 30 | "Canyon Node".into() 31 | } 32 | 33 | fn impl_version() -> String { 34 | env!("SUBSTRATE_CLI_IMPL_VERSION").into() 35 | } 36 | 37 | fn description() -> String { 38 | env!("CARGO_PKG_DESCRIPTION").into() 39 | } 40 | 41 | fn author() -> String { 42 | env!("CARGO_PKG_AUTHORS").into() 43 | } 44 | 45 | fn support_url() -> String { 46 | "https://github.com/canyon-network/canyon/issues/new".into() 47 | } 48 | 49 | fn copyright_start_year() -> i32 { 50 | 2021 51 | } 52 | 53 | fn load_spec(&self, id: &str) -> std::result::Result, String> { 54 | let spec = match id { 55 | "" => { 56 | return Err( 57 | "Please specify which chain you want to run, e.g. --dev or --chain=local" 58 | .into(), 59 | ) 60 | } 61 | "dev" => Box::new(chain_spec::development_config()), 62 | "local" => Box::new(chain_spec::local_testnet_config()), 63 | "staging" => Box::new(chain_spec::staging_testnet_config()), 64 | path => Box::new(chain_spec::ChainSpec::from_json_file( 65 | std::path::PathBuf::from(path), 66 | )?), 67 | }; 68 | Ok(spec) 69 | } 70 | 71 | fn native_runtime_version(_: &Box) -> &'static RuntimeVersion { 72 | &canyon_runtime::VERSION 73 | } 74 | } 75 | 76 | /// Parse command line arguments into service configuration. 77 | pub fn run() -> Result<()> { 78 | let cli = Cli::from_args(); 79 | 80 | match &cli.subcommand { 81 | None => { 82 | let runner = cli.create_runner(&cli.run)?; 83 | runner.run_node_until_exit(|config| async move { 84 | match config.role { 85 | Role::Light => service::new_light(config), 86 | _ => service::new_full(config), 87 | } 88 | .map_err(sc_cli::Error::Service) 89 | }) 90 | } 91 | Some(Subcommand::Inspect(cmd)) => { 92 | let runner = cli.create_runner(cmd)?; 93 | 94 | runner.sync_run(|config| cmd.run::(config)) 95 | } 96 | Some(Subcommand::Benchmark(cmd)) => { 97 | if cfg!(feature = "runtime-benchmarks") { 98 | let runner = cli.create_runner(cmd)?; 99 | 100 | runner.sync_run(|config| cmd.run::(config)) 101 | } else { 102 | Err("Benchmarking wasn't enabled when building the node. \ 103 | You can enable it with `--features runtime-benchmarks`." 104 | .into()) 105 | } 106 | } 107 | Some(Subcommand::Key(cmd)) => cmd.run(&cli), 108 | Some(Subcommand::Sign(cmd)) => cmd.run(), 109 | Some(Subcommand::Verify(cmd)) => cmd.run(), 110 | Some(Subcommand::Vanity(cmd)) => cmd.run(), 111 | Some(Subcommand::BuildSpec(cmd)) => { 112 | let runner = cli.create_runner(cmd)?; 113 | runner.sync_run(|config| cmd.run(config.chain_spec, config.network)) 114 | } 115 | Some(Subcommand::CheckBlock(cmd)) => { 116 | let runner = cli.create_runner(cmd)?; 117 | runner.async_run(|config| { 118 | let PartialComponents { 119 | client, 120 | task_manager, 121 | import_queue, 122 | .. 123 | } = new_partial(&config)?; 124 | Ok((cmd.run(client, import_queue), task_manager)) 125 | }) 126 | } 127 | Some(Subcommand::ExportBlocks(cmd)) => { 128 | let runner = cli.create_runner(cmd)?; 129 | runner.async_run(|config| { 130 | let PartialComponents { 131 | client, 132 | task_manager, 133 | .. 134 | } = new_partial(&config)?; 135 | Ok((cmd.run(client, config.database), task_manager)) 136 | }) 137 | } 138 | Some(Subcommand::ExportState(cmd)) => { 139 | let runner = cli.create_runner(cmd)?; 140 | runner.async_run(|config| { 141 | let PartialComponents { 142 | client, 143 | task_manager, 144 | .. 145 | } = new_partial(&config)?; 146 | Ok((cmd.run(client, config.chain_spec), task_manager)) 147 | }) 148 | } 149 | Some(Subcommand::ImportBlocks(cmd)) => { 150 | let runner = cli.create_runner(cmd)?; 151 | runner.async_run(|config| { 152 | let PartialComponents { 153 | client, 154 | task_manager, 155 | import_queue, 156 | .. 157 | } = new_partial(&config)?; 158 | Ok((cmd.run(client, import_queue), task_manager)) 159 | }) 160 | } 161 | Some(Subcommand::PurgeChain(cmd)) => { 162 | let runner = cli.create_runner(cmd)?; 163 | runner.sync_run(|config| cmd.run(config.database)) 164 | } 165 | Some(Subcommand::Revert(cmd)) => { 166 | let runner = cli.create_runner(cmd)?; 167 | runner.async_run(|config| { 168 | let PartialComponents { 169 | client, 170 | task_manager, 171 | backend, 172 | .. 173 | } = new_partial(&config)?; 174 | Ok((cmd.run(client, backend), task_manager)) 175 | }) 176 | } 177 | #[cfg(feature = "try-runtime")] 178 | Some(Subcommand::TryRuntime(cmd)) => { 179 | let runner = cli.create_runner(cmd)?; 180 | runner.async_run(|config| { 181 | // we don't need any of the components of new_partial, just a runtime, or a task 182 | // manager to do `async_run`. 183 | let registry = config.prometheus_config.as_ref().map(|cfg| &cfg.registry); 184 | let task_manager = 185 | sc_service::TaskManager::new(config.task_executor.clone(), registry) 186 | .map_err(|e| sc_cli::Error::Service(sc_service::Error::Prometheus(e)))?; 187 | 188 | Ok((cmd.run::(config), task_manager)) 189 | }) 190 | } 191 | } 192 | } 193 | -------------------------------------------------------------------------------- /runtime/src/voter_bags.rs: -------------------------------------------------------------------------------- 1 | // This file is part of Substrate. 2 | 3 | // Copyright (C) 2021 Parity Technologies (UK) Ltd. 4 | // SPDX-License-Identifier: Apache-2.0 5 | 6 | // Licensed under the Apache License, Version 2.0 (the "License"); 7 | // you may not use this file except in compliance with the License. 8 | // You may obtain a copy of the License at 9 | // 10 | // http://www.apache.org/licenses/LICENSE-2.0 11 | // 12 | // Unless required by applicable law or agreed to in writing, software 13 | // distributed under the License is distributed on an "AS IS" BASIS, 14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | 18 | //! Autogenerated voter bag thresholds. 19 | //! 20 | //! Generated on 2021-07-05T09:17:40.469754927+00:00 21 | //! for the node runtime. 22 | 23 | /// Existential weight for this runtime. 24 | #[cfg(any(test, feature = "std"))] 25 | #[allow(unused)] 26 | pub const EXISTENTIAL_WEIGHT: u64 = 100_000_000_000_000; 27 | 28 | /// Constant ratio between bags for this runtime. 29 | #[cfg(any(test, feature = "std"))] 30 | #[allow(unused)] 31 | pub const CONSTANT_RATIO: f64 = 1.0628253590743408; 32 | 33 | /// Upper thresholds delimiting the bag list. 34 | pub const THRESHOLDS: [u64; 200] = [ 35 | 100_000_000_000_000, 36 | 106_282_535_907_434, 37 | 112_959_774_389_150, 38 | 120_056_512_776_105, 39 | 127_599_106_300_477, 40 | 135_615_565_971_369, 41 | 144_135_662_599_590, 42 | 153_191_037_357_827, 43 | 162_815_319_286_803, 44 | 173_044_250_183_800, 45 | 183_915_817_337_347, 46 | 195_470_394_601_017, 47 | 207_750_892_330_229, 48 | 220_802_916_738_890, 49 | 234_674_939_267_673, 50 | 249_418_476_592_914, 51 | 265_088_281_944_639, 52 | 281_742_548_444_211, 53 | 299_443_125_216_738, 54 | 318_255_747_080_822, 55 | 338_250_278_668_647, 56 | 359_500_973_883_001, 57 | 382_086_751_654_776, 58 | 406_091_489_025_036, 59 | 431_604_332_640_068, 60 | 458_720_029_816_222, 61 | 487_539_280_404_019, 62 | 518_169_110_758_247, 63 | 550_723_271_202_866, 64 | 585_322_658_466_782, 65 | 622_095_764_659_305, 66 | 661_179_154_452_653, 67 | 702_717_972_243_610, 68 | 746_866_481_177_808, 69 | 793_788_636_038_393, 70 | 843_658_692_126_636, 71 | 896_661_852_395_681, 72 | 952_994_955_240_703, 73 | 1_012_867_205_499_736, 74 | 1_076_500_951_379_881, 75 | 1_144_132_510_194_192, 76 | 1_216_013_045_975_769, 77 | 1_292_409_502_228_280, 78 | 1_373_605_593_276_862, 79 | 1_459_902_857_901_004, 80 | 1_551_621_779_162_291, 81 | 1_649_102_974_585_730, 82 | 1_752_708_461_114_642, 83 | 1_862_822_999_536_805, 84 | 1_979_855_523_374_646, 85 | 2_104_240_657_545_975, 86 | 2_236_440_332_435_128, 87 | 2_376_945_499_368_703, 88 | 2_526_277_953_866_680, 89 | 2_684_992_273_439_945, 90 | 2_853_677_877_130_641, 91 | 3_032_961_214_443_876, 92 | 3_223_508_091_799_862, 93 | 3_426_026_145_146_232, 94 | 3_641_267_467_913_124, 95 | 3_870_031_404_070_482, 96 | 4_113_167_516_660_186, 97 | 4_371_578_742_827_277, 98 | 4_646_224_747_067_156, 99 | 4_938_125_485_141_739, 100 | 5_248_364_991_899_922, 101 | 5_578_095_407_069_235, 102 | 5_928_541_253_969_291, 103 | 6_301_003_987_036_955, 104 | 6_696_866_825_051_405, 105 | 7_117_599_888_008_300, 106 | 7_564_765_656_719_910, 107 | 8_040_024_775_416_580, 108 | 8_545_142_218_898_723, 109 | 9_081_993_847_142_344, 110 | 9_652_573_371_700_016, 111 | 10_258_999_759_768_490, 112 | 10_903_525_103_419_522, 113 | 11_588_542_983_217_942, 114 | 12_316_597_357_287_042, 115 | 13_090_392_008_832_678, 116 | 13_912_800_587_211_472, 117 | 14_786_877_279_832_732, 118 | 15_715_868_154_526_436, 119 | 16_703_223_214_499_558, 120 | 17_752_609_210_649_358, 121 | 18_867_923_258_814_856, 122 | 20_053_307_312_537_008, 123 | 21_313_163_545_075_252, 124 | 22_652_170_697_804_756, 125 | 24_075_301_455_707_600, 126 | 25_587_840_914_485_432, 127 | 27_195_406_207_875_088, 128 | 28_903_967_368_057_400, 129 | 30_719_869_496_628_636, 130 | 32_649_856_328_471_220, 131 | 34_701_095_276_033_064, 132 | 36_881_204_047_022_752, 133 | 39_198_278_934_370_992, 134 | 41_660_924_883_519_016, 135 | 44_278_287_448_695_240, 136 | 47_060_086_756_856_400, 137 | 50_016_653_605_425_536, 138 | 53_158_967_827_883_320, 139 | 56_498_699_069_691_424, 140 | 60_048_250_125_977_912, 141 | 63_820_803_001_928_304, 142 | 67_830_367_866_937_216, 143 | 72_091_835_084_322_176, 144 | 76_621_030_509_822_880, 145 | 81_434_774_264_248_528, 146 | 86_550_943_198_537_824, 147 | 91_988_537_283_208_848, 148 | 97_767_750_168_749_840, 149 | 103_910_044_178_992_000, 150 | 110_438_230_015_967_792, 151 | 117_376_551_472_255_616, 152 | 124_750_775_465_407_920, 153 | 132_588_287_728_824_640, 154 | 140_918_194_514_440_064, 155 | 149_771_430_684_917_568, 156 | 159_180_874_596_775_264, 157 | 169_181_470_201_085_280, 158 | 179_810_356_815_193_344, 159 | 191_107_007_047_393_216, 160 | 203_113_373_386_768_288, 161 | 215_874_044_002_592_672, 162 | 229_436_408_331_885_600, 163 | 243_850_833_070_063_392, 164 | 259_170_849_218_267_264, 165 | 275_453_350_882_006_752, 166 | 292_758_806_559_399_232, 167 | 311_151_483_703_668_992, 168 | 330_699_687_393_865_920, 169 | 351_476_014_000_157_824, 170 | 373_557_620_785_735_808, 171 | 397_026_512_446_556_096, 172 | 421_969_845_653_044_224, 173 | 448_480_252_724_740_928, 174 | 476_656_185_639_923_904, 175 | 506_602_281_657_757_760, 176 | 538_429_751_910_786_752, 177 | 572_256_794_410_890_176, 178 | 608_209_033_002_485_632, 179 | 646_419_983_893_124_352, 180 | 687_031_551_494_039_552, 181 | 730_194_555_412_054_016, 182 | 776_069_290_549_944_960, 183 | 824_826_122_395_314_176, 184 | 876_646_119_708_695_936, 185 | 931_721_726_960_522_368, 186 | 990_257_479_014_182_144, 187 | 1_052_470_760_709_299_712, 188 | 1_118_592_614_166_106_112, 189 | 1_188_868_596_808_997_376, 190 | 1_263_559_693_295_730_432, 191 | 1_342_943_284_738_898_688, 192 | 1_427_314_178_819_094_784, 193 | 1_516_985_704_615_302_400, 194 | 1_612_290_876_218_400_768, 195 | 1_713_583_629_449_105_408, 196 | 1_821_240_136_273_157_632, 197 | 1_935_660_201_795_120_128, 198 | 2_057_268_749_018_809_600, 199 | 2_186_517_396_888_336_384, 200 | 2_323_886_137_470_138_880, 201 | 2_469_885_118_504_583_168, 202 | 2_625_056_537_947_004_416, 203 | 2_789_976_657_533_970_944, 204 | 2_965_257_942_852_572_160, 205 | 3_151_551_337_860_326_400, 206 | 3_349_548_682_302_620_672, 207 | 3_559_985_281_005_267_968, 208 | 3_783_642_634_583_792_128, 209 | 4_021_351_341_710_503_936, 210 | 4_273_994_183_717_548_544, 211 | 4_542_509_402_991_247_872, 212 | 4_827_894_187_332_742_144, 213 | 5_131_208_373_224_844_288, 214 | 5_453_578_381_757_959_168, 215 | 5_796_201_401_831_965_696, 216 | 6_160_349_836_169_256_960, 217 | 6_547_376_026_650_146_816, 218 | 6_958_717_276_519_173_120, 219 | 7_395_901_188_113_309_696, 220 | 7_860_551_335_934_872_576, 221 | 8_354_393_296_137_270_272, 222 | 8_879_261_054_815_360_000, 223 | 9_437_103_818_898_946_048, 224 | 10_029_993_254_943_105_024, 225 | 10_660_131_182_698_121_216, 226 | 11_329_857_752_030_707_712, 227 | 12_041_660_133_563_240_448, 228 | 12_798_181_755_305_525_248, 229 | 13_602_232_119_581_272_064, 230 | 14_456_797_236_706_498_560, 231 | 15_365_050_714_167_523_328, 232 | 16_330_365_542_480_556_032, 233 | 17_356_326_621_502_140_416, 234 | 18_446_744_073_709_551_615, 235 | ]; 236 | -------------------------------------------------------------------------------- /cli/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "canyon-cli" 3 | version = "0.1.0" 4 | authors = ["Canyon Labs "] 5 | edition = "2018" 6 | build = "build.rs" 7 | 8 | [package.metadata.wasm-pack.profile.release] 9 | # `wasm-opt` has some problems on linux, see 10 | # https://github.com/rustwasm/wasm-pack/issues/781 etc. 11 | wasm-opt = false 12 | 13 | [package.metadata.docs.rs] 14 | targets = ["x86_64-unknown-linux-gnu"] 15 | 16 | [lib] 17 | crate-type = ["cdylib", "rlib"] 18 | 19 | [dependencies] 20 | codec = { package = "parity-scale-codec", version = "2.3" } 21 | futures = "0.3.16" 22 | jsonrpc-pubsub = "18.0.0" 23 | hex-literal = "0.3.1" 24 | log = "0.4.8" 25 | parking_lot = "0.11.1" 26 | rand = "0.7.2" 27 | serde = { version = "1.0.102", features = ["derive"] } 28 | structopt = { version = "0.3.8", optional = true } 29 | 30 | # primitives 31 | sp-authority-discovery = { git = "https://github.com/paritytech/substrate", branch = "master" } 32 | sp-authorship = { git = "https://github.com/paritytech/substrate", branch = "master" } 33 | sp-consensus = { git = "https://github.com/paritytech/substrate", branch = "master" } 34 | sp-consensus-babe = { git = "https://github.com/paritytech/substrate", branch = "master" } 35 | sp-core = { git = "https://github.com/paritytech/substrate", branch = "master" } 36 | sp-finality-grandpa = { git = "https://github.com/paritytech/substrate", branch = "master" } 37 | sp-io = { git = "https://github.com/paritytech/substrate", branch = "master" } 38 | sp-keyring = { git = "https://github.com/paritytech/substrate", branch = "master" } 39 | sp-keystore = { git = "https://github.com/paritytech/substrate", branch = "master" } 40 | sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master" } 41 | sp-timestamp = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" } 42 | sp-transaction-pool = { git = "https://github.com/paritytech/substrate", branch = "master" } 43 | 44 | # client dependencies 45 | sc-authority-discovery = { git = "https://github.com/paritytech/substrate", branch = "master" } 46 | sc-basic-authorship = { git = "https://github.com/paritytech/substrate", branch = "master" } 47 | sc-chain-spec = { git = "https://github.com/paritytech/substrate", branch = "master" } 48 | sc-client-api = { git = "https://github.com/paritytech/substrate", branch = "master" } 49 | sc-client-db = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" } 50 | sc-consensus = { git = "https://github.com/paritytech/substrate", branch = "master" } 51 | sc-consensus-babe = { git = "https://github.com/paritytech/substrate", branch = "master" } 52 | sc-consensus-slots = { git = "https://github.com/paritytech/substrate", branch = "master" } 53 | sc-consensus-uncles = { git = "https://github.com/paritytech/substrate", branch = "master" } 54 | sc-executor = { git = "https://github.com/paritytech/substrate", branch = "master" } 55 | sc-network = { git = "https://github.com/paritytech/substrate", branch = "master" } 56 | sc-offchain = { git = "https://github.com/paritytech/substrate", branch = "master" } 57 | sc-rpc = { git = "https://github.com/paritytech/substrate", branch = "master" } 58 | sc-service = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" } 59 | sc-sync-state-rpc = { git = "https://github.com/paritytech/substrate", branch = "master" } 60 | sc-telemetry = { git = "https://github.com/paritytech/substrate", branch = "master" } 61 | sc-transaction-pool = { git = "https://github.com/paritytech/substrate", branch = "master" } 62 | grandpa = { package = "sc-finality-grandpa", git = "https://github.com/paritytech/substrate", branch = "master" } 63 | sc-tracing = { git = "https://github.com/paritytech/substrate", branch = "master" } 64 | 65 | # frame dependencies 66 | pallet-authority-discovery = { git = "https://github.com/paritytech/substrate", branch = "master" } 67 | pallet-balances = { git = "https://github.com/paritytech/substrate", branch = "master" } 68 | pallet-contracts = { git = "https://github.com/paritytech/substrate", branch = "master" } 69 | pallet-grandpa = { git = "https://github.com/paritytech/substrate", branch = "master" } 70 | pallet-im-online = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" } 71 | pallet-indices = { git = "https://github.com/paritytech/substrate", branch = "master" } 72 | pallet-staking = { git = "https://github.com/paritytech/substrate", branch = "master" } 73 | pallet-timestamp = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" } 74 | pallet-transaction-payment = { git = "https://github.com/paritytech/substrate", branch = "master" } 75 | frame-support = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" } 76 | frame-system = { git = "https://github.com/paritytech/substrate", branch = "master" } 77 | 78 | # canyon-specific dependencies 79 | canyon-executor = { path = "../executor" } 80 | canyon-inspect = { path = "../inspect", optional = true } 81 | canyon-primitives = { path = "../primitives" } 82 | canyon-rpc = { path = "../rpc" } 83 | canyon-runtime = { path = "../runtime" } 84 | 85 | cc-datastore = { path = "../client/datastore" } 86 | cc-consensus-poa = { path = "../client/consensus/poa" } 87 | pallet-permastore = { path = "../pallets/permastore" } 88 | pallet-poa = { path = "../pallets/poa" } 89 | 90 | # CLI-specific dependencies 91 | sc-cli = { git = "https://github.com/paritytech/substrate", optional = true , branch = "master" } 92 | frame-benchmarking-cli = { git = "https://github.com/paritytech/substrate", optional = true , branch = "master" } 93 | try-runtime-cli = { git = "https://github.com/paritytech/substrate", optional = true , branch = "master" } 94 | 95 | [target.'cfg(target_arch="x86_64")'.dependencies] 96 | sc-cli = { git = "https://github.com/paritytech/substrate", branch = "master", optional = true, features = ["wasmtime"] } 97 | sc-service = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false, features = ["wasmtime"] } 98 | sp-trie = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false, features = ["memory-tracker"] } 99 | 100 | canyon-executor = { path = "../executor", features = ["wasmtime"] } 101 | 102 | [dev-dependencies] 103 | assert_cmd = "1.0" 104 | async-std = { version = "1.6.5", features = ["attributes"] } 105 | futures = "0.3.16" 106 | nix = "0.19" 107 | platforms = "1.1" 108 | regex = "1" 109 | serde_json = "1.0" 110 | soketto = "0.4.2" 111 | tempfile = "3.1.0" 112 | 113 | sc-consensus = { git = "https://github.com/paritytech/substrate", branch = "master" } 114 | sc-consensus-babe = { git = "https://github.com/paritytech/substrate", branch = "master" } 115 | sc-consensus-epochs = { git = "https://github.com/paritytech/substrate", branch = "master" } 116 | sc-keystore = { git = "https://github.com/paritytech/substrate", branch = "master" } 117 | sc-service-test = { git = "https://github.com/paritytech/substrate", branch = "master" } 118 | 119 | [build-dependencies] 120 | structopt = { version = "0.3.8", optional = true } 121 | 122 | sc-cli = { git = "https://github.com/paritytech/substrate", optional = true , branch = "master" } 123 | 124 | frame-benchmarking-cli = { git = "https://github.com/paritytech/substrate", optional = true , branch = "master" } 125 | substrate-build-script-utils = { git = "https://github.com/paritytech/substrate", optional = true , branch = "master" } 126 | substrate-frame-cli = { git = "https://github.com/paritytech/substrate", optional = true , branch = "master" } 127 | try-runtime-cli = { git = "https://github.com/paritytech/substrate", optional = true , branch = "master" } 128 | 129 | canyon-inspect = { path = "../inspect", optional = true } 130 | 131 | [features] 132 | default = ["cli"] 133 | cli = [ 134 | "canyon-executor/wasmi-errno", 135 | "canyon-inspect", 136 | "sc-cli", 137 | "frame-benchmarking-cli", 138 | "substrate-frame-cli", 139 | "sc-service/db", 140 | "structopt", 141 | "substrate-build-script-utils", 142 | "try-runtime-cli", 143 | ] 144 | runtime-benchmarks = [ 145 | "canyon-runtime/runtime-benchmarks", 146 | "frame-benchmarking-cli", 147 | ] 148 | # Enable features that allow the runtime to be tried and debugged. Name might be subject to change 149 | # in the near future. 150 | try-runtime = [ 151 | "canyon-runtime/try-runtime", 152 | "try-runtime-cli", 153 | ] 154 | -------------------------------------------------------------------------------- /client/rpc/src/permastore/tests.rs: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | // This file is part of Canyon. 3 | // 4 | // Copyright (c) 2021 Canyon Labs. 5 | // 6 | // Canyon is free software: you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published 8 | // by the Free Software Foundation, either version 3 of the License, 9 | // or (at your option) any later version. 10 | // 11 | // Canyon is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with Canyon. If not, see . 18 | 19 | use super::*; 20 | 21 | use std::sync::Arc; 22 | 23 | use assert_matches::assert_matches; 24 | use codec::Encode; 25 | use futures::{executor, StreamExt}; 26 | use jsonrpc_pubsub::{manager::SubscriptionManager, SubscriptionId}; 27 | use parking_lot::RwLock; 28 | 29 | use sc_rpc::author::Author; 30 | use sc_rpc_api::{author::hash::ExtrinsicOrHash, DenyUnsafe}; 31 | use sc_transaction_pool::{BasicPool, FullChainApi}; 32 | use sp_core::{blake2_256, hexdisplay::HexDisplay, H256}; 33 | use sp_keystore::testing::KeyStore; 34 | use substrate_test_runtime_client::{ 35 | self, 36 | runtime::{Block, Extrinsic, Transfer}, 37 | AccountKeyring, Backend, Client, DefaultTestClientBuilderExt, TestClientBuilderExt, 38 | }; 39 | 40 | fn uxt(sender: AccountKeyring, nonce: u64) -> Extrinsic { 41 | let tx = Transfer { 42 | amount: Default::default(), 43 | nonce, 44 | from: sender.into(), 45 | to: Default::default(), 46 | }; 47 | tx.into_signed_tx() 48 | } 49 | 50 | type FullTransactionPool = BasicPool, Block>, Block>; 51 | 52 | type TestAuthor = Author>; 53 | 54 | struct TestSetup { 55 | pub client: Arc>, 56 | pub keystore: Arc, 57 | pub pool: Arc, 58 | } 59 | 60 | impl Default for TestSetup { 61 | fn default() -> Self { 62 | let keystore = Arc::new(KeyStore::new()); 63 | let client_builder = substrate_test_runtime_client::TestClientBuilder::new(); 64 | let client = Arc::new(client_builder.set_keystore(keystore.clone()).build()); 65 | 66 | let spawner = sp_core::testing::TaskExecutor::new(); 67 | let pool = BasicPool::new_full( 68 | Default::default(), 69 | true.into(), 70 | None, 71 | spawner, 72 | client.clone(), 73 | ); 74 | 75 | TestSetup { 76 | client, 77 | keystore, 78 | pool, 79 | } 80 | } 81 | } 82 | 83 | impl TestSetup { 84 | fn author(&self) -> TestAuthor { 85 | let subscriptions = SubscriptionManager::new(Arc::new(sc_rpc::testing::TaskExecutor)); 86 | sc_rpc::author::Author::new( 87 | self.client.clone(), 88 | self.pool.clone(), 89 | subscriptions, 90 | self.keystore.clone(), 91 | DenyUnsafe::No, 92 | ) 93 | } 94 | 95 | fn permastore( 96 | &self, 97 | ) -> Permastore< 98 | cc_datastore::PermanentStorage>, 99 | FullTransactionPool, 100 | TestAuthor, 101 | Block, 102 | > { 103 | Permastore { 104 | storage: Arc::new(RwLock::new(cc_datastore::PermanentStorage::new_test( 105 | self.client.clone(), 106 | ))), 107 | pool: self.pool.clone(), 108 | author: self.author(), 109 | deny_unsafe: DenyUnsafe::No, 110 | phatom: PhantomData::, 111 | } 112 | } 113 | } 114 | 115 | #[test] 116 | fn submit_transaction_should_not_cause_error() { 117 | let p = TestSetup::default().permastore(); 118 | let xt = uxt(AccountKeyring::Alice, 1).encode(); 119 | let h: H256 = blake2_256(&xt).into(); 120 | 121 | let data = b"mocked data".to_vec(); 122 | assert_matches!( 123 | executor::block_on(PermastoreApi::submit_extrinsic(&p, xt.clone().into(), data.clone().into())), 124 | Ok(h2) if h == h2 125 | ); 126 | assert!( 127 | executor::block_on(PermastoreApi::submit_extrinsic(&p, xt.into(), data.into())).is_err() 128 | ); 129 | } 130 | 131 | #[test] 132 | fn submit_rich_transaction_should_not_cause_error() { 133 | let p = TestSetup::default().permastore(); 134 | let xt = uxt(AccountKeyring::Alice, 0).encode(); 135 | let h: H256 = blake2_256(&xt).into(); 136 | 137 | let data = b"mocked data".to_vec(); 138 | assert_matches!( 139 | executor::block_on(PermastoreApi::submit_extrinsic(&p, xt.clone().into(), data.clone().into())), 140 | Ok(h2) if h == h2 141 | ); 142 | assert!( 143 | executor::block_on(PermastoreApi::submit_extrinsic(&p, xt.into(), data.into())).is_err() 144 | ); 145 | } 146 | 147 | #[test] 148 | fn should_watch_extrinsic() { 149 | // given 150 | let setup = TestSetup::default(); 151 | let p = setup.author(); 152 | 153 | let (subscriber, id_rx, data) = jsonrpc_pubsub::typed::Subscriber::new_test("test"); 154 | 155 | // when 156 | p.watch_extrinsic( 157 | Default::default(), 158 | subscriber, 159 | uxt(AccountKeyring::Alice, 0).encode().into(), 160 | ); 161 | 162 | let id = executor::block_on(id_rx).unwrap().unwrap(); 163 | assert_matches!(id, SubscriptionId::String(_)); 164 | 165 | let id = match id { 166 | SubscriptionId::String(id) => id, 167 | _ => unreachable!(), 168 | }; 169 | 170 | // check notifications 171 | let replacement = { 172 | let tx = Transfer { 173 | amount: 5, 174 | nonce: 0, 175 | from: AccountKeyring::Alice.into(), 176 | to: Default::default(), 177 | }; 178 | tx.into_signed_tx() 179 | }; 180 | executor::block_on(AuthorApi::submit_extrinsic(&p, replacement.encode().into())).unwrap(); 181 | let (res, data) = executor::block_on(data.into_future()); 182 | 183 | let expected = Some(format!( 184 | r#"{{"jsonrpc":"2.0","method":"test","params":{{"result":"ready","subscription":"{}"}}}}"#, 185 | id, 186 | )); 187 | assert_eq!(res, expected); 188 | 189 | let h = blake2_256(&replacement.encode()); 190 | let expected = Some(format!( 191 | r#"{{"jsonrpc":"2.0","method":"test","params":{{"result":{{"usurped":"0x{}"}},"subscription":"{}"}}}}"#, 192 | HexDisplay::from(&h), 193 | id, 194 | )); 195 | 196 | let res = executor::block_on(data.into_future()).0; 197 | assert_eq!(res, expected); 198 | } 199 | 200 | #[test] 201 | fn should_return_watch_validation_error() { 202 | // given 203 | let setup = TestSetup::default(); 204 | let p = setup.author(); 205 | 206 | let (subscriber, id_rx, _data) = jsonrpc_pubsub::typed::Subscriber::new_test("test"); 207 | 208 | // when 209 | p.watch_extrinsic( 210 | Default::default(), 211 | subscriber, 212 | uxt(AccountKeyring::Alice, 179).encode().into(), 213 | ); 214 | 215 | // then 216 | let res = executor::block_on(id_rx).unwrap(); 217 | assert!( 218 | res.is_err(), 219 | "Expected the transaction to be rejected as invalid." 220 | ); 221 | } 222 | 223 | #[test] 224 | fn should_return_pending_extrinsics() { 225 | let p = TestSetup::default().permastore(); 226 | 227 | let ex = uxt(AccountKeyring::Alice, 0); 228 | let data = b"mocked data".to_vec(); 229 | executor::block_on(PermastoreApi::submit_extrinsic( 230 | &p, 231 | ex.encode().into(), 232 | data.into(), 233 | )) 234 | .unwrap(); 235 | assert_matches!( 236 | p.author.pending_extrinsics(), 237 | Ok(ref expected) if *expected == vec![Bytes(ex.encode())] 238 | ); 239 | } 240 | 241 | #[test] 242 | fn should_remove_extrinsics() { 243 | let setup = TestSetup::default(); 244 | let p = setup.permastore(); 245 | 246 | let data: Bytes = b"mocked data".to_vec().into(); 247 | 248 | let ex1 = uxt(AccountKeyring::Alice, 0); 249 | executor::block_on(p.submit_extrinsic(ex1.encode().into(), data.clone())).unwrap(); 250 | let ex2 = uxt(AccountKeyring::Alice, 1); 251 | executor::block_on(p.submit_extrinsic(ex2.encode().into(), data.clone())).unwrap(); 252 | let ex3 = uxt(AccountKeyring::Bob, 0); 253 | let hash3 = executor::block_on(p.submit_extrinsic(ex3.encode().into(), data)).unwrap(); 254 | assert_eq!(setup.pool.status().ready, 3); 255 | 256 | // now remove all 3 257 | let removed = p 258 | .remove_extrinsic(vec![ 259 | ExtrinsicOrHash::Hash(hash3), 260 | // Removing this one will also remove ex2 261 | ExtrinsicOrHash::Extrinsic(ex1.encode().into()), 262 | ]) 263 | .unwrap(); 264 | 265 | assert_eq!(removed.len(), 3); 266 | } 267 | -------------------------------------------------------------------------------- /rpc/src/lib.rs: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | // This file is part of Canyon. 3 | // 4 | // Copyright (c) 2021 Canyon Labs. 5 | // 6 | // Canyon is free software: you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published 8 | // by the Free Software Foundation, either version 3 of the License, 9 | // or (at your option) any later version. 10 | // 11 | // Canyon is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with Canyon. If not, see . 18 | 19 | //! A collection of canyon-specific RPC methods. 20 | //! 21 | //! Since `substrate` core functionality makes no assumptions 22 | //! about the modules used inside the runtime, so do 23 | //! RPC methods defined in `sc-rpc` crate. 24 | //! It means that `client/rpc` can't have any methods that 25 | //! need some strong assumptions about the particular runtime. 26 | //! 27 | //! The RPCs available in this crate however can make some assumptions 28 | //! about how the runtime is constructed and what FRAME pallets 29 | //! are part of it. Therefore all node-runtime-specific RPCs can 30 | //! be placed here or imported from corresponding FRAME RPC definitions. 31 | 32 | #![warn(missing_docs)] 33 | 34 | use std::sync::Arc; 35 | 36 | use sc_client_api::AuxStore; 37 | use sc_consensus_babe::{Config, Epoch}; 38 | use sc_consensus_babe_rpc::BabeRpcHandler; 39 | use sc_consensus_epochs::SharedEpochChanges; 40 | use sc_finality_grandpa::{ 41 | FinalityProofProvider, GrandpaJustificationStream, SharedAuthoritySet, SharedVoterState, 42 | }; 43 | use sc_finality_grandpa_rpc::GrandpaRpcHandler; 44 | use sc_rpc::SubscriptionTaskExecutor; 45 | pub use sc_rpc_api::DenyUnsafe; 46 | use sc_transaction_pool_api::TransactionPool; 47 | use sp_api::ProvideRuntimeApi; 48 | use sp_block_builder::BlockBuilder; 49 | use sp_blockchain::{Error as BlockChainError, HeaderBackend, HeaderMetadata}; 50 | use sp_consensus::SelectChain; 51 | use sp_consensus_babe::BabeApi; 52 | use sp_keystore::SyncCryptoStorePtr; 53 | 54 | use canyon_primitives::{AccountId, Balance, Block, BlockNumber, Hash, Index}; 55 | 56 | /// Light client extra dependencies. 57 | pub struct LightDeps { 58 | /// The client instance to use. 59 | pub client: Arc, 60 | /// Transaction pool instance. 61 | pub pool: Arc

, 62 | /// Remote access to the blockchain (async). 63 | pub remote_blockchain: Arc>, 64 | /// Fetcher instance. 65 | pub fetcher: Arc, 66 | } 67 | 68 | /// Extra dependencies for BABE. 69 | pub struct BabeDeps { 70 | /// BABE protocol config. 71 | pub babe_config: Config, 72 | /// BABE pending epoch changes. 73 | pub shared_epoch_changes: SharedEpochChanges, 74 | /// The keystore that manages the keys of the node. 75 | pub keystore: SyncCryptoStorePtr, 76 | } 77 | 78 | /// Extra dependencies for GRANDPA 79 | pub struct GrandpaDeps { 80 | /// Voting round info. 81 | pub shared_voter_state: SharedVoterState, 82 | /// Authority set info. 83 | pub shared_authority_set: SharedAuthoritySet, 84 | /// Receives notifications about justification events from Grandpa. 85 | pub justification_stream: GrandpaJustificationStream, 86 | /// Executor to drive the subscription manager in the Grandpa RPC handler. 87 | pub subscription_executor: SubscriptionTaskExecutor, 88 | /// Finality proof provider. 89 | pub finality_provider: Arc>, 90 | } 91 | 92 | /// Full client dependencies. 93 | pub struct FullDeps { 94 | /// The client instance to use. 95 | pub client: Arc, 96 | /// Transaction pool instance. 97 | pub pool: Arc

, 98 | /// The SelectChain Strategy 99 | pub select_chain: SC, 100 | /// A copy of the chain spec. 101 | pub chain_spec: Box, 102 | /// Whether to deny unsafe calls 103 | pub deny_unsafe: DenyUnsafe, 104 | /// BABE specific dependencies. 105 | pub babe: BabeDeps, 106 | /// GRANDPA specific dependencies. 107 | pub grandpa: GrandpaDeps, 108 | /// permanent storage 109 | pub perma_storage: S, 110 | } 111 | 112 | /// A IO handler that uses all Full RPC extensions. 113 | pub type IoHandler = jsonrpc_core::IoHandler; 114 | 115 | /// Instantiate all Full RPC extensions. 116 | pub fn create_full( 117 | deps: FullDeps, 118 | author: A, 119 | ) -> Result, Box> 120 | where 121 | C: ProvideRuntimeApi 122 | + HeaderBackend 123 | + AuxStore 124 | + HeaderMetadata 125 | + Sync 126 | + Send 127 | + 'static, 128 | C::Api: substrate_frame_rpc_system::AccountNonceApi, 129 | C::Api: pallet_transaction_payment_rpc::TransactionPaymentRuntimeApi, 130 | C::Api: BabeApi, 131 | C::Api: BlockBuilder, 132 | P: TransactionPool + 'static, 133 |

::Hash: serde::de::DeserializeOwned, 134 | SC: SelectChain + 'static, 135 | B: sc_client_api::Backend + Send + Sync + 'static, 136 | B::State: sc_client_api::backend::StateBackend>, 137 | S: cp_permastore::PermaStorage + 'static, 138 | A: sc_rpc_api::author::AuthorApi< 139 | sc_transaction_pool_api::TxHash

, 140 | ::Hash, 141 | Metadata = sc_rpc_api::Metadata, 142 | >, 143 | { 144 | use pallet_transaction_payment_rpc::{TransactionPayment, TransactionPaymentApi}; 145 | use substrate_frame_rpc_system::{FullSystem, SystemApi}; 146 | 147 | let mut io = jsonrpc_core::IoHandler::default(); 148 | let FullDeps { 149 | client, 150 | pool, 151 | select_chain, 152 | chain_spec, 153 | deny_unsafe, 154 | babe, 155 | grandpa, 156 | perma_storage, 157 | } = deps; 158 | 159 | let BabeDeps { 160 | keystore, 161 | babe_config, 162 | shared_epoch_changes, 163 | } = babe; 164 | let GrandpaDeps { 165 | shared_voter_state, 166 | shared_authority_set, 167 | justification_stream, 168 | subscription_executor, 169 | finality_provider, 170 | } = grandpa; 171 | 172 | io.extend_with(SystemApi::to_delegate(FullSystem::new( 173 | client.clone(), 174 | pool.clone(), 175 | deny_unsafe, 176 | ))); 177 | io.extend_with(TransactionPaymentApi::to_delegate(TransactionPayment::new( 178 | client.clone(), 179 | ))); 180 | io.extend_with(sc_consensus_babe_rpc::BabeApi::to_delegate( 181 | BabeRpcHandler::new( 182 | client.clone(), 183 | shared_epoch_changes.clone(), 184 | keystore, 185 | babe_config, 186 | select_chain, 187 | deny_unsafe, 188 | ), 189 | )); 190 | io.extend_with(sc_finality_grandpa_rpc::GrandpaApi::to_delegate( 191 | GrandpaRpcHandler::new( 192 | shared_authority_set.clone(), 193 | shared_voter_state, 194 | justification_stream, 195 | subscription_executor, 196 | finality_provider, 197 | ), 198 | )); 199 | 200 | io.extend_with(sc_sync_state_rpc::SyncStateRpcApi::to_delegate( 201 | sc_sync_state_rpc::SyncStateRpcHandler::new( 202 | chain_spec, 203 | client, 204 | shared_authority_set, 205 | shared_epoch_changes, 206 | deny_unsafe, 207 | )?, 208 | )); 209 | 210 | io.extend_with(cc_rpc_api::permastore::PermastoreApi::to_delegate( 211 | cc_rpc::permastore::Permastore::<_, _, _, Block>::new( 212 | perma_storage, 213 | pool, 214 | author, 215 | deny_unsafe, 216 | ), 217 | )); 218 | 219 | Ok(io) 220 | } 221 | 222 | /// Instantiate all Light RPC extensions. 223 | pub fn create_light(deps: LightDeps) -> jsonrpc_core::IoHandler 224 | where 225 | C: sp_blockchain::HeaderBackend, 226 | C: Send + Sync + 'static, 227 | F: sc_client_api::light::Fetcher + 'static, 228 | P: TransactionPool + 'static, 229 | M: jsonrpc_core::Metadata + Default, 230 | { 231 | use substrate_frame_rpc_system::{LightSystem, SystemApi}; 232 | 233 | let LightDeps { 234 | client, 235 | pool, 236 | remote_blockchain, 237 | fetcher, 238 | } = deps; 239 | let mut io = jsonrpc_core::IoHandler::default(); 240 | io.extend_with(SystemApi::::to_delegate( 241 | LightSystem::new(client, remote_blockchain, fetcher, pool), 242 | )); 243 | 244 | io 245 | } 246 | -------------------------------------------------------------------------------- /primitives/consensus/poa/src/lib.rs: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | // This file is part of Canyon. 3 | // 4 | // Copyright (c) 2021 Canyon Labs. 5 | // 6 | // Canyon is free software: you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published 8 | // by the Free Software Foundation, either version 3 of the License, 9 | // or (at your option) any later version. 10 | // 11 | // Canyon is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with Canyon. If not, see . 18 | 19 | #![cfg_attr(not(feature = "std"), no_std)] 20 | 21 | use codec::{Decode, Encode, MaxEncodedLen}; 22 | use scale_info::TypeInfo; 23 | 24 | use sp_inherents::InherentIdentifier; 25 | use sp_runtime::ConsensusEngineId; 26 | use sp_std::vec::Vec; 27 | 28 | /// The identifier for the inherent of poa pallet. 29 | pub const POA_INHERENT_IDENTIFIER: InherentIdentifier = *b"poaproof"; 30 | 31 | /// The engine id for the Proof of Access consensus. 32 | pub const POA_ENGINE_ID: ConsensusEngineId = *b"POA:"; 33 | 34 | /// This struct includes the raw bytes of recall chunk as well as the chunk proof stuffs. 35 | #[derive(Clone, Eq, PartialEq, Encode, Decode, TypeInfo)] 36 | #[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))] 37 | #[cfg_attr(feature = "std", serde(rename_all = "camelCase"))] 38 | pub struct ChunkProof { 39 | /// Trie nodes that compose the proof. 40 | /// 41 | /// Merkle path of chunks from `chunk` to the chunk root. 42 | pub proof: Vec>, 43 | 44 | /// Random data chunk that is proved to exist. 45 | pub chunk: Vec, 46 | 47 | /// Index of `chunk` in the total chunks of that transaction data. 48 | /// 49 | /// Required for verifing `proof`. 50 | pub chunk_index: u32, 51 | } 52 | 53 | impl sp_std::fmt::Debug for ChunkProof { 54 | #[cfg(feature = "std")] 55 | fn fmt(&self, f: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result { 56 | let chunk_in_hex = format!("0x{}", sp_core::hexdisplay::HexDisplay::from(&self.chunk)); 57 | f.debug_struct("ChunkProof") 58 | .field("chunk", &chunk_in_hex) 59 | .field("chunk_index", &self.chunk_index) 60 | .field("proof", &self.proof) 61 | .finish() 62 | } 63 | 64 | #[cfg(not(feature = "std"))] 65 | fn fmt(&self, f: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result { 66 | f.write_str("ChunkProof { }") 67 | } 68 | } 69 | 70 | /// An utility function to enocde chunk/extrinsic index as trie key. 71 | // The final proof can be more compact. 72 | // See https://github.com/paritytech/substrate/pull/8624#discussion_r616075183 73 | pub fn encode_index(input: u32) -> Vec { 74 | codec::Encode::encode(&codec::Compact(input)) 75 | } 76 | 77 | impl ChunkProof { 78 | /// Creates a new instance of [`ChunkProof`]. 79 | pub fn new(proof: Vec>, chunk: Vec, chunk_index: u32) -> Self { 80 | Self { 81 | proof, 82 | chunk, 83 | chunk_index, 84 | } 85 | } 86 | 87 | /// Returns the proof size in bytes. 88 | pub fn size(&self) -> usize { 89 | self.proof.iter().map(|p| p.len()).sum() 90 | } 91 | } 92 | 93 | /// This struct is used to prove the historical random data access of block author. 94 | #[derive(Debug, Clone, Eq, PartialEq, Encode, Decode, TypeInfo)] 95 | #[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))] 96 | #[cfg_attr(feature = "std", serde(rename_all = "camelCase"))] 97 | pub struct ProofOfAccess { 98 | /// Number of trials when a valid `ProofOfAccess` created. 99 | pub depth: u32, 100 | /// Merkle path/proof of the recall tx. 101 | pub tx_path: Vec>, 102 | /// Proof of the recall chunk. 103 | pub chunk_proof: ChunkProof, 104 | } 105 | 106 | /// Errors that can occur while checking the validity of [`ProofOfAccess`]. 107 | #[derive(Clone, PartialEq, Eq, Encode, Decode, TypeInfo)] 108 | #[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))] 109 | #[cfg_attr(feature = "std", derive(Debug))] 110 | pub enum PoaValidityError { 111 | /// Depth can not be zero. 112 | TooSmallDepth, 113 | /// Depth excceeds the maximum size specified in the config. 114 | TooLargeDepth(u32, u32), 115 | /// Tx path exceeds the maximum size specified in the config. 116 | TooLargeTxPath(u32, u32), 117 | /// Chunk path exceeds the maximum size specified in the config. 118 | TooLargeChunkPath(u32, u32), 119 | } 120 | 121 | #[cfg(not(feature = "std"))] 122 | impl sp_std::fmt::Debug for PoaValidityError { 123 | fn fmt(&self, f: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result { 124 | match self { 125 | Self::TooSmallDepth => f.write_str("PoaValidityError::TooSmallDepth"), 126 | Self::TooLargeDepth(_, _) => f.write_str("PoaValidityError::TooLargeDepth"), 127 | Self::TooLargeTxPath(_, _) => f.write_str("PoaValidityError::TooLargeTxPath"), 128 | Self::TooLargeChunkPath(_, _) => f.write_str("PoaValidityError::TooLargeChunkPath"), 129 | } 130 | } 131 | } 132 | 133 | impl ProofOfAccess { 134 | /// Creates a new instance of [`ProofOfAccess`]. 135 | pub fn new(depth: u32, tx_path: Vec>, chunk_proof: ChunkProof) -> Self { 136 | Self { 137 | depth, 138 | tx_path, 139 | chunk_proof, 140 | } 141 | } 142 | 143 | /// Returns the size of tx proof. 144 | pub fn tx_path_len(&self) -> usize { 145 | self.tx_path.iter().map(|x| x.len()).sum() 146 | } 147 | 148 | /// Returns the size of chunk proof. 149 | pub fn chunk_path_len(&self) -> usize { 150 | self.chunk_proof.size() 151 | } 152 | 153 | /// Returns true if the proof is valid given `poa_config`. 154 | pub fn check_validity(&self, poa_config: &PoaConfiguration) -> Result<(), PoaValidityError> { 155 | let PoaConfiguration { 156 | max_depth, 157 | max_tx_path, 158 | max_chunk_path, 159 | } = poa_config; 160 | 161 | if self.depth == 0 { 162 | return Err(PoaValidityError::TooSmallDepth); 163 | } 164 | 165 | if self.depth > *max_depth { 166 | return Err(PoaValidityError::TooLargeChunkPath(self.depth, *max_depth)); 167 | } 168 | 169 | let tx_path_len = self.tx_path_len(); 170 | if tx_path_len > *max_tx_path as usize { 171 | return Err(PoaValidityError::TooLargeTxPath( 172 | tx_path_len as u32, 173 | *max_tx_path, 174 | )); 175 | } 176 | 177 | let chunk_path_len = self.chunk_path_len(); 178 | if chunk_path_len > *max_chunk_path as usize { 179 | return Err(PoaValidityError::TooLargeChunkPath( 180 | chunk_path_len as u32, 181 | *max_chunk_path, 182 | )); 183 | } 184 | 185 | Ok(()) 186 | } 187 | } 188 | 189 | /// This struct represents the outcome of creating the inherent data of [`ProofOfAccess`]. 190 | #[derive(Debug, Clone, Eq, PartialEq, Encode, Decode, TypeInfo)] 191 | #[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))] 192 | #[cfg_attr(feature = "std", serde(rename_all = "camelCase"))] 193 | pub enum PoaOutcome { 194 | /// Not required for this block due to the entire weave is empty. 195 | Skipped, 196 | /// Failed to create a valid [`ProofOfAccess`] due to the maximum depth limit has been reached. 197 | MaxDepthReached(u32), 198 | /// Generate a [`ProofOfAccess`] successfully. 199 | /// 200 | /// Each block contains a justification of poa as long as the weave 201 | /// size is not zero and will be verified on block import. 202 | Justification(ProofOfAccess), 203 | } 204 | 205 | impl PoaOutcome { 206 | /// Returns true if the poa inherent must be included in the block. 207 | pub fn require_inherent(&self) -> bool { 208 | matches!(self, Self::Justification(..)) 209 | } 210 | } 211 | 212 | /// Maximum depth is 1000. 213 | const MAX_DEPTH: u32 = 1_000; 214 | /// Maximum byte size of tx path is 256 KiB. 215 | const MAX_TX_PATH: u32 = 256 * 1024; 216 | /// Maximu byte size of chunk path 256 KiB. 217 | const MAX_CHUNK_PATH: u32 = 256 * 1024; 218 | 219 | /// Configuration of the PoA consensus engine. 220 | #[derive(Clone, Eq, PartialEq, Encode, Decode, MaxEncodedLen, TypeInfo)] 221 | pub struct PoaConfiguration { 222 | /// The maximum depth of attempting to generate a valid [`ProofOfAccess`]. 223 | pub max_depth: u32, 224 | /// Maximum byte size of tx merkle path. 225 | pub max_tx_path: u32, 226 | /// Maximum byte size of chunk merkle path. 227 | pub max_chunk_path: u32, 228 | } 229 | 230 | impl Default for PoaConfiguration { 231 | fn default() -> Self { 232 | Self { 233 | max_depth: MAX_DEPTH, 234 | max_tx_path: MAX_TX_PATH, 235 | max_chunk_path: MAX_CHUNK_PATH, 236 | } 237 | } 238 | } 239 | 240 | impl PoaConfiguration { 241 | /// Returns true if all the sanity checks are passed. 242 | pub fn check_sanity(&self) -> bool { 243 | // TODO: 244 | // 1. upper limit check? 245 | // 2. more accurate check for the proof since the size of merkle proof has a lower bound? 246 | self.max_depth > 0 && self.max_tx_path > 0 && self.max_chunk_path > 0 247 | } 248 | } 249 | 250 | impl sp_std::fmt::Debug for PoaConfiguration { 251 | #[cfg(feature = "std")] 252 | fn fmt(&self, f: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result { 253 | f.debug_struct("PoaConfiguration") 254 | .field("max_depth", &self.max_depth) 255 | .field("max_tx_path", &self.max_tx_path) 256 | .field("max_chunk_path", &self.max_chunk_path) 257 | .finish() 258 | } 259 | 260 | #[cfg(not(feature = "std"))] 261 | fn fmt(&self, f: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result { 262 | f.write_str("PoaConfiguration { }") 263 | } 264 | } 265 | -------------------------------------------------------------------------------- /inspect/src/lib.rs: -------------------------------------------------------------------------------- 1 | // This file is part of Canyon. 2 | 3 | // Copyright (C) 2021 Canyon Network. 4 | // License: GPL-3.0 5 | 6 | //! A CLI extension for substrate node, adding sub-command to pretty print debug info 7 | //! about blocks and extrinsics. 8 | //! 9 | //! The blocks and extrinsics can either be retrieved from the database (on-chain), 10 | //! or a raw SCALE-encoding can be provided. 11 | 12 | #![warn(missing_docs)] 13 | 14 | pub mod cli; 15 | pub mod command; 16 | 17 | use std::{fmt, fmt::Debug, marker::PhantomData, str::FromStr}; 18 | 19 | use codec::{Decode, Encode}; 20 | 21 | use sc_client_api::BlockBackend; 22 | use sp_blockchain::HeaderBackend; 23 | use sp_core::hexdisplay::HexDisplay; 24 | use sp_runtime::{ 25 | generic::BlockId, 26 | traits::{Block, Hash, HashFor, NumberFor}, 27 | }; 28 | 29 | /// A helper type for a generic block input. 30 | pub type BlockAddressFor = 31 | BlockAddress< as Hash>::Output, NumberFor>; 32 | 33 | /// A Pretty formatter implementation. 34 | pub trait PrettyPrinter { 35 | /// Nicely format block. 36 | fn fmt_block(&self, fmt: &mut fmt::Formatter, block: &TBlock) -> fmt::Result; 37 | /// Nicely format extrinsic. 38 | fn fmt_extrinsic(&self, fmt: &mut fmt::Formatter, extrinsic: &TBlock::Extrinsic) 39 | -> fmt::Result; 40 | } 41 | 42 | /// Default dummy debug printer. 43 | #[derive(Default)] 44 | pub struct DebugPrinter; 45 | impl PrettyPrinter for DebugPrinter { 46 | fn fmt_block(&self, fmt: &mut fmt::Formatter, block: &TBlock) -> fmt::Result { 47 | writeln!(fmt, "Header:")?; 48 | writeln!(fmt, "{:?}", block.header())?; 49 | writeln!(fmt, "Block bytes: {:?}", HexDisplay::from(&block.encode()))?; 50 | writeln!(fmt, "Extrinsics ({})", block.extrinsics().len())?; 51 | for (idx, ex) in block.extrinsics().iter().enumerate() { 52 | writeln!(fmt, "- {}:", idx)?; 53 | >::fmt_extrinsic(self, fmt, ex)?; 54 | } 55 | Ok(()) 56 | } 57 | 58 | fn fmt_extrinsic( 59 | &self, 60 | fmt: &mut fmt::Formatter, 61 | extrinsic: &TBlock::Extrinsic, 62 | ) -> fmt::Result { 63 | writeln!(fmt, " {:#?}", extrinsic)?; 64 | writeln!(fmt, " Bytes: {:?}", HexDisplay::from(&extrinsic.encode()))?; 65 | Ok(()) 66 | } 67 | } 68 | 69 | /// Aggregated error for `Inspector` operations. 70 | #[derive(Debug, derive_more::From, derive_more::Display)] 71 | pub enum Error { 72 | /// Could not decode Block or Extrinsic. 73 | Codec(codec::Error), 74 | /// Error accessing blockchain DB. 75 | Blockchain(sp_blockchain::Error), 76 | /// Given block has not been found. 77 | NotFound(String), 78 | } 79 | 80 | impl std::error::Error for Error { 81 | fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { 82 | match *self { 83 | Self::Codec(ref e) => Some(e), 84 | Self::Blockchain(ref e) => Some(e), 85 | Self::NotFound(_) => None, 86 | } 87 | } 88 | } 89 | 90 | /// A helper trait to access block headers and bodies. 91 | pub trait ChainAccess: HeaderBackend + BlockBackend {} 92 | 93 | impl ChainAccess for T 94 | where 95 | TBlock: Block, 96 | T: sp_blockchain::HeaderBackend + sc_client_api::BlockBackend, 97 | { 98 | } 99 | 100 | /// Blockchain inspector. 101 | pub struct Inspector = DebugPrinter> { 102 | printer: TPrinter, 103 | chain: Box>, 104 | _block: PhantomData, 105 | } 106 | 107 | impl> Inspector { 108 | /// Create new instance of the inspector with default printer. 109 | pub fn new(chain: impl ChainAccess + 'static) -> Self 110 | where 111 | TPrinter: Default, 112 | { 113 | Self::with_printer(chain, Default::default()) 114 | } 115 | 116 | /// Customize pretty-printing of the data. 117 | pub fn with_printer(chain: impl ChainAccess + 'static, printer: TPrinter) -> Self { 118 | Inspector { 119 | chain: Box::new(chain) as _, 120 | printer, 121 | _block: Default::default(), 122 | } 123 | } 124 | 125 | /// Get a pretty-printed block. 126 | pub fn block(&self, input: BlockAddressFor) -> Result { 127 | struct BlockPrinter<'a, A, B>(A, &'a B); 128 | impl<'a, A: Block, B: PrettyPrinter> fmt::Display for BlockPrinter<'a, A, B> { 129 | fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { 130 | self.1.fmt_block(fmt, &self.0) 131 | } 132 | } 133 | 134 | let block = self.get_block(input)?; 135 | Ok(format!("{}", BlockPrinter(block, &self.printer))) 136 | } 137 | 138 | fn get_block(&self, input: BlockAddressFor) -> Result { 139 | Ok(match input { 140 | BlockAddress::Bytes(bytes) => TBlock::decode(&mut &*bytes)?, 141 | BlockAddress::Number(number) => { 142 | let id = BlockId::number(number); 143 | let not_found = format!("Could not find block {:?}", id); 144 | let body = self 145 | .chain 146 | .block_body(&id)? 147 | .ok_or_else(|| Error::NotFound(not_found.clone()))?; 148 | let header = self 149 | .chain 150 | .header(id)? 151 | .ok_or_else(|| Error::NotFound(not_found.clone()))?; 152 | TBlock::new(header, body) 153 | } 154 | BlockAddress::Hash(hash) => { 155 | let id = BlockId::hash(hash); 156 | let not_found = format!("Could not find block {:?}", id); 157 | let body = self 158 | .chain 159 | .block_body(&id)? 160 | .ok_or_else(|| Error::NotFound(not_found.clone()))?; 161 | let header = self 162 | .chain 163 | .header(id)? 164 | .ok_or_else(|| Error::NotFound(not_found.clone()))?; 165 | TBlock::new(header, body) 166 | } 167 | }) 168 | } 169 | 170 | /// Get a pretty-printed extrinsic. 171 | pub fn extrinsic( 172 | &self, 173 | input: ExtrinsicAddress< as Hash>::Output, NumberFor>, 174 | ) -> Result { 175 | struct ExtrinsicPrinter<'a, A: Block, B>(A::Extrinsic, &'a B); 176 | impl<'a, A: Block, B: PrettyPrinter> fmt::Display for ExtrinsicPrinter<'a, A, B> { 177 | fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { 178 | self.1.fmt_extrinsic(fmt, &self.0) 179 | } 180 | } 181 | 182 | let ext = match input { 183 | ExtrinsicAddress::Block(block, index) => { 184 | let block = self.get_block(block)?; 185 | block.extrinsics().get(index).cloned().ok_or_else(|| { 186 | Error::NotFound(format!( 187 | "Could not find extrinsic {} in block {:?}", 188 | index, block 189 | )) 190 | })? 191 | } 192 | ExtrinsicAddress::Bytes(bytes) => TBlock::Extrinsic::decode(&mut &*bytes)?, 193 | }; 194 | 195 | Ok(format!("{}", ExtrinsicPrinter(ext, &self.printer))) 196 | } 197 | } 198 | 199 | /// A block to retrieve. 200 | #[derive(Debug, Clone, PartialEq)] 201 | pub enum BlockAddress { 202 | /// Get block by hash. 203 | Hash(Hash), 204 | /// Get block by number. 205 | Number(Number), 206 | /// Raw SCALE-encoded bytes. 207 | Bytes(Vec), 208 | } 209 | 210 | impl FromStr for BlockAddress { 211 | type Err = String; 212 | 213 | fn from_str(s: &str) -> Result { 214 | // try to parse hash first 215 | if let Ok(hash) = s.parse() { 216 | return Ok(Self::Hash(hash)); 217 | } 218 | 219 | // then number 220 | if let Ok(number) = s.parse() { 221 | return Ok(Self::Number(number)); 222 | } 223 | 224 | // then assume it's bytes (hex-encoded) 225 | sp_core::bytes::from_hex(s).map(Self::Bytes).map_err(|e| { 226 | format!( 227 | "Given string does not look like hash or number. It could not be parsed as bytes either: {}", 228 | e 229 | ) 230 | }) 231 | } 232 | } 233 | 234 | /// An extrinsic address to decode and print out. 235 | #[derive(Debug, Clone, PartialEq)] 236 | pub enum ExtrinsicAddress { 237 | /// Extrinsic as part of existing block. 238 | Block(BlockAddress, usize), 239 | /// Raw SCALE-encoded extrinsic bytes. 240 | Bytes(Vec), 241 | } 242 | 243 | impl FromStr for ExtrinsicAddress { 244 | type Err = String; 245 | 246 | fn from_str(s: &str) -> Result { 247 | // first try raw bytes 248 | if let Ok(bytes) = sp_core::bytes::from_hex(s).map(Self::Bytes) { 249 | return Ok(bytes); 250 | } 251 | 252 | // split by a bunch of different characters 253 | let mut it = s.split(|c| c == '.' || c == ':' || c == ' '); 254 | let block = it 255 | .next() 256 | .expect("First element of split iterator is never empty; qed") 257 | .parse()?; 258 | 259 | let index = it 260 | .next() 261 | .ok_or("Extrinsic index missing: example \"5:0\"")? 262 | .parse() 263 | .map_err(|e| format!("Invalid index format: {}", e))?; 264 | 265 | Ok(Self::Block(block, index)) 266 | } 267 | } 268 | 269 | #[cfg(test)] 270 | mod tests { 271 | use super::*; 272 | use sp_core::hash::H160 as Hash; 273 | 274 | #[test] 275 | fn should_parse_block_strings() { 276 | type BlockAddress = super::BlockAddress; 277 | 278 | let b0 = BlockAddress::from_str("3BfC20f0B9aFcAcE800D73D2191166FF16540258"); 279 | let b1 = BlockAddress::from_str("1234"); 280 | let b2 = BlockAddress::from_str("0"); 281 | let b3 = BlockAddress::from_str("0x0012345f"); 282 | 283 | assert_eq!( 284 | b0, 285 | Ok(BlockAddress::Hash( 286 | "3BfC20f0B9aFcAcE800D73D2191166FF16540258".parse().unwrap() 287 | )) 288 | ); 289 | assert_eq!(b1, Ok(BlockAddress::Number(1234))); 290 | assert_eq!(b2, Ok(BlockAddress::Number(0))); 291 | assert_eq!(b3, Ok(BlockAddress::Bytes(vec![0, 0x12, 0x34, 0x5f]))); 292 | } 293 | 294 | #[test] 295 | fn should_parse_extrinsic_address() { 296 | type BlockAddress = super::BlockAddress; 297 | type ExtrinsicAddress = super::ExtrinsicAddress; 298 | 299 | let e0 = ExtrinsicAddress::from_str("1234"); 300 | let b0 = ExtrinsicAddress::from_str("3BfC20f0B9aFcAcE800D73D2191166FF16540258:5"); 301 | let b1 = ExtrinsicAddress::from_str("1234:0"); 302 | let b2 = ExtrinsicAddress::from_str("0 0"); 303 | let b3 = ExtrinsicAddress::from_str("0x0012345f"); 304 | 305 | assert_eq!(e0, Err("Extrinsic index missing: example \"5:0\"".into())); 306 | assert_eq!( 307 | b0, 308 | Ok(ExtrinsicAddress::Block( 309 | BlockAddress::Hash("3BfC20f0B9aFcAcE800D73D2191166FF16540258".parse().unwrap()), 310 | 5 311 | )) 312 | ); 313 | assert_eq!( 314 | b1, 315 | Ok(ExtrinsicAddress::Block(BlockAddress::Number(1234), 0)) 316 | ); 317 | assert_eq!(b2, Ok(ExtrinsicAddress::Block(BlockAddress::Number(0), 0))); 318 | assert_eq!(b3, Ok(ExtrinsicAddress::Bytes(vec![0, 0x12, 0x34, 0x5f]))); 319 | } 320 | } 321 | -------------------------------------------------------------------------------- /runtime/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "canyon-runtime" 3 | version = "0.1.0" 4 | authors = ["Canyon Labs "] 5 | edition = "2018" 6 | build = "build.rs" 7 | 8 | [package.metadata.docs.rs] 9 | targets = ["x86_64-unknown-linux-gnu"] 10 | 11 | [dependencies] 12 | codec = { package = "parity-scale-codec", version = "2.3", default-features = false, features = ["derive", "max-encoded-len"] } 13 | hex-literal = { version = "0.3.1", optional = true } 14 | log = { version = "0.4.14", default-features = false } 15 | scale-info = { version = "1.0", default-features = false, features = ["derive"] } 16 | serde = { version = "1.0.102", optional = true } 17 | static_assertions = "1.1.0" 18 | 19 | # primitives 20 | sp-api = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" } 21 | sp-authority-discovery = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" } 22 | sp-block-builder = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" } 23 | sp-consensus-babe = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" } 24 | sp-core = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" } 25 | sp-inherents = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" } 26 | sp-io = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } 27 | sp-keyring = { git = "https://github.com/paritytech/substrate", optional = true , branch = "master" } 28 | sp-offchain = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" } 29 | sp-npos-elections = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" } 30 | sp-runtime = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" } 31 | sp-session = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" } 32 | sp-staking = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" } 33 | sp-std = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" } 34 | sp-transaction-pool = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" } 35 | sp-version = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" } 36 | 37 | # frame dependencies 38 | frame-benchmarking = { git = "https://github.com/paritytech/substrate", default-features = false, optional = true , branch = "master" } 39 | frame-election-provider-support = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" } 40 | frame-executive = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" } 41 | frame-support = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" } 42 | frame-system = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" } 43 | frame-system-benchmarking = { git = "https://github.com/paritytech/substrate", default-features = false, optional = true , branch = "master" } 44 | frame-system-rpc-runtime-api = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" } 45 | frame-try-runtime = { git = "https://github.com/paritytech/substrate", default-features = false, optional = true , branch = "master" } 46 | pallet-assets = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" } 47 | pallet-authority-discovery = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" } 48 | pallet-authorship = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" } 49 | pallet-babe = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" } 50 | pallet-bags-list = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" } 51 | pallet-balances = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" } 52 | pallet-bounties = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" } 53 | pallet-collective = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" } 54 | pallet-democracy = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" } 55 | pallet-election-provider-multi-phase = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" } 56 | pallet-elections-phragmen = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" } 57 | pallet-gilt = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" } 58 | pallet-grandpa = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" } 59 | pallet-im-online = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" } 60 | pallet-indices = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" } 61 | pallet-identity = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" } 62 | pallet-lottery = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" } 63 | pallet-membership = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" } 64 | pallet-multisig = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" } 65 | pallet-offences = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" } 66 | pallet-offences-benchmarking = { git = "https://github.com/paritytech/substrate", default-features = false, optional = true , branch = "master" } 67 | pallet-proxy = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" } 68 | pallet-randomness-collective-flip = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" } 69 | pallet-session = { git = "https://github.com/paritytech/substrate", default-features = false, features = ["historical"] , branch = "master" } 70 | pallet-session-benchmarking = { git = "https://github.com/paritytech/substrate", default-features = false, optional = true , branch = "master" } 71 | pallet-staking = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" } 72 | pallet-staking-reward-curve = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" } 73 | pallet-scheduler = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" } 74 | pallet-sudo = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" } 75 | pallet-timestamp = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" } 76 | pallet-tips = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" } 77 | pallet-treasury = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" } 78 | pallet-utility = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" } 79 | pallet-transaction-payment = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" } 80 | pallet-transaction-payment-rpc-runtime-api = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" } 81 | pallet-vesting = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" } 82 | 83 | canyon-primitives = { path = "../primitives", default-features = false } 84 | cp-permastore = { path = "../primitives/permastore", default-features = false } 85 | cp-poa = { path = "../primitives/poa", default-features = false } 86 | 87 | pallet-permastore = { path = "../pallets/permastore", default-features = false } 88 | pallet-poa = { path = "../pallets/poa", default-features = false } 89 | 90 | [build-dependencies] 91 | substrate-wasm-builder = { git = "https://github.com/paritytech/substrate", branch = "master" } 92 | 93 | [features] 94 | default = ["std"] 95 | with-tracing = [ "frame-executive/with-tracing" ] 96 | std = [ 97 | "codec/std", 98 | "log/std", 99 | "scale-info/std", 100 | "serde", 101 | "sp-api/std", 102 | "sp-authority-discovery/std", 103 | "sp-block-builder/std", 104 | "sp-consensus-babe/std", 105 | "sp-core/std", 106 | "sp-inherents/std", 107 | "sp-io/std", 108 | "sp-keyring", 109 | "sp-offchain/std", 110 | "sp-runtime/std", 111 | "sp-session/std", 112 | "sp-staking/std", 113 | "sp-std/std", 114 | "sp-transaction-pool/std", 115 | "sp-version/std", 116 | "pallet-assets/std", 117 | "pallet-authority-discovery/std", 118 | "pallet-authorship/std", 119 | "pallet-babe/std", 120 | "pallet-bags-list/std", 121 | "pallet-balances/std", 122 | "pallet-bounties/std", 123 | "pallet-collective/std", 124 | "pallet-democracy/std", 125 | "pallet-elections-phragmen/std", 126 | "pallet-gilt/std", 127 | "pallet-grandpa/std", 128 | "pallet-im-online/std", 129 | "pallet-indices/std", 130 | "pallet-lottery/std", 131 | "pallet-membership/std", 132 | "pallet-multisig/std", 133 | "pallet-identity/std", 134 | "pallet-scheduler/std", 135 | "pallet-offences/std", 136 | "pallet-proxy/std", 137 | "pallet-staking/std", 138 | "pallet-randomness-collective-flip/std", 139 | "pallet-session/std", 140 | "pallet-sudo/std", 141 | "pallet-election-provider-multi-phase/std", 142 | "pallet-timestamp/std", 143 | "pallet-tips/std", 144 | "pallet-transaction-payment-rpc-runtime-api/std", 145 | "pallet-transaction-payment/std", 146 | "pallet-treasury/std", 147 | "pallet-utility/std", 148 | "pallet-vesting/std", 149 | "frame-benchmarking/std", 150 | "frame-election-provider-support/std", 151 | "frame-executive/std", 152 | "frame-support/std", 153 | "frame-system-rpc-runtime-api/std", 154 | "frame-system/std", 155 | "frame-try-runtime/std", 156 | 157 | "canyon-primitives/std", 158 | "cp-permastore/std", 159 | "cp-poa/std", 160 | "pallet-permastore/std", 161 | "pallet-poa/std", 162 | ] 163 | runtime-benchmarks = [ 164 | "hex-literal", 165 | "frame-benchmarking", 166 | "frame-support/runtime-benchmarks", 167 | "frame-system/runtime-benchmarks", 168 | "frame-election-provider-support/runtime-benchmarks", 169 | "pallet-election-provider-multi-phase/runtime-benchmarks", 170 | "sp-runtime/runtime-benchmarks", 171 | "pallet-assets/runtime-benchmarks", 172 | "pallet-babe/runtime-benchmarks", 173 | "pallet-bags-list/runtime-benchmarks", 174 | "pallet-balances/runtime-benchmarks", 175 | "pallet-bounties/runtime-benchmarks", 176 | "pallet-collective/runtime-benchmarks", 177 | "pallet-democracy/runtime-benchmarks", 178 | "pallet-elections-phragmen/runtime-benchmarks", 179 | "pallet-gilt/runtime-benchmarks", 180 | "pallet-grandpa/runtime-benchmarks", 181 | "pallet-identity/runtime-benchmarks", 182 | "pallet-im-online/runtime-benchmarks", 183 | "pallet-indices/runtime-benchmarks", 184 | "pallet-lottery/runtime-benchmarks", 185 | "pallet-multisig/runtime-benchmarks", 186 | "pallet-proxy/runtime-benchmarks", 187 | "pallet-scheduler/runtime-benchmarks", 188 | "pallet-staking/runtime-benchmarks", 189 | "pallet-timestamp/runtime-benchmarks", 190 | "pallet-tips/runtime-benchmarks", 191 | "pallet-treasury/runtime-benchmarks", 192 | "pallet-utility/runtime-benchmarks", 193 | "pallet-vesting/runtime-benchmarks", 194 | "pallet-offences-benchmarking", 195 | "pallet-session-benchmarking", 196 | "frame-system-benchmarking", 197 | "pallet-permastore/runtime-benchmarks", 198 | "pallet-poa/runtime-benchmarks", 199 | ] 200 | try-runtime = [ 201 | "frame-executive/try-runtime", 202 | "frame-try-runtime", 203 | "frame-system/try-runtime", 204 | "pallet-assets/try-runtime", 205 | "pallet-authority-discovery/try-runtime", 206 | "pallet-authorship/try-runtime", 207 | "pallet-babe/try-runtime", 208 | "pallet-balances/try-runtime", 209 | "pallet-bounties/try-runtime", 210 | "pallet-collective/try-runtime", 211 | "pallet-democracy/try-runtime", 212 | "pallet-elections-phragmen/try-runtime", 213 | "pallet-grandpa/try-runtime", 214 | "pallet-im-online/try-runtime", 215 | "pallet-indices/try-runtime", 216 | "pallet-lottery/try-runtime", 217 | "pallet-membership/try-runtime", 218 | "pallet-multisig/try-runtime", 219 | "pallet-identity/try-runtime", 220 | "pallet-scheduler/try-runtime", 221 | "pallet-offences/try-runtime", 222 | "pallet-proxy/try-runtime", 223 | "pallet-randomness-collective-flip/try-runtime", 224 | "pallet-session/try-runtime", 225 | "pallet-staking/try-runtime", 226 | "pallet-sudo/try-runtime", 227 | "pallet-election-provider-multi-phase/try-runtime", 228 | "pallet-timestamp/try-runtime", 229 | "pallet-tips/try-runtime", 230 | "pallet-transaction-payment/try-runtime", 231 | "pallet-treasury/try-runtime", 232 | "pallet-utility/try-runtime", 233 | "pallet-vesting/try-runtime", 234 | "pallet-gilt/try-runtime", 235 | "pallet-permastore/try-runtime", 236 | "pallet-poa/try-runtime", 237 | ] 238 | -------------------------------------------------------------------------------- /pallets/poa/src/lib.rs: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | // This file is part of Canyon. 3 | // 4 | // Copyright (c) 2021 Canyon Labs. 5 | // 6 | // Canyon is free software: you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published 8 | // by the Free Software Foundation, either version 3 of the License, 9 | // or (at your option) any later version. 10 | // 11 | // Canyon is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with Canyon. If not, see . 18 | 19 | //! # Poa Pallet 20 | //! 21 | //! The Poa pallet provides the feature of recording the validators' 22 | //! historical depth info from PoA consensus engine on chain, which 23 | //! can be used to estimate the actual storage capacity of a validator. 24 | //! 25 | //! we can say a validator tends to have stored 100% of the network 26 | //! data locally with a great chance if it had produced N blocks with 27 | //! a total depth of N. The estimated result becomes increasingly 28 | //! accurate and reliable with more and more blocks being authored 29 | //! by that validator. 30 | //! 31 | //! ## Interface 32 | //! 33 | //! ### Inherent Extrinsics 34 | //! 35 | //! The Poa pallet creates the inherent extrinsic [`Call::deposit`] 36 | //! when the inherent data contains a valid [`POA_INHERENT_IDENTIFIER`], 37 | //! in which a new digest item will probably be deposited. 38 | 39 | // Ensure we're `no_std` when compiling for Wasm. 40 | #![cfg_attr(not(feature = "std"), no_std)] 41 | #![deny(rustdoc::broken_intra_doc_links)] 42 | 43 | use codec::{Decode, Encode, MaxEncodedLen}; 44 | use scale_info::TypeInfo; 45 | 46 | use sp_runtime::{ 47 | generic::DigestItem, 48 | traits::{AtLeast32BitUnsigned, SaturatedConversion}, 49 | Permill, 50 | }; 51 | use sp_std::prelude::*; 52 | 53 | use frame_support::{ 54 | inherent::{InherentData, InherentIdentifier, MakeFatalError, ProvideInherent}, 55 | weights::DispatchClass, 56 | RuntimeDebug, 57 | }; 58 | 59 | use canyon_primitives::Depth; 60 | use cp_consensus_poa::{PoaConfiguration, PoaOutcome, POA_ENGINE_ID, POA_INHERENT_IDENTIFIER}; 61 | 62 | #[cfg(any(feature = "runtime-benchmarks", test))] 63 | mod benchmarking; 64 | #[cfg(all(feature = "std", test))] 65 | mod mock; 66 | #[cfg(all(feature = "std", test))] 67 | mod tests; 68 | pub mod weights; 69 | 70 | pub use self::weights::WeightInfo; 71 | // Re-export pallet items so that they can be accessed from the crate namespace. 72 | pub use pallet::*; 73 | 74 | /// Historical info about the average value of depth. 75 | /// 76 | /// This struct is used for calculating the historical average depth 77 | /// of a validator, which implies the storage capacity per validator. 78 | #[derive(RuntimeDebug, Clone, Eq, PartialEq, Encode, Decode, MaxEncodedLen, TypeInfo)] 79 | pub struct DepthInfo { 80 | /// Number of blocks authored by a validator since the weave is non-empty. 81 | /// 82 | /// The `blocks` here is not equal to the number of total blocks 83 | /// authored by a validator from the genesis block because the poa 84 | /// contruction is skipped when the weave is empty, the blocks 85 | /// authored in that period are not counted. 86 | pub blocks: BlockNumber, 87 | /// Sum of all depths so far. 88 | pub total_depth: Depth, 89 | } 90 | 91 | impl DepthInfo { 92 | /// Adds a new depth to the historical depth info. 93 | /// 94 | /// # NOTE 95 | /// 96 | /// The smallest depth is 1, which has been ensured when creating 97 | /// the inherent, it means the block author located the recall 98 | /// block at the first time. 99 | pub fn add_depth(&mut self, depth: Depth) { 100 | self.total_depth += depth; 101 | self.blocks += 1u32.into(); 102 | } 103 | 104 | /// Returns the calculated storage capacity. 105 | /// 106 | /// In theory, the greater the historical average depth, the less the 107 | /// storage of node stored locally. 108 | /// 109 | /// ```text 110 | /// average_depth = self.total_depth / self.blocks 111 | /// 112 | /// storage_capacity = 1 / average_depth 113 | /// = self.blocks / self.total_depth 114 | /// ``` 115 | pub fn as_storage_capacity(&self) -> Permill { 116 | Permill::from_rational(self.blocks, self.total_depth.saturated_into()) 117 | } 118 | } 119 | 120 | /// Trait for providing the author of current block. 121 | pub trait BlockAuthor { 122 | /// Returns the author of current building block. 123 | fn author() -> AccountId; 124 | } 125 | 126 | /// Error type for the poa inherent. 127 | #[derive(RuntimeDebug, Clone, Encode, Decode, TypeInfo)] 128 | pub enum InherentError { 129 | /// The poa entry included is invalid. 130 | InvalidProofOfAccess, 131 | /// Poa inherent is not provided. 132 | MissingPoaInherent, 133 | } 134 | 135 | #[frame_support::pallet] 136 | pub mod pallet { 137 | use super::*; 138 | use frame_support::pallet_prelude::*; 139 | use frame_system::pallet_prelude::*; 140 | 141 | /// Our pallet's configuration trait. All our types and constants go in here. If the 142 | /// pallet is dependent on specific other pallets, then their configuration traits 143 | /// should be added to our implied traits list. 144 | /// 145 | /// `frame_system::Config` should always be included. 146 | #[pallet::config] 147 | pub trait Config: frame_system::Config { 148 | /// The overarching event type. 149 | type Event: From> + IsType<::Event>; 150 | 151 | /// Find the author of current block. 152 | type BlockAuthor: BlockAuthor; 153 | 154 | /// Weight information for extrinsics in this pallet. 155 | type WeightInfo: WeightInfo; 156 | } 157 | 158 | #[pallet::pallet] 159 | #[pallet::generate_store(pub(super) trait Store)] 160 | #[pallet::generate_storage_info] 161 | pub struct Pallet(_); 162 | 163 | #[pallet::hooks] 164 | impl Hooks> for Pallet { 165 | fn on_finalize(_n: BlockNumberFor) {} 166 | } 167 | 168 | #[pallet::call] 169 | impl Pallet { 170 | /// Handle the inherent data from the poa consensus. 171 | /// 172 | /// Deposit a consensus log if `poa_outcome` contains a valid `ProofOfAccess`. 173 | #[pallet::weight((T::WeightInfo::deposit(), DispatchClass::Mandatory))] 174 | pub fn deposit(origin: OriginFor, poa_outcome: PoaOutcome) -> DispatchResult { 175 | ensure_none(origin)?; 176 | 177 | match poa_outcome { 178 | PoaOutcome::Justification(poa) => { 179 | poa.check_validity(&Self::poa_config()).map_err(|e| { 180 | frame_support::log::error!( 181 | target: "runtime::poa", 182 | "Checking poa validity failed when creating the poa `deposit` inherent: {:?}", 183 | e, 184 | ); 185 | Error::::InvalidProofOfAccess 186 | })?; 187 | 188 | Self::note_depth(poa.depth); 189 | >::deposit_log(DigestItem::Seal( 190 | POA_ENGINE_ID, 191 | poa.encode(), 192 | )); 193 | } 194 | PoaOutcome::MaxDepthReached(_) => { 195 | // Decrease the storage capacity? 196 | // Need to update outcome.require_inherent() too. 197 | // 198 | // TODO: slash the block author when SLA is too low? 199 | // None 200 | } 201 | PoaOutcome::Skipped => (), 202 | } 203 | 204 | Ok(()) 205 | } 206 | 207 | /// Set new poa configuration. 208 | #[pallet::weight(T::WeightInfo::set_config())] 209 | pub fn set_config(origin: OriginFor, new: PoaConfiguration) -> DispatchResult { 210 | ensure_root(origin)?; 211 | 212 | ensure!(new.check_sanity(), Error::::InvalidPoaConfiguration); 213 | 214 | PoaConfig::::put(&new); 215 | 216 | Self::deposit_event(Event::::ConfigUpdated(new)); 217 | 218 | Ok(()) 219 | } 220 | } 221 | 222 | #[pallet::inherent] 223 | impl ProvideInherent for Pallet { 224 | type Call = Call; 225 | type Error = MakeFatalError; 226 | 227 | const INHERENT_IDENTIFIER: InherentIdentifier = POA_INHERENT_IDENTIFIER; 228 | 229 | fn create_inherent(data: &InherentData) -> Option { 230 | let poa_outcome: PoaOutcome = match data.get_data(&Self::INHERENT_IDENTIFIER) { 231 | Ok(Some(outcome)) => outcome, 232 | Ok(None) => return None, 233 | Err(e) => { 234 | frame_support::log::error!( 235 | target: "runtime::poa", 236 | "Error occurred when getting the inherent data of poa: {:?}", 237 | e, 238 | ); 239 | return None; 240 | } 241 | }; 242 | 243 | // TODO: avoide double including the full ProofOfAccess struct in extrinsic 244 | // as it will be included in the header anyway? 245 | Some(Call::deposit { poa_outcome }) 246 | } 247 | 248 | fn check_inherent(call: &Self::Call, _: &InherentData) -> Result<(), Self::Error> { 249 | match call { 250 | Call::deposit { 251 | poa_outcome: PoaOutcome::Justification(poa), 252 | } => poa.check_validity(&Self::poa_config()).map_err(|e| { 253 | frame_support::log::error!( 254 | target: "runtime::poa", 255 | "Check inherent failed due to poa is invalid: {:?}", e, 256 | ); 257 | InherentError::InvalidProofOfAccess.into() 258 | }), 259 | _ => Ok(()), 260 | } 261 | } 262 | 263 | fn is_inherent(call: &Self::Call) -> bool { 264 | matches!(call, Call::deposit { .. }) 265 | } 266 | 267 | fn is_inherent_required(data: &InherentData) -> Result, Self::Error> { 268 | match data.get_data::(&Self::INHERENT_IDENTIFIER) { 269 | Ok(Some(outcome)) if outcome.require_inherent() => { 270 | Ok(Some(InherentError::MissingPoaInherent.into())) 271 | } 272 | _ => Ok(None), 273 | } 274 | } 275 | } 276 | 277 | /// Event for the poa pallet. 278 | #[pallet::event] 279 | #[pallet::generate_deposit(pub(super) fn deposit_event)] 280 | pub enum Event { 281 | /// New poa configuration. 282 | ConfigUpdated(PoaConfiguration), 283 | } 284 | 285 | /// Error for the poa pallet. 286 | #[pallet::error] 287 | pub enum Error { 288 | /// Invalid inherent data of `[ProofOfAccess]` 289 | InvalidProofOfAccess, 290 | /// The poa configuration failed the sanity checks. 291 | InvalidPoaConfiguration, 292 | } 293 | 294 | /// Poa Configuration. 295 | #[pallet::storage] 296 | #[pallet::getter(fn poa_config)] 297 | pub type PoaConfig = StorageValue<_, PoaConfiguration, ValueQuery>; 298 | 299 | /// Historical depth info for each validator. 300 | /// 301 | /// The probabilistic estimate of the proportion of each 302 | /// validator's local storage to the entire network storage. 303 | /// 304 | /// Indicated by the average depth of poa generation of a validator. 305 | /// The smaller the depth, the greater the storage capacity. 306 | #[pallet::storage] 307 | #[pallet::getter(fn history_depth)] 308 | pub type HistoryDepth = 309 | StorageMap<_, Blake2_128Concat, T::AccountId, DepthInfo>; 310 | 311 | /// Helper storage item of current block author for easier testing. 312 | #[cfg(test)] 313 | #[pallet::storage] 314 | pub(super) type TestAuthor = StorageValue<_, T::AccountId, ValueQuery>; 315 | 316 | impl Pallet { 317 | /// Updates the historical depth info of block author. 318 | pub(crate) fn note_depth(depth: Depth) { 319 | let block_author = T::BlockAuthor::author(); 320 | 321 | if let Some(mut old) = HistoryDepth::::get(&block_author) { 322 | old.add_depth(depth); 323 | HistoryDepth::::insert(&block_author, old); 324 | } else { 325 | HistoryDepth::::insert( 326 | &block_author, 327 | DepthInfo { 328 | blocks: 1u32.into(), 329 | total_depth: depth, 330 | }, 331 | ); 332 | } 333 | } 334 | } 335 | } 336 | --------------------------------------------------------------------------------