├── .gitignore ├── 1.json ├── Cargo.lock ├── Cargo.toml ├── LICENSE ├── README.md ├── cli ├── Cargo.toml ├── build.rs ├── res │ └── trust_cc2.json └── src │ ├── browser.rs │ ├── chain_spec.rs │ ├── cli.rs │ ├── command.rs │ ├── lib.rs │ └── service.rs ├── executor ├── Cargo.toml ├── benches │ └── bench.rs ├── src │ └── lib.rs └── tests │ ├── basic.rs │ ├── common.rs │ ├── fees.rs │ └── submit_transaction.rs ├── file_header.txt ├── inspect ├── Cargo.toml └── src │ ├── cli.rs │ ├── command.rs │ └── lib.rs ├── primitives ├── Cargo.toml └── src │ └── lib.rs ├── rpc-client ├── Cargo.toml └── src │ └── main.rs ├── rpc ├── Cargo.toml └── src │ └── lib.rs ├── runtime ├── Cargo.toml ├── build.rs └── src │ ├── constants.rs │ ├── impls.rs │ └── lib.rs ├── scripts └── init.sh ├── src └── main.rs └── testing ├── Cargo.toml └── src ├── bench.rs ├── client.rs ├── genesis.rs ├── keyring.rs └── lib.rs /.gitignore: -------------------------------------------------------------------------------- 1 | **/target/ 2 | data/ 3 | **/*.rs.bk 4 | *.swp 5 | .wasm-binaries 6 | .vscode 7 | .DS_Store 8 | .idea/ 9 | rls*.log 10 | runtime/Cargo.lock 11 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "trustbase" 3 | version = "0.2.0" 4 | authors = ["trust dev"] 5 | license = 'Apache-2.0' 6 | edition = "2018" 7 | 8 | [[bin]] 9 | name = "trustbase" 10 | path = "src/main.rs" 11 | 12 | [dependencies] 13 | node-cli = { package = "node-cli", path = "cli" } 14 | 15 | 16 | 17 | [workspace] 18 | members = [ 19 | 'cli', 20 | 'primitives', 21 | 'executor', 22 | 'inspect', 23 | 'runtime', 24 | 'testing', 25 | ] 26 | 27 | [profile.release] 28 | panic = 'unwind' 29 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # trustbase 2 | 3 | [![License: GPL v3](https://img.shields.io/badge/License-GPLv3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0) 4 | 5 | trustbase client implementation for trustbase, a Substrate compatible chain for wasm smart contracts. 6 | 7 | ## Setup Environment 8 | 9 | Install all the required dependencies with a single command 10 | 11 | ```bash 12 | curl https://getsubstrate.io -sSf | bash -s -- --fast 13 | ``` 14 | 15 | ## Build from source 16 | 17 | Once the development environment is set up, build the trustbase client. 18 | 19 | ```bash 20 | cargo build --release --locked 21 | ``` 22 | 23 | ## Usage 24 | 25 | To run local dev node, do 26 | 27 | ``` 28 | cargo run --release -- --dev 29 | ``` 30 | 31 | To run local network, do 32 | 33 | ``` 34 | cargo run --release -- --chain local 35 | ``` 36 | 37 | To run trustbase testnet cc2, do 38 | 39 | ``` 40 | ./target/release/trustbase --chain testnet 41 | ``` 42 | 43 | ## TrustBase network 44 | 45 | This repo supports trustbase runtimes for trustcc2. 46 | 47 | Connect to the trustcc1 network by running: 48 | 49 | ```bash 50 | ./target/release/trustbase 51 | ``` 52 | -------------------------------------------------------------------------------- /cli/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "node-cli" 3 | version = "2.0.0" 4 | build = "build.rs" 5 | edition = "2018" 6 | 7 | authors = ["trust dev"] 8 | license = 'Apache-2.0' 9 | description = "Generic TrustBase node implementation in Rust." 10 | 11 | [package.metadata.wasm-pack.profile.release] 12 | # `wasm-opt` has some problems on linux, see 13 | # https://github.com/rustwasm/wasm-pack/issues/781 etc. 14 | wasm-opt = false 15 | 16 | [package.metadata.docs.rs] 17 | targets = ["x86_64-unknown-linux-gnu"] 18 | 19 | [badges] 20 | travis-ci = { repository = "paritytech/substrate" } 21 | maintenance = { status = "actively-developed" } 22 | is-it-maintained-issue-resolution = { repository = "paritytech/substrate" } 23 | is-it-maintained-open-issues = { repository = "paritytech/substrate" } 24 | 25 | #[[bin]] 26 | #name = "trustbase" 27 | #path = "bin/main.rs" 28 | #required-features = ["cli"] 29 | 30 | [lib] 31 | crate-type = ["cdylib", "rlib"] 32 | 33 | [dependencies] 34 | # third-party dependencies 35 | codec = { package = "parity-scale-codec", version = "2.0.0" } 36 | serde = { version = "1.0.102", features = ["derive"] } 37 | futures = { version = "0.3.9", features = ["compat"] } 38 | hex-literal = "0.3.1" 39 | log = "0.4.8" 40 | rand = "0.7.2" 41 | structopt = { version = "0.3.8", optional = true } 42 | parking_lot = "0.11.1" 43 | 44 | # primitives 45 | sp-authority-discovery = { version = "3.0.0", git = "https://github.com/paritytech/substrate" } 46 | sp-consensus-babe = { version = "0.9.0", git = "https://github.com/paritytech/substrate" } 47 | grandpa-primitives = { version = "3.0.0", package = "sp-finality-grandpa", git = "https://github.com/paritytech/substrate" } 48 | sp-core = { version = "3.0.0", git = "https://github.com/paritytech/substrate" } 49 | sp-runtime = { version = "3.0.0", git = "https://github.com/paritytech/substrate" } 50 | sp-timestamp = { version = "3.0.0", git = "https://github.com/paritytech/substrate" } 51 | sp-authorship = { version = "3.0.0", git = "https://github.com/paritytech/substrate" } 52 | sp-inherents = { version = "3.0.0", git = "https://github.com/paritytech/substrate" } 53 | sp-keyring = { version = "3.0.0", git = "https://github.com/paritytech/substrate" } 54 | sp-keystore = { version = "0.9.0", git = "https://github.com/paritytech/substrate" } 55 | sp-io = { version = "3.0.0", git = "https://github.com/paritytech/substrate" } 56 | sp-consensus = { version = "0.9.0", git = "https://github.com/paritytech/substrate" } 57 | sp-transaction-pool = { version = "3.0.0", git = "https://github.com/paritytech/substrate" } 58 | 59 | # client dependencies 60 | sc-client-api = { version = "3.0.0", git = "https://github.com/paritytech/substrate" } 61 | sc-chain-spec = { version = "3.0.0", git = "https://github.com/paritytech/substrate" } 62 | sc-consensus = { version = "0.9.0", git = "https://github.com/paritytech/substrate" } 63 | sc-transaction-pool = { version = "3.0.0", git = "https://github.com/paritytech/substrate" } 64 | sc-network = { version = "0.9.0", git = "https://github.com/paritytech/substrate" } 65 | sc-consensus-slots = { version = "0.9.0", git = "https://github.com/paritytech/substrate" } 66 | sc-consensus-babe = { version = "0.9.0", git = "https://github.com/paritytech/substrate" } 67 | sc-consensus-uncles = { version = "0.9.0", git = "https://github.com/paritytech/substrate" } 68 | grandpa = { version = "0.9.0", package = "sc-finality-grandpa", git = "https://github.com/paritytech/substrate" } 69 | sc-client-db = { version = "0.9.0", default-features = false, git = "https://github.com/paritytech/substrate" } 70 | sc-offchain = { version = "3.0.0", git = "https://github.com/paritytech/substrate" } 71 | sc-rpc = { version = "3.0.0", git = "https://github.com/paritytech/substrate" } 72 | sc-basic-authorship = { version = "0.9.0", git = "https://github.com/paritytech/substrate" } 73 | sc-service = { version = "0.9.0", default-features = false, git = "https://github.com/paritytech/substrate" } 74 | sc-tracing = { version = "3.0.0", git = "https://github.com/paritytech/substrate" } 75 | sc-telemetry = { version = "3.0.0", git = "https://github.com/paritytech/substrate" } 76 | sc-authority-discovery = { version = "0.9.0", git = "https://github.com/paritytech/substrate" } 77 | sc-finality-grandpa-warp-sync = { version = "0.9.0", git = "https://github.com/paritytech/substrate", optional = true } 78 | 79 | # frame dependencies 80 | pallet-indices = { version = "3.0.0", git = "https://github.com/paritytech/substrate" } 81 | pallet-timestamp = { version = "3.0.0", default-features = false, git = "https://github.com/paritytech/substrate" } 82 | pallet-contracts = { version = "3.0.0", git = "https://github.com/paritytech/substrate" } 83 | frame-system = { version = "3.0.0", git = "https://github.com/paritytech/substrate" } 84 | pallet-balances = { version = "3.0.0", git = "https://github.com/paritytech/substrate" } 85 | pallet-transaction-payment = { version = "3.0.0", git = "https://github.com/paritytech/substrate" } 86 | frame-support = { version = "3.0.0", default-features = false, git = "https://github.com/paritytech/substrate" } 87 | pallet-im-online = { version = "3.0.0", default-features = false, git = "https://github.com/paritytech/substrate" } 88 | pallet-authority-discovery = { version = "3.0.0", git = "https://github.com/paritytech/substrate" } 89 | pallet-staking = { version = "3.0.0", git = "https://github.com/paritytech/substrate" } 90 | pallet-grandpa = { version = "3.1.0", git = "https://github.com/paritytech/substrate" } 91 | 92 | # node-specific dependencies 93 | node-runtime = { version = "2.0.0", path = "../runtime" } 94 | node-rpc = { version = "2.0.0", path = "../rpc" } 95 | node-primitives = { version = "2.0.0", path = "../primitives" } 96 | node-executor = { version = "2.0.0", path = "../executor" } 97 | 98 | # CLI-specific dependencies 99 | sc-cli = { version = "0.9.0", optional = true, git = "https://github.com/paritytech/substrate" } 100 | frame-benchmarking-cli = { version = "3.0.0", optional = true, git = "https://github.com/paritytech/substrate" } 101 | node-inspect = { version = "0.8.0", optional = true, path = "../inspect" } 102 | try-runtime-cli = { version = "0.9.0", optional = true, git = "https://github.com/paritytech/substrate" } 103 | 104 | # WASM-specific dependencies 105 | wasm-bindgen = { version = "0.2.73", optional = true } 106 | wasm-bindgen-futures = { version = "0.4.18", optional = true } 107 | browser-utils = { package = "substrate-browser-utils", git = "https://github.com/paritytech/substrate", optional = true, version = "0.9.0"} 108 | libp2p-wasm-ext = { version = "0.28", features = ["websocket"], optional = true } 109 | 110 | [target.'cfg(target_arch="x86_64")'.dependencies] 111 | node-executor = { version = "2.0.0", path = "../executor", features = [ "wasmtime" ] } 112 | sc-cli = { version = "0.9.0", optional = true, git = "https://github.com/paritytech/substrate", features = [ "wasmtime" ] } 113 | sc-service = { version = "0.9.0", default-features = false, git = "https://github.com/paritytech/substrate", features = [ "wasmtime" ] } 114 | sp-trie = { version = "3.0.0", default-features = false, git = "https://github.com/paritytech/substrate", features = ["memory-tracker"] } 115 | 116 | [dev-dependencies] 117 | sc-keystore = { version = "3.0.0", git = "https://github.com/paritytech/substrate" } 118 | sc-consensus = { version = "0.9.0", git = "https://github.com/paritytech/substrate" } 119 | sc-consensus-babe = { version = "0.9.0", git = "https://github.com/paritytech/substrate" } 120 | sc-consensus-epochs = { version = "0.9.0", git = "https://github.com/paritytech/substrate" } 121 | sc-service-test = { version = "2.0.0", git = "https://github.com/paritytech/substrate" } 122 | futures = "0.3.9" 123 | tempfile = "3.1.0" 124 | assert_cmd = "1.0" 125 | nix = "0.19" 126 | serde_json = "1.0" 127 | regex = "1" 128 | platforms = "1.1" 129 | async-std = { version = "1.6.5", features = ["attributes"] } 130 | soketto = "0.4.2" 131 | 132 | [build-dependencies] 133 | structopt = { version = "0.3.8", optional = true } 134 | node-inspect = { version = "0.8.0", optional = true, path = "../inspect" } 135 | frame-benchmarking-cli = { version = "3.0.0", optional = true, git = "https://github.com/paritytech/substrate" } 136 | substrate-build-script-utils = { version = "3.0.0", optional = true, git = "https://github.com/paritytech/substrate" } 137 | substrate-frame-cli = { version = "3.0.0", optional = true, git = "https://github.com/paritytech/substrate" } 138 | try-runtime-cli = { version = "0.9.0", optional = true, git = "https://github.com/paritytech/substrate" } 139 | 140 | [build-dependencies.sc-cli] 141 | version = "0.9.0" 142 | package = "sc-cli" 143 | git = "https://github.com/paritytech/substrate" 144 | optional = true 145 | 146 | [features] 147 | default = [ "cli" ] 148 | browser = [ 149 | "browser-utils", 150 | "wasm-bindgen", 151 | "wasm-bindgen-futures", 152 | "libp2p-wasm-ext", 153 | ] 154 | cli = [ 155 | "node-executor/wasmi-errno", 156 | "node-inspect", 157 | "sc-cli", 158 | "frame-benchmarking-cli", 159 | "substrate-frame-cli", 160 | "sc-service/db", 161 | "sc-finality-grandpa-warp-sync", 162 | "structopt", 163 | "substrate-build-script-utils", 164 | "try-runtime-cli", 165 | ] 166 | runtime-benchmarks = [ 167 | "node-runtime/runtime-benchmarks", 168 | "frame-benchmarking-cli", 169 | ] 170 | # Enable features that allow the runtime to be tried and debugged. Name might be subject to change 171 | # in the near future. 172 | try-runtime = [ 173 | "node-runtime/try-runtime", 174 | "try-runtime-cli", 175 | ] 176 | -------------------------------------------------------------------------------- /cli/build.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2019 TrustBase Network 2 | // This file is part of TrustBase library. 3 | // 4 | // The TrustBase library is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU Lesser General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // The TrustBase library is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU Lesser General Public License for more details. 13 | 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program. If not, see . 16 | 17 | fn main() { 18 | #[cfg(feature = "cli")] 19 | cli::main(); 20 | } 21 | 22 | #[cfg(feature = "cli")] 23 | mod cli { 24 | include!("src/cli.rs"); 25 | 26 | use std::{fs, env, path::Path}; 27 | use sc_cli::structopt::clap::Shell; 28 | use substrate_build_script_utils::{generate_cargo_keys, rerun_if_git_head_changed}; 29 | 30 | pub fn main() { 31 | build_shell_completion(); 32 | generate_cargo_keys(); 33 | 34 | rerun_if_git_head_changed(); 35 | } 36 | 37 | /// Build shell completion scripts for all known shells 38 | /// Full list in https://github.com/kbknapp/clap-rs/blob/e9d0562a1dc5dfe731ed7c767e6cee0af08f0cf9/src/app/parser.rs#L123 39 | fn build_shell_completion() { 40 | for shell in &[Shell::Bash, Shell::Fish, Shell::Zsh, Shell::Elvish, Shell::PowerShell] { 41 | build_completion(shell); 42 | } 43 | } 44 | 45 | /// Build the shell auto-completion for a given Shell 46 | fn build_completion(shell: &Shell) { 47 | let outdir = match env::var_os("OUT_DIR") { 48 | None => return, 49 | Some(dir) => dir, 50 | }; 51 | let path = Path::new(&outdir) 52 | .parent().unwrap() 53 | .parent().unwrap() 54 | .parent().unwrap() 55 | .join("completion-scripts"); 56 | 57 | fs::create_dir(&path).ok(); 58 | 59 | Cli::clap().gen_completions("trustbase-node", *shell, &path); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /cli/src/browser.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2019 TrustBase Network 2 | // This file is part of TrustBase library. 3 | // 4 | // The TrustBase library is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU Lesser General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // The TrustBase library is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program. If not, see . 16 | 17 | use crate::chain_spec::ChainSpec; 18 | use log::info; 19 | use wasm_bindgen::prelude::*; 20 | use browser_utils::{ 21 | Client, 22 | browser_configuration, init_logging, set_console_error_panic_hook, 23 | }; 24 | 25 | /// Starts the client. 26 | #[wasm_bindgen] 27 | pub async fn start_client(chain_spec: Option, log_level: String) -> Result { 28 | start_inner(chain_spec, log_level) 29 | .await 30 | .map_err(|err| JsValue::from_str(&err.to_string())) 31 | } 32 | 33 | async fn start_inner( 34 | chain_spec: Option, 35 | log_directives: String, 36 | ) -> Result> { 37 | set_console_error_panic_hook(); 38 | init_logging(&log_directives)?; 39 | let chain_spec = match chain_spec { 40 | Some(chain_spec) => ChainSpec::from_json_bytes(chain_spec.as_bytes().to_vec()) 41 | .map_err(|e| format!("{:?}", e))?, 42 | None => crate::chain_spec::development_config(), 43 | }; 44 | 45 | let config = browser_configuration(chain_spec).await?; 46 | 47 | info!("TrustBase browser node"); 48 | info!("✌️ version {}", config.impl_version); 49 | info!("❤️ by Parity Technologies, 2017-2021"); 50 | info!("📋 Chain specification: {}", config.chain_spec.name()); 51 | info!("🏷 Node name: {}", config.network.node_name); 52 | info!("👤 Role: {:?}", config.role); 53 | 54 | // Create the service. This is the most heavy initialization step. 55 | let (task_manager, rpc_handlers) = 56 | crate::service::new_light_base(config) 57 | .map(|(components, rpc_handlers, _, _, _)| (components, rpc_handlers)) 58 | .map_err(|e| format!("{:?}", e))?; 59 | 60 | Ok(browser_utils::start_client(task_manager, rpc_handlers)) 61 | } 62 | -------------------------------------------------------------------------------- /cli/src/chain_spec.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2019 TrustBase Network 2 | // This file is part of TrustBase library. 3 | // 4 | // The TrustBase library is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU Lesser General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // The TrustBase library is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU Lesser General Public License for more details. 13 | 14 | 15 | // You should have received a copy of the GNU General Public License 16 | // along with this program. If not, see . 17 | 18 | //! TrustBase chain configurations. 19 | 20 | use sc_chain_spec::ChainSpecExtension; 21 | use sp_core::{Pair, Public, crypto::UncheckedInto, sr25519}; 22 | use serde::{Serialize, Deserialize}; 23 | use node_runtime::{ 24 | AuthorityDiscoveryConfig, BabeConfig, BalancesConfig, CouncilConfig, 25 | DemocracyConfig, GrandpaConfig, ImOnlineConfig, SessionConfig, SessionKeys, StakerStatus, 26 | StakingConfig, ElectionsConfig, IndicesConfig, SocietyConfig, SudoConfig, SystemConfig, 27 | TechnicalCommitteeConfig, wasm_binary_unwrap, MAX_NOMINATIONS, 28 | }; 29 | use node_runtime::Block; 30 | use node_runtime::constants::currency::*; 31 | use sc_service::ChainType; 32 | use hex_literal::hex; 33 | use sc_telemetry::TelemetryEndpoints; 34 | use grandpa_primitives::{AuthorityId as GrandpaId}; 35 | use sp_consensus_babe::{AuthorityId as BabeId}; 36 | use pallet_im_online::sr25519::{AuthorityId as ImOnlineId}; 37 | use sp_authority_discovery::AuthorityId as AuthorityDiscoveryId; 38 | use sp_runtime::{Perbill, traits::{Verify, IdentifyAccount}}; 39 | 40 | pub use node_primitives::{AccountId, Balance, Signature}; 41 | pub use node_runtime::GenesisConfig; 42 | 43 | type AccountPublic = ::Signer; 44 | 45 | const TRUSTCC2_TELEMETRY_URL: &str = "wss://telemetry.polkadot.io/submit/"; 46 | 47 | /// Node `ChainSpec` extensions. 48 | /// 49 | /// Additional parameters for some TrustBase core modules, 50 | /// customizable from the chain spec. 51 | #[derive(Default, Clone, Serialize, Deserialize, ChainSpecExtension)] 52 | #[serde(rename_all = "camelCase")] 53 | pub struct Extensions { 54 | /// Block numbers with known hashes. 55 | pub fork_blocks: sc_client_api::ForkBlocks, 56 | /// Known bad block hashes. 57 | pub bad_blocks: sc_client_api::BadBlocks, 58 | } 59 | 60 | /// Specialized `ChainSpec`. 61 | pub type ChainSpec = sc_service::GenericChainSpec< 62 | GenesisConfig, 63 | Extensions, 64 | >; 65 | /// Flaming Fir testnet generator 66 | pub fn trust_cc2_config() -> Result { 67 | ChainSpec::from_json_bytes(&include_bytes!("../res/trust_cc2.json")[..]) 68 | } 69 | 70 | fn session_keys( 71 | grandpa: GrandpaId, 72 | babe: BabeId, 73 | im_online: ImOnlineId, 74 | authority_discovery: AuthorityDiscoveryId, 75 | ) -> SessionKeys { 76 | SessionKeys { grandpa, babe, im_online, authority_discovery } 77 | } 78 | 79 | fn testnet_config_genesis() -> GenesisConfig { 80 | // stash, controller, session-key 81 | // generated with secret: 82 | // for i in 1 2 3 4 ; do for j in stash controller; do subkey inspect "$secret"/fir/$j/$i; done; done 83 | // and 84 | // for i in 1 2 3 4 ; do for j in session; do subkey --ed25519 inspect "$secret"//fir//$j//$i; done; done 85 | 86 | let initial_authorities: Vec<(AccountId, AccountId, GrandpaId, BabeId, ImOnlineId, AuthorityDiscoveryId)> = vec![( 87 | // 5FHAoSx5RpeaxAfAasqoLaFJShf4nT7Nzg8wArCAnkUSc35G 88 | hex!["8e3659306967d22db66360dae35a250a816a49a0560fd340bd23cb67d5c24f69"].into(), 89 | // 5EhRVJobxCD3L8mNzazaRApzhwqXjUrRFYVFwNpxmrnymLpp 90 | hex!["7479723f8e880cd7c54671c3c012405ec3229974b3c3e1f455472e7c60245b41"].into(), 91 | // 5HWcZhWqCQm9w2oKct1UXkymVCkQf9W1DsjSNbWb9C4dzbue 92 | hex!["f0efbb3ba8b3b507ef8ab80f203832554a55913b3092e89b9797b066d6bde209"].unchecked_into(), 93 | // 5EPQnq4rbr8HhjXV8AEXFVWqydPKTcm9ww3FdkwBsKmcDdZE 94 | hex!["66bcadfe4c77ebf6f270b1c983327fe799e75c43fbd0ff245d0964a4e8e7240b"].unchecked_into(), 95 | // 5EPQnq4rbr8HhjXV8AEXFVWqydPKTcm9ww3FdkwBsKmcDdZE 96 | hex!["66bcadfe4c77ebf6f270b1c983327fe799e75c43fbd0ff245d0964a4e8e7240b"].unchecked_into(), 97 | // 5EPQnq4rbr8HhjXV8AEXFVWqydPKTcm9ww3FdkwBsKmcDdZE 98 | hex!["66bcadfe4c77ebf6f270b1c983327fe799e75c43fbd0ff245d0964a4e8e7240b"].unchecked_into(), 99 | ),( 100 | // 5EZZ2v4mX3cbMPn7nh2XztDXmPhQqEjqCY91p58BgNoYBUWk 101 | hex!["6e78e1b4a82e03c957fd6e2bb393de72372180a4d5c3c74011cad0f75554d649"].into(), 102 | // 5GH8r7cTKQYfZF5KPQC9T5X9CeUx7N5NCQuC1se8kEfzTcNR 103 | hex!["ba6c0107240c63cbb2c9f3ee12e0beeaf2c15e193016b6378261c09b3a97ab4c"].into(), 104 | // 5FYfZinXLfRx5z6AsYAmRXV99RYqobCjnboFTZWDi8Jr1nJS 105 | hex!["9a07dafeffeafc8a9c7212afd9a2de8f3681fcaa7e0d86413889f1304d7cbaf6"].unchecked_into(), 106 | // 5EjzSDzW4bZKWU2Q5Jz8HbiijNqabpW1wV6wDYVCNyWPM8rF 107 | hex!["766ed89755181326d9a0a5921e4dec15efea32f5b3162b076f9661cf9ae8ed7c"].unchecked_into(), 108 | // 5EjzSDzW4bZKWU2Q5Jz8HbiijNqabpW1wV6wDYVCNyWPM8rF 109 | hex!["766ed89755181326d9a0a5921e4dec15efea32f5b3162b076f9661cf9ae8ed7c"].unchecked_into(), 110 | // 5EjzSDzW4bZKWU2Q5Jz8HbiijNqabpW1wV6wDYVCNyWPM8rF 111 | hex!["766ed89755181326d9a0a5921e4dec15efea32f5b3162b076f9661cf9ae8ed7c"].unchecked_into(), 112 | ),( 113 | // 5EhFQxYQ5R69snnTaaFf1HdAepWFEudHHkgEqQPjsRwWcwLn 114 | hex!["745787e5956204ec868069ad79cd5606a170760967b9b23b66c9fd6a1406d830"].into(), 115 | // 5FWAFEQGjVzo4MVxnWCh5wSgtakMcP1KvPZ8yAMMjYxqj9rK 116 | hex!["981eab3829581e9274d32379d51d21a3b21879695217bf99fb41c22c77d49a3e"].into(), 117 | // 5Es66HgxzDabC9vS9LjjPxyixY9kEsNi8VJgXoXRoyyBD15d 118 | hex!["7bd89ac6e1a6ad194c244f0c642e0b6b40a0e477c0e6df46a5eb60b0705e41c3"].unchecked_into(), 119 | // 5GWTionxm9rN7PsVyJwKa3Q9ij62yoTX9TMKeTBF8YWz9MLB 120 | hex!["c495bad86a3642811ebb54a6e8f08cfb2c6ed281c184920c6eacac634e48ee74"].unchecked_into(), 121 | // 5GWTionxm9rN7PsVyJwKa3Q9ij62yoTX9TMKeTBF8YWz9MLB 122 | hex!["c495bad86a3642811ebb54a6e8f08cfb2c6ed281c184920c6eacac634e48ee74"].unchecked_into(), 123 | // 5GWTionxm9rN7PsVyJwKa3Q9ij62yoTX9TMKeTBF8YWz9MLB 124 | hex!["c495bad86a3642811ebb54a6e8f08cfb2c6ed281c184920c6eacac634e48ee74"].unchecked_into(), 125 | ),( 126 | // 5CnkJUAxV4MoULHyYut4UkQYLzKR5p71usm5SyHJfV2hcfRG 127 | hex!["2010897b516c6cd0c43e727690a8dc3fcb19dccd126b9625e08a9fcd65944f13"].into(), 128 | // 5C5HKrq3uCT3YnwTjHACJHXtzmHcK1SiovxyEczoeYJL81uQ 129 | hex!["0070aa837f8b46ab5bef7d137cdeb3af2a77152357886c364c0e126451bc9422"].into(), 130 | // 5DXSupP8CVJqn1XvswbxR3FrywT7B7oCBCcMuexYPTPqfVG2 131 | hex!["40a18c31daa63f713fbc3a089e0eb696381d0af23f015342ad98a995a3a9a125"].unchecked_into(), 132 | // 5CQJ8SW3WXPfMQbbriNScUFF3sxTJa7Hfk2Y1a7axkstMJa3 133 | hex!["0ef10842f02694ca5e4a7e51838aed4f0b02a2e94e92d16154972c2f1b575246"].unchecked_into(), 134 | // 5CQJ8SW3WXPfMQbbriNScUFF3sxTJa7Hfk2Y1a7axkstMJa3 135 | hex!["0ef10842f02694ca5e4a7e51838aed4f0b02a2e94e92d16154972c2f1b575246"].unchecked_into(), 136 | // 5CQJ8SW3WXPfMQbbriNScUFF3sxTJa7Hfk2Y1a7axkstMJa3 137 | hex!["0ef10842f02694ca5e4a7e51838aed4f0b02a2e94e92d16154972c2f1b575246"].unchecked_into(), 138 | )]; 139 | 140 | // generated with secret: subkey inspect "$secret"/fir 141 | let root_key: AccountId = hex![ 142 | // 5DLNQLALs9aG927EPyrTq8xjCki1LP35a5VDFQX3rBWo1mAP 143 | "382eabedd42655978ddc2e4203677500c21df8685c93c1cb4c6d5f50a9b4f045" 144 | ].into(); 145 | 146 | let endowed_accounts: Vec = vec![root_key.clone()]; 147 | 148 | testnet_genesis( 149 | initial_authorities, 150 | vec![], 151 | root_key, 152 | Some(endowed_accounts) 153 | ) 154 | } 155 | 156 | /// Staging testnet config. 157 | pub fn testnet_config() -> ChainSpec { 158 | let boot_nodes = vec![]; 159 | ChainSpec::from_genesis( 160 | "trust_cc2 Testnet", 161 | "trust_cc2_testnet", 162 | ChainType::Live, 163 | testnet_config_genesis, 164 | boot_nodes, 165 | Some(TelemetryEndpoints::new(vec![(TRUSTCC2_TELEMETRY_URL.to_string(), 0)]) 166 | .expect("trust_cc2 telemetry url is valid; qed")), 167 | None, 168 | None, 169 | Default::default(), 170 | ) 171 | } 172 | 173 | /// Helper function to generate a crypto pair from seed 174 | pub fn get_from_seed(seed: &str) -> ::Public { 175 | TPublic::Pair::from_string(&format!("//{}", seed), None) 176 | .expect("static values are valid; qed") 177 | .public() 178 | } 179 | 180 | /// Helper function to generate an account ID from seed 181 | pub fn get_account_id_from_seed(seed: &str) -> AccountId where 182 | AccountPublic: From<::Public> 183 | { 184 | AccountPublic::from(get_from_seed::(seed)).into_account() 185 | } 186 | 187 | /// Helper function to generate stash, controller and session key from seed 188 | pub fn authority_keys_from_seed(seed: &str) -> ( 189 | AccountId, 190 | AccountId, 191 | GrandpaId, 192 | BabeId, 193 | ImOnlineId, 194 | AuthorityDiscoveryId, 195 | ) { 196 | ( 197 | get_account_id_from_seed::(&format!("{}//stash", seed)), 198 | get_account_id_from_seed::(seed), 199 | get_from_seed::(seed), 200 | get_from_seed::(seed), 201 | get_from_seed::(seed), 202 | get_from_seed::(seed), 203 | ) 204 | } 205 | 206 | /// Helper function to create GenesisConfig for testing 207 | pub fn testnet_genesis( 208 | initial_authorities: Vec<( 209 | AccountId, 210 | AccountId, 211 | GrandpaId, 212 | BabeId, 213 | ImOnlineId, 214 | AuthorityDiscoveryId, 215 | )>, 216 | initial_nominators: Vec, 217 | root_key: AccountId, 218 | endowed_accounts: Option>, 219 | ) -> GenesisConfig { 220 | let mut endowed_accounts: Vec = endowed_accounts.unwrap_or_else(|| { 221 | vec![ 222 | get_account_id_from_seed::("Alice"), 223 | get_account_id_from_seed::("Bob"), 224 | get_account_id_from_seed::("Charlie"), 225 | get_account_id_from_seed::("Dave"), 226 | get_account_id_from_seed::("Eve"), 227 | get_account_id_from_seed::("Ferdie"), 228 | get_account_id_from_seed::("Alice//stash"), 229 | get_account_id_from_seed::("Bob//stash"), 230 | get_account_id_from_seed::("Charlie//stash"), 231 | get_account_id_from_seed::("Dave//stash"), 232 | get_account_id_from_seed::("Eve//stash"), 233 | get_account_id_from_seed::("Ferdie//stash"), 234 | ] 235 | }); 236 | // endow all authorities and nominators. 237 | initial_authorities.iter().map(|x| &x.0).chain(initial_nominators.iter()).for_each(|x| { 238 | if !endowed_accounts.contains(&x) { 239 | endowed_accounts.push(x.clone()) 240 | } 241 | }); 242 | 243 | // stakers: all validators and nominators. 244 | let mut rng = rand::thread_rng(); 245 | let stakers = initial_authorities 246 | .iter() 247 | .map(|x| (x.0.clone(), x.1.clone(), STASH, StakerStatus::Validator)) 248 | .chain(initial_nominators.iter().map(|x| { 249 | use rand::{seq::SliceRandom, Rng}; 250 | let limit = (MAX_NOMINATIONS as usize).min(initial_authorities.len()); 251 | let count = rng.gen::() % limit; 252 | let nominations = initial_authorities 253 | .as_slice() 254 | .choose_multiple(&mut rng, count) 255 | .into_iter() 256 | .map(|choice| choice.0.clone()) 257 | .collect::>(); 258 | (x.clone(), x.clone(), STASH, StakerStatus::Nominator(nominations)) 259 | })) 260 | .collect::>(); 261 | 262 | let num_endowed_accounts = endowed_accounts.len(); 263 | 264 | const ENDOWMENT: Balance = 10_000_000 * DOLLARS; 265 | const STASH: Balance = ENDOWMENT / 2; 266 | 267 | GenesisConfig { 268 | system: SystemConfig { 269 | code: wasm_binary_unwrap().to_vec(), 270 | changes_trie_config: Default::default(), 271 | }, 272 | balances: BalancesConfig { 273 | balances: endowed_accounts.iter().cloned() 274 | .map(|x| (x, ENDOWMENT)) 275 | .collect() 276 | }, 277 | indices: IndicesConfig { 278 | indices: vec![], 279 | }, 280 | session: SessionConfig { 281 | keys: initial_authorities.iter().map(|x| { 282 | (x.0.clone(), x.0.clone(), session_keys( 283 | x.2.clone(), 284 | x.3.clone(), 285 | x.4.clone(), 286 | x.5.clone(), 287 | )) 288 | }).collect::>(), 289 | }, 290 | staking: StakingConfig { 291 | validator_count: initial_authorities.len() as u32, 292 | minimum_validator_count: initial_authorities.len() as u32, 293 | invulnerables: initial_authorities.iter().map(|x| x.0.clone()).collect(), 294 | slash_reward_fraction: Perbill::from_percent(10), 295 | stakers, 296 | .. Default::default() 297 | }, 298 | democracy: DemocracyConfig::default(), 299 | elections: ElectionsConfig { 300 | members: endowed_accounts.iter() 301 | .take((num_endowed_accounts + 1) / 2) 302 | .cloned() 303 | .map(|member| (member, STASH)) 304 | .collect(), 305 | }, 306 | council: CouncilConfig::default(), 307 | technical_committee: TechnicalCommitteeConfig { 308 | members: endowed_accounts.iter() 309 | .take((num_endowed_accounts + 1) / 2) 310 | .cloned() 311 | .collect(), 312 | phantom: Default::default(), 313 | }, 314 | sudo: SudoConfig { 315 | key: root_key, 316 | }, 317 | babe: BabeConfig { 318 | authorities: vec![], 319 | epoch_config: Some(node_runtime::BABE_GENESIS_EPOCH_CONFIG), 320 | }, 321 | im_online: ImOnlineConfig { 322 | keys: vec![], 323 | }, 324 | authority_discovery: AuthorityDiscoveryConfig { 325 | keys: vec![], 326 | }, 327 | grandpa: GrandpaConfig { 328 | authorities: vec![], 329 | }, 330 | technical_membership: Default::default(), 331 | treasury: Default::default(), 332 | society: SocietyConfig { 333 | members: endowed_accounts.iter() 334 | .take((num_endowed_accounts + 1) / 2) 335 | .cloned() 336 | .collect(), 337 | pot: 0, 338 | max_members: 999, 339 | }, 340 | transaction_storage: Default::default(), 341 | } 342 | } 343 | 344 | fn development_config_genesis() -> GenesisConfig { 345 | testnet_genesis( 346 | vec![ 347 | authority_keys_from_seed("Alice"), 348 | ], 349 | vec![], 350 | get_account_id_from_seed::("Alice"), 351 | None, 352 | ) 353 | } 354 | 355 | /// Development config (single validator Alice) 356 | pub fn development_config() -> ChainSpec { 357 | ChainSpec::from_genesis( 358 | "Development", 359 | "dev", 360 | ChainType::Development, 361 | development_config_genesis, 362 | vec![], 363 | None, 364 | None, 365 | None, 366 | Default::default(), 367 | ) 368 | } 369 | 370 | fn local_testnet_genesis() -> GenesisConfig { 371 | testnet_genesis( 372 | vec![ 373 | authority_keys_from_seed("Alice"), 374 | authority_keys_from_seed("Bob"), 375 | ], 376 | vec![], 377 | get_account_id_from_seed::("Alice"), 378 | None, 379 | ) 380 | } 381 | 382 | /// Local testnet config (multivalidator Alice + Bob) 383 | pub fn local_testnet_config() -> ChainSpec { 384 | ChainSpec::from_genesis( 385 | "Local Testnet", 386 | "local_testnet", 387 | ChainType::Local, 388 | local_testnet_genesis, 389 | vec![], 390 | None, 391 | None, 392 | None, 393 | Default::default(), 394 | ) 395 | } 396 | 397 | #[cfg(test)] 398 | pub(crate) mod tests { 399 | use super::*; 400 | use crate::service::{new_full_base, new_light_base, NewFullBase}; 401 | use sc_service_test; 402 | use sp_runtime::BuildStorage; 403 | 404 | fn local_testnet_genesis_instant_single() -> GenesisConfig { 405 | testnet_genesis( 406 | vec![ 407 | authority_keys_from_seed("Alice"), 408 | ], 409 | vec![], 410 | get_account_id_from_seed::("Alice"), 411 | None, 412 | ) 413 | } 414 | 415 | /// Local testnet config (single validator - Alice) 416 | pub fn integration_test_config_with_single_authority() -> ChainSpec { 417 | ChainSpec::from_genesis( 418 | "Integration Test", 419 | "test", 420 | ChainType::Development, 421 | local_testnet_genesis_instant_single, 422 | vec![], 423 | None, 424 | None, 425 | None, 426 | Default::default(), 427 | ) 428 | } 429 | 430 | /// Local testnet config (multivalidator Alice + Bob) 431 | pub fn integration_test_config_with_two_authorities() -> ChainSpec { 432 | ChainSpec::from_genesis( 433 | "Integration Test", 434 | "test", 435 | ChainType::Development, 436 | local_testnet_genesis, 437 | vec![], 438 | None, 439 | None, 440 | None, 441 | Default::default(), 442 | ) 443 | } 444 | 445 | #[test] 446 | #[ignore] 447 | fn test_connectivity() { 448 | sc_service_test::connectivity( 449 | integration_test_config_with_two_authorities(), 450 | |config| { 451 | let NewFullBase { task_manager, client, network, transaction_pool, .. } 452 | = new_full_base(config,|_, _| ())?; 453 | Ok(sc_service_test::TestNetComponents::new(task_manager, client, network, transaction_pool)) 454 | }, 455 | |config| { 456 | let (keep_alive, _, client, network, transaction_pool) = new_light_base(config)?; 457 | Ok(sc_service_test::TestNetComponents::new(keep_alive, client, network, transaction_pool)) 458 | } 459 | ); 460 | } 461 | 462 | #[test] 463 | fn test_create_development_chain_spec() { 464 | development_config().build_storage().unwrap(); 465 | } 466 | 467 | #[test] 468 | fn test_create_local_testnet_chain_spec() { 469 | local_testnet_config().build_storage().unwrap(); 470 | } 471 | 472 | #[test] 473 | fn test_staging_test_net_chain_spec() { 474 | testnet_config().build_storage().unwrap(); 475 | } 476 | } 477 | -------------------------------------------------------------------------------- /cli/src/cli.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2019 TrustBase Network 2 | // This file is part of TrustBase library. 3 | // 4 | // The TrustBase library is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU Lesser General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // The TrustBase library is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU Lesser General Public License for more details. 13 | 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program. If not, see . 16 | 17 | use sc_cli::{RunCmd, KeySubcommand, SignCmd, VanityCmd, VerifyCmd}; 18 | use structopt::StructOpt; 19 | 20 | /// An overarching CLI command definition. 21 | #[derive(Debug, StructOpt)] 22 | pub struct Cli { 23 | /// Possible subcommand with parameters. 24 | #[structopt(subcommand)] 25 | pub subcommand: Option, 26 | #[allow(missing_docs)] 27 | #[structopt(flatten)] 28 | pub run: RunCmd, 29 | } 30 | 31 | /// Possible subcommands of the main binary. 32 | #[derive(Debug, StructOpt)] 33 | pub enum Subcommand { 34 | /// Key management cli utilities 35 | Key(KeySubcommand), 36 | 37 | /// The custom inspect subcommmand for decoding blocks and extrinsics. 38 | #[structopt( 39 | name = "inspect", 40 | about = "Decode given block or extrinsic using current native runtime." 41 | )] 42 | Inspect(node_inspect::cli::InspectCmd), 43 | 44 | /// The custom benchmark subcommmand benchmarking runtime pallets. 45 | #[structopt(name = "benchmark", about = "Benchmark runtime pallets.")] 46 | Benchmark(frame_benchmarking_cli::BenchmarkCmd), 47 | 48 | /// Try some command against runtime state. 49 | #[cfg(feature = "try-runtime")] 50 | TryRuntime(try_runtime_cli::TryRuntimeCmd), 51 | 52 | /// Try some command against runtime state. Note: `try-runtime` feature must be enabled. 53 | #[cfg(not(feature = "try-runtime"))] 54 | TryRuntime, 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 | -------------------------------------------------------------------------------- /cli/src/command.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2019 TrustBase Network 2 | // This file is part of TrustBase library. 3 | // 4 | // The TrustBase library is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU Lesser General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // The TrustBase library is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU Lesser General Public License for more details. 13 | 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program. If not, see . 16 | 17 | use crate::{chain_spec, service, Cli, Subcommand}; 18 | use node_executor::Executor; 19 | use node_runtime::{Block, RuntimeApi}; 20 | use sc_cli::{Result, SubstrateCli, RuntimeVersion, Role, ChainSpec}; 21 | use sc_service::PartialComponents; 22 | use crate::service::new_partial; 23 | 24 | impl SubstrateCli for Cli { 25 | fn impl_name() -> String { 26 | "TrustBase Node".into() 27 | } 28 | 29 | fn impl_version() -> String { 30 | env!("SUBSTRATE_CLI_IMPL_VERSION").into() 31 | } 32 | 33 | fn description() -> String { 34 | env!("CARGO_PKG_DESCRIPTION").into() 35 | } 36 | 37 | fn author() -> String { 38 | env!("CARGO_PKG_AUTHORS").into() 39 | } 40 | 41 | fn support_url() -> String { 42 | "https://github.com/paritytech/substrate/issues/new".into() 43 | } 44 | 45 | fn copyright_start_year() -> i32 { 46 | 2017 47 | } 48 | 49 | fn load_spec(&self, id: &str) -> std::result::Result, String> { 50 | Ok(match id { 51 | "dev" => Box::new(chain_spec::development_config()), 52 | "local" => Box::new(chain_spec::local_testnet_config()), 53 | "" => Box::new(chain_spec::trust_cc2_config()?), 54 | "testnet" => Box::new(chain_spec::testnet_config()), 55 | path => Box::new(chain_spec::ChainSpec::from_json_file( 56 | std::path::PathBuf::from(path), 57 | )?), 58 | }) 59 | } 60 | 61 | fn native_runtime_version(_: &Box) -> &'static RuntimeVersion { 62 | &node_runtime::VERSION 63 | } 64 | } 65 | 66 | /// Parse command line arguments into service configuration. 67 | pub fn run() -> Result<()> { 68 | let cli = Cli::from_args(); 69 | 70 | match &cli.subcommand { 71 | None => { 72 | let runner = cli.create_runner(&cli.run)?; 73 | runner.run_node_until_exit(|config| async move { 74 | match config.role { 75 | Role::Light => service::new_light(config), 76 | _ => service::new_full(config), 77 | }.map_err(sc_cli::Error::Service) 78 | }) 79 | } 80 | Some(Subcommand::Inspect(cmd)) => { 81 | let runner = cli.create_runner(cmd)?; 82 | 83 | runner.sync_run(|config| cmd.run::(config)) 84 | } 85 | Some(Subcommand::Benchmark(cmd)) => { 86 | if cfg!(feature = "runtime-benchmarks") { 87 | let runner = cli.create_runner(cmd)?; 88 | 89 | runner.sync_run(|config| cmd.run::(config)) 90 | } else { 91 | Err("Benchmarking wasn't enabled when building the node. \ 92 | You can enable it with `--features runtime-benchmarks`.".into()) 93 | } 94 | } 95 | Some(Subcommand::Key(cmd)) => cmd.run(&cli), 96 | Some(Subcommand::Sign(cmd)) => cmd.run(), 97 | Some(Subcommand::Verify(cmd)) => cmd.run(), 98 | Some(Subcommand::Vanity(cmd)) => cmd.run(), 99 | Some(Subcommand::BuildSpec(cmd)) => { 100 | let runner = cli.create_runner(cmd)?; 101 | runner.sync_run(|config| cmd.run(config.chain_spec, config.network)) 102 | }, 103 | Some(Subcommand::CheckBlock(cmd)) => { 104 | let runner = cli.create_runner(cmd)?; 105 | runner.async_run(|config| { 106 | let PartialComponents { client, task_manager, import_queue, ..} 107 | = new_partial(&config)?; 108 | Ok((cmd.run(client, import_queue), task_manager)) 109 | }) 110 | }, 111 | Some(Subcommand::ExportBlocks(cmd)) => { 112 | let runner = cli.create_runner(cmd)?; 113 | runner.async_run(|config| { 114 | let PartialComponents { client, task_manager, ..} 115 | = new_partial(&config)?; 116 | Ok((cmd.run(client, config.database), task_manager)) 117 | }) 118 | }, 119 | Some(Subcommand::ExportState(cmd)) => { 120 | let runner = cli.create_runner(cmd)?; 121 | runner.async_run(|config| { 122 | let PartialComponents { client, task_manager, ..} 123 | = new_partial(&config)?; 124 | Ok((cmd.run(client, config.chain_spec), task_manager)) 125 | }) 126 | }, 127 | Some(Subcommand::ImportBlocks(cmd)) => { 128 | let runner = cli.create_runner(cmd)?; 129 | runner.async_run(|config| { 130 | let PartialComponents { client, task_manager, import_queue, ..} 131 | = new_partial(&config)?; 132 | Ok((cmd.run(client, import_queue), task_manager)) 133 | }) 134 | }, 135 | Some(Subcommand::PurgeChain(cmd)) => { 136 | let runner = cli.create_runner(cmd)?; 137 | runner.sync_run(|config| cmd.run(config.database)) 138 | }, 139 | Some(Subcommand::Revert(cmd)) => { 140 | let runner = cli.create_runner(cmd)?; 141 | runner.async_run(|config| { 142 | let PartialComponents { client, task_manager, backend, ..} 143 | = new_partial(&config)?; 144 | Ok((cmd.run(client, backend), task_manager)) 145 | }) 146 | }, 147 | #[cfg(feature = "try-runtime")] 148 | Some(Subcommand::TryRuntime(cmd)) => { 149 | let runner = cli.create_runner(cmd)?; 150 | runner.async_run(|config| { 151 | // we don't need any of the components of new_partial, just a runtime, or a task 152 | // manager to do `async_run`. 153 | let registry = config.prometheus_config.as_ref().map(|cfg| &cfg.registry); 154 | let task_manager = sc_service::TaskManager::new( 155 | config.task_executor.clone(), 156 | registry, 157 | ).map_err(|e| sc_cli::Error::Service(sc_service::Error::Prometheus(e)))?; 158 | 159 | Ok((cmd.run::(config), task_manager)) 160 | }) 161 | }, 162 | #[cfg(not(feature = "try-runtime"))] 163 | Some(Subcommand::TryRuntime) => { 164 | Err("TryRuntime wasn't enabled when building the node. \ 165 | You can enable it with `--features try-runtime`.".into()) 166 | }, 167 | } 168 | } 169 | -------------------------------------------------------------------------------- /cli/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2019 TrustBase Network 2 | // This file is part of TrustBase library. 3 | // 4 | // The TrustBase library is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU Lesser General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // The TrustBase library is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU Lesser General Public License for more details. 13 | 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program. If not, see . 16 | 17 | //! TrustBase CLI library. 18 | //! 19 | //! This package has two Cargo features: 20 | //! 21 | //! - `cli` (default): exposes functions that parse command-line options, then start and run the 22 | //! node as a CLI application. 23 | //! 24 | //! - `browser`: exposes the content of the `browser` module, which consists of exported symbols 25 | //! that are meant to be passed through the `wasm-bindgen` utility and called from JavaScript. 26 | //! Despite its name the produced WASM can theoretically also be used from NodeJS, although this 27 | //! hasn't been tested. 28 | 29 | pub mod chain_spec; 30 | 31 | #[macro_use] 32 | mod service; 33 | #[cfg(feature = "browser")] 34 | mod browser; 35 | #[cfg(feature = "cli")] 36 | mod cli; 37 | #[cfg(feature = "cli")] 38 | mod command; 39 | 40 | #[cfg(feature = "browser")] 41 | pub use browser::*; 42 | #[cfg(feature = "cli")] 43 | pub use cli::*; 44 | #[cfg(feature = "cli")] 45 | pub use command::*; 46 | 47 | pub type Result = sc_cli::Result; -------------------------------------------------------------------------------- /executor/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "node-executor" 3 | version = "2.0.0" 4 | authors = ["trust dev"] 5 | 6 | edition = "2018" 7 | license = "Apache-2.0" 8 | description = "TrustBase node implementation in Rust." 9 | 10 | [package.metadata.docs.rs] 11 | targets = ["x86_64-unknown-linux-gnu"] 12 | 13 | [dependencies] 14 | codec = { package = "parity-scale-codec", version = "2.0.0" } 15 | node-primitives = { version = "2.0.0", path = "../primitives" } 16 | node-runtime = { version = "2.0.0", path = "../runtime" } 17 | sc-executor = { version = "0.9.0", git = "https://github.com/paritytech/substrate" } 18 | sp-core = { version = "3.0.0", git = "https://github.com/paritytech/substrate" } 19 | sp-keystore = { version = "0.9.0", git = "https://github.com/paritytech/substrate" } 20 | sp-io = { version = "3.0.0", git = "https://github.com/paritytech/substrate" } 21 | sp-state-machine = { version = "0.9.0", git = "https://github.com/paritytech/substrate" } 22 | sp-trie = { version = "3.0.0", git = "https://github.com/paritytech/substrate" } 23 | trie-root = "0.16.0" 24 | frame-benchmarking = { version = "3.1.0", git = "https://github.com/paritytech/substrate" } 25 | 26 | [dev-dependencies] 27 | criterion = "0.3.0" 28 | frame-support = { version = "3.0.0", git = "https://github.com/paritytech/substrate" } 29 | frame-system = { version = "3.0.0", git = "https://github.com/paritytech/substrate" } 30 | node-testing = { version = "2.0.0", path = "../testing" } 31 | pallet-balances = { version = "3.0.0", git = "https://github.com/paritytech/substrate" } 32 | pallet-contracts = { version = "3.0.0", git = "https://github.com/paritytech/substrate" } 33 | pallet-grandpa = { version = "3.1.0", git = "https://github.com/paritytech/substrate" } 34 | pallet-im-online = { version = "3.0.0", git = "https://github.com/paritytech/substrate" } 35 | pallet-indices = { version = "3.0.0", git = "https://github.com/paritytech/substrate" } 36 | pallet-session = { version = "3.0.0", git = "https://github.com/paritytech/substrate" } 37 | pallet-timestamp = { version = "3.0.0", git = "https://github.com/paritytech/substrate" } 38 | pallet-transaction-payment = { version = "3.0.0", git = "https://github.com/paritytech/substrate" } 39 | pallet-treasury = { version = "3.0.0", git = "https://github.com/paritytech/substrate" } 40 | sp-application-crypto = { version = "3.0.0", git = "https://github.com/paritytech/substrate" } 41 | sp-consensus-babe = { version = "0.9.0", git = "https://github.com/paritytech/substrate" } 42 | sp-runtime = { version = "3.0.0", git = "https://github.com/paritytech/substrate" } 43 | sp-externalities = { version = "0.9.0", git = "https://github.com/paritytech/substrate" } 44 | substrate-test-client = { version = "2.0.0", git = "https://github.com/paritytech/substrate" } 45 | wat = "1.0" 46 | futures = "0.3.9" 47 | 48 | [features] 49 | wasmtime = [ 50 | "sc-executor/wasmtime", 51 | ] 52 | wasmi-errno = [ 53 | "sc-executor/wasmi-errno", 54 | ] 55 | stress-test = [] 56 | 57 | [[bench]] 58 | name = "bench" 59 | harness = false 60 | -------------------------------------------------------------------------------- /executor/benches/bench.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2019 TrustBase Network 2 | // This file is part of TrustBase library. 3 | // 4 | // The TrustBase library is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU Lesser General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // The TrustBase library is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU Lesser General Public License for more details. 13 | 14 | use codec::{Decode, Encode}; 15 | use criterion::{BatchSize, Criterion, criterion_group, criterion_main}; 16 | use node_executor::Executor; 17 | use node_primitives::{BlockNumber, Hash}; 18 | use node_runtime::{ 19 | Block, BuildStorage, Call, CheckedExtrinsic, GenesisConfig, Header, UncheckedExtrinsic, 20 | }; 21 | use node_runtime::constants::currency::*; 22 | use node_testing::keyring::*; 23 | use sp_core::{NativeOrEncoded, NeverNativeValue}; 24 | use sp_core::storage::well_known_keys; 25 | use sp_core::traits::{CodeExecutor, RuntimeCode}; 26 | use frame_support::Hashable; 27 | use sp_state_machine::TestExternalities as CoreTestExternalities; 28 | use sc_executor::{NativeExecutor, RuntimeInfo, WasmExecutionMethod, Externalities}; 29 | use sp_runtime::traits::BlakeTwo256; 30 | 31 | criterion_group!(benches, bench_execute_block); 32 | criterion_main!(benches); 33 | 34 | /// The wasm runtime code. 35 | pub fn compact_code_unwrap() -> &'static [u8] { 36 | node_runtime::WASM_BINARY.expect("Development wasm binary is not available. \ 37 | Testing is only supported with the flag disabled.") 38 | } 39 | 40 | const GENESIS_HASH: [u8; 32] = [69u8; 32]; 41 | 42 | const TRANSACTION_VERSION: u32 = node_runtime::VERSION.transaction_version; 43 | 44 | const SPEC_VERSION: u32 = node_runtime::VERSION.spec_version; 45 | 46 | const HEAP_PAGES: u64 = 20; 47 | 48 | type TestExternalities = CoreTestExternalities; 49 | 50 | #[derive(Debug)] 51 | enum ExecutionMethod { 52 | Native, 53 | Wasm(WasmExecutionMethod), 54 | } 55 | 56 | fn sign(xt: CheckedExtrinsic) -> UncheckedExtrinsic { 57 | node_testing::keyring::sign(xt, SPEC_VERSION, TRANSACTION_VERSION, GENESIS_HASH) 58 | } 59 | 60 | fn new_test_ext(genesis_config: &GenesisConfig) -> TestExternalities { 61 | let mut test_ext = TestExternalities::new_with_code( 62 | compact_code_unwrap(), 63 | genesis_config.build_storage().unwrap(), 64 | ); 65 | test_ext.ext().place_storage(well_known_keys::HEAP_PAGES.to_vec(), Some(HEAP_PAGES.encode())); 66 | test_ext 67 | } 68 | 69 | fn construct_block( 70 | executor: &NativeExecutor, 71 | ext: &mut E, 72 | number: BlockNumber, 73 | parent_hash: Hash, 74 | extrinsics: Vec, 75 | ) -> (Vec, Hash) { 76 | use sp_trie::{TrieConfiguration, trie_types::Layout}; 77 | 78 | // sign extrinsics. 79 | let extrinsics = extrinsics.into_iter().map(sign).collect::>(); 80 | 81 | // calculate the header fields that we can. 82 | let extrinsics_root = Layout::::ordered_trie_root( 83 | extrinsics.iter().map(Encode::encode) 84 | ).to_fixed_bytes() 85 | .into(); 86 | 87 | let header = Header { 88 | parent_hash, 89 | number, 90 | extrinsics_root, 91 | state_root: Default::default(), 92 | digest: Default::default(), 93 | }; 94 | 95 | let runtime_code = RuntimeCode { 96 | code_fetcher: &sp_core::traits::WrappedRuntimeCode(compact_code_unwrap().into()), 97 | hash: vec![1, 2, 3], 98 | heap_pages: None, 99 | }; 100 | 101 | // execute the block to get the real header. 102 | executor.call:: _>( 103 | ext, 104 | &runtime_code, 105 | "Core_initialize_block", 106 | &header.encode(), 107 | true, 108 | None, 109 | ).0.unwrap(); 110 | 111 | for i in extrinsics.iter() { 112 | executor.call:: _>( 113 | ext, 114 | &runtime_code, 115 | "BlockBuilder_apply_extrinsic", 116 | &i.encode(), 117 | true, 118 | None, 119 | ).0.unwrap(); 120 | } 121 | 122 | let header = match executor.call:: _>( 123 | ext, 124 | &runtime_code, 125 | "BlockBuilder_finalize_block", 126 | &[0u8;0], 127 | true, 128 | None, 129 | ).0.unwrap() { 130 | NativeOrEncoded::Native(_) => unreachable!(), 131 | NativeOrEncoded::Encoded(h) => Header::decode(&mut &h[..]).unwrap(), 132 | }; 133 | 134 | let hash = header.blake2_256(); 135 | (Block { header, extrinsics }.encode(), hash.into()) 136 | } 137 | 138 | 139 | fn test_blocks(genesis_config: &GenesisConfig, executor: &NativeExecutor) 140 | -> Vec<(Vec, Hash)> 141 | { 142 | let mut test_ext = new_test_ext(genesis_config); 143 | let mut block1_extrinsics = vec![ 144 | CheckedExtrinsic { 145 | signed: None, 146 | function: Call::Timestamp(pallet_timestamp::Call::set(0)), 147 | }, 148 | ]; 149 | block1_extrinsics.extend((0..20).map(|i| { 150 | CheckedExtrinsic { 151 | signed: Some((alice(), signed_extra(i, 0))), 152 | function: Call::Balances(pallet_balances::Call::transfer(bob().into(), 1 * DOLLARS)), 153 | } 154 | })); 155 | let block1 = construct_block( 156 | executor, 157 | &mut test_ext.ext(), 158 | 1, 159 | GENESIS_HASH.into(), 160 | block1_extrinsics, 161 | ); 162 | 163 | vec![block1] 164 | } 165 | 166 | fn bench_execute_block(c: &mut Criterion) { 167 | let mut group = c.benchmark_group("execute blocks"); 168 | let execution_methods = vec![ 169 | ExecutionMethod::Native, 170 | ExecutionMethod::Wasm(WasmExecutionMethod::Interpreted), 171 | #[cfg(feature = "wasmtime")] 172 | ExecutionMethod::Wasm(WasmExecutionMethod::Compiled), 173 | ]; 174 | 175 | for strategy in execution_methods { 176 | group.bench_function( 177 | format!("{:?}", strategy), 178 | |b| { 179 | let genesis_config = node_testing::genesis::config(false, Some(compact_code_unwrap())); 180 | let (use_native, wasm_method) = match strategy { 181 | ExecutionMethod::Native => (true, WasmExecutionMethod::Interpreted), 182 | ExecutionMethod::Wasm(wasm_method) => (false, wasm_method), 183 | }; 184 | 185 | let executor = NativeExecutor::new(wasm_method, None, 8); 186 | let runtime_code = RuntimeCode { 187 | code_fetcher: &sp_core::traits::WrappedRuntimeCode(compact_code_unwrap().into()), 188 | hash: vec![1, 2, 3], 189 | heap_pages: None, 190 | }; 191 | 192 | // Get the runtime version to initialize the runtimes cache. 193 | { 194 | let mut test_ext = new_test_ext(&genesis_config); 195 | executor.runtime_version(&mut test_ext.ext(), &runtime_code).unwrap(); 196 | } 197 | 198 | let blocks = test_blocks(&genesis_config, &executor); 199 | 200 | b.iter_batched_ref( 201 | || new_test_ext(&genesis_config), 202 | |test_ext| { 203 | for block in blocks.iter() { 204 | executor.call:: _>( 205 | &mut test_ext.ext(), 206 | &runtime_code, 207 | "Core_execute_block", 208 | &block.0, 209 | use_native, 210 | None, 211 | ).0.unwrap(); 212 | } 213 | }, 214 | BatchSize::LargeInput, 215 | ); 216 | }, 217 | ); 218 | } 219 | } 220 | -------------------------------------------------------------------------------- /executor/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2019 TrustBase Network 2 | // This file is part of TrustBase library. 3 | // 4 | // The TrustBase library is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU Lesser General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // The TrustBase library is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU Lesser General Public License for more details. 13 | 14 | //! A `CodeExecutor` specialization which uses natively compiled runtime when the wasm to be 15 | //! executed is equivalent to the natively compiled code. 16 | 17 | pub use sc_executor::NativeExecutor; 18 | use sc_executor::native_executor_instance; 19 | 20 | // Declare an instance of the native executor named `Executor`. Include the wasm binary as the 21 | // equivalent wasm code. 22 | native_executor_instance!( 23 | pub Executor, 24 | node_runtime::api::dispatch, 25 | node_runtime::native_version, 26 | frame_benchmarking::benchmarking::HostFunctions, 27 | ); 28 | -------------------------------------------------------------------------------- /executor/tests/basic.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2019 TrustBase Network 2 | // This file is part of TrustBase library. 3 | // 4 | // The TrustBase library is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU Lesser General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // The TrustBase library is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU Lesser General Public License for more details. 13 | 14 | use codec::{Encode, Decode, Joiner}; 15 | use frame_support::{ 16 | traits::Currency, 17 | weights::{GetDispatchInfo, DispatchInfo, DispatchClass}, 18 | }; 19 | use sp_core::{NeverNativeValue, traits::Externalities, storage::well_known_keys}; 20 | use sp_runtime::{ 21 | ApplyExtrinsicResult, 22 | traits::Hash as HashT, 23 | transaction_validity::InvalidTransaction, 24 | }; 25 | use frame_system::{self, EventRecord, Phase, AccountInfo}; 26 | 27 | use node_runtime::{ 28 | Header, Block, UncheckedExtrinsic, CheckedExtrinsic, Call, Runtime, Balances, 29 | System, TransactionPayment, Event, 30 | constants::{time::SLOT_DURATION, currency::*}, 31 | }; 32 | use node_primitives::{Balance, Hash}; 33 | use wat; 34 | use node_testing::keyring::*; 35 | 36 | pub mod common; 37 | use self::common::{*, sign}; 38 | 39 | /// The wasm runtime binary which hasn't undergone the compacting process. 40 | /// 41 | /// The idea here is to pass it as the current runtime code to the executor so the executor will 42 | /// have to execute provided wasm code instead of the native equivalent. This trick is used to 43 | /// test code paths that differ between native and wasm versions. 44 | pub fn bloaty_code_unwrap() -> &'static [u8] { 45 | node_runtime::WASM_BINARY_BLOATY.expect("Development wasm binary is not available. \ 46 | Testing is only supported with the flag disabled.") 47 | } 48 | 49 | /// Default transfer fee. This will use the same logic that is implemented in transaction-payment module. 50 | /// 51 | /// Note that reads the multiplier from storage directly, hence to get the fee of `extrinsic` 52 | /// at block `n`, it must be called prior to executing block `n` to do the calculation with the 53 | /// correct multiplier. 54 | fn transfer_fee(extrinsic: &E) -> Balance { 55 | TransactionPayment::compute_fee( 56 | extrinsic.encode().len() as u32, 57 | &default_transfer_call().get_dispatch_info(), 58 | 0, 59 | ) 60 | } 61 | 62 | fn xt() -> UncheckedExtrinsic { 63 | sign(CheckedExtrinsic { 64 | signed: Some((alice(), signed_extra(0, 0))), 65 | function: Call::Balances(default_transfer_call()), 66 | }) 67 | } 68 | 69 | fn set_heap_pages(ext: &mut E, heap_pages: u64) { 70 | ext.place_storage(well_known_keys::HEAP_PAGES.to_vec(), Some(heap_pages.encode())); 71 | } 72 | 73 | fn changes_trie_block() -> (Vec, Hash) { 74 | let time = 42 * 1000; 75 | construct_block( 76 | &mut new_test_ext(compact_code_unwrap(), true), 77 | 1, 78 | GENESIS_HASH.into(), 79 | vec![ 80 | CheckedExtrinsic { 81 | signed: None, 82 | function: Call::Timestamp(pallet_timestamp::Call::set(time)), 83 | }, 84 | CheckedExtrinsic { 85 | signed: Some((alice(), signed_extra(0, 0))), 86 | function: Call::Balances(pallet_balances::Call::transfer(bob().into(), 69 * DOLLARS)), 87 | }, 88 | ], 89 | (time / SLOT_DURATION).into(), 90 | ) 91 | } 92 | 93 | /// block 1 and 2 must be created together to ensure transactions are only signed once (since they 94 | /// are not guaranteed to be deterministic) and to ensure that the correct state is propagated 95 | /// from block1's execution to block2 to derive the correct storage_root. 96 | fn blocks() -> ((Vec, Hash), (Vec, Hash)) { 97 | let mut t = new_test_ext(compact_code_unwrap(), false); 98 | let time1 = 42 * 1000; 99 | let block1 = construct_block( 100 | &mut t, 101 | 1, 102 | GENESIS_HASH.into(), 103 | vec![ 104 | CheckedExtrinsic { 105 | signed: None, 106 | function: Call::Timestamp(pallet_timestamp::Call::set(time1)), 107 | }, 108 | CheckedExtrinsic { 109 | signed: Some((alice(), signed_extra(0, 0))), 110 | function: Call::Balances(pallet_balances::Call::transfer(bob().into(), 69 * DOLLARS)), 111 | }, 112 | ], 113 | (time1 / SLOT_DURATION).into(), 114 | ); 115 | let time2 = 52 * 1000; 116 | let block2 = construct_block( 117 | &mut t, 118 | 2, 119 | block1.1.clone(), 120 | vec![ 121 | CheckedExtrinsic { 122 | signed: None, 123 | function: Call::Timestamp(pallet_timestamp::Call::set(time2)), 124 | }, 125 | CheckedExtrinsic { 126 | signed: Some((bob(), signed_extra(0, 0))), 127 | function: Call::Balances(pallet_balances::Call::transfer(alice().into(), 5 * DOLLARS)), 128 | }, 129 | CheckedExtrinsic { 130 | signed: Some((alice(), signed_extra(1, 0))), 131 | function: Call::Balances(pallet_balances::Call::transfer(bob().into(), 15 * DOLLARS)), 132 | } 133 | ], 134 | (time2 / SLOT_DURATION).into(), 135 | ); 136 | 137 | // session change => consensus authorities change => authorities change digest item appears 138 | let digest = Header::decode(&mut &block2.0[..]).unwrap().digest; 139 | assert_eq!(digest.logs().len(), 1 /* Just babe slot */); 140 | 141 | (block1, block2) 142 | } 143 | 144 | fn block_with_size(time: u64, nonce: u32, size: usize) -> (Vec, Hash) { 145 | construct_block( 146 | &mut new_test_ext(compact_code_unwrap(), false), 147 | 1, 148 | GENESIS_HASH.into(), 149 | vec![ 150 | CheckedExtrinsic { 151 | signed: None, 152 | function: Call::Timestamp(pallet_timestamp::Call::set(time * 1000)), 153 | }, 154 | CheckedExtrinsic { 155 | signed: Some((alice(), signed_extra(nonce, 0))), 156 | function: Call::System(frame_system::Call::remark(vec![0; size])), 157 | } 158 | ], 159 | (time * 1000 / SLOT_DURATION).into(), 160 | ) 161 | } 162 | 163 | #[test] 164 | fn panic_execution_with_foreign_code_gives_error() { 165 | let mut t = new_test_ext(bloaty_code_unwrap(), false); 166 | t.insert( 167 | >::hashed_key_for(alice()), 168 | (69u128, 0u32, 0u128, 0u128, 0u128).encode() 169 | ); 170 | t.insert(>::hashed_key().to_vec(), 69_u128.encode()); 171 | t.insert(>::hashed_key_for(0), vec![0u8; 32]); 172 | 173 | let r = executor_call:: _>( 174 | &mut t, 175 | "Core_initialize_block", 176 | &vec![].and(&from_block_number(1u32)), 177 | true, 178 | None, 179 | ).0; 180 | assert!(r.is_ok()); 181 | let v = executor_call:: _>( 182 | &mut t, 183 | "BlockBuilder_apply_extrinsic", 184 | &vec![].and(&xt()), 185 | true, 186 | None, 187 | ).0.unwrap(); 188 | let r = ApplyExtrinsicResult::decode(&mut &v.as_encoded()[..]).unwrap(); 189 | assert_eq!(r, Err(InvalidTransaction::Payment.into())); 190 | } 191 | 192 | #[test] 193 | fn bad_extrinsic_with_native_equivalent_code_gives_error() { 194 | let mut t = new_test_ext(compact_code_unwrap(), false); 195 | t.insert( 196 | >::hashed_key_for(alice()), 197 | (0u32, 0u32, 0u32, 69u128, 0u128, 0u128, 0u128).encode() 198 | ); 199 | t.insert(>::hashed_key().to_vec(), 69_u128.encode()); 200 | t.insert(>::hashed_key_for(0), vec![0u8; 32]); 201 | 202 | let r = executor_call:: _>( 203 | &mut t, 204 | "Core_initialize_block", 205 | &vec![].and(&from_block_number(1u32)), 206 | true, 207 | None, 208 | ).0; 209 | assert!(r.is_ok()); 210 | let v = executor_call:: _>( 211 | &mut t, 212 | "BlockBuilder_apply_extrinsic", 213 | &vec![].and(&xt()), 214 | true, 215 | None, 216 | ).0.unwrap(); 217 | let r = ApplyExtrinsicResult::decode(&mut &v.as_encoded()[..]).unwrap(); 218 | assert_eq!(r, Err(InvalidTransaction::Payment.into())); 219 | } 220 | 221 | #[test] 222 | fn successful_execution_with_native_equivalent_code_gives_ok() { 223 | let mut t = new_test_ext(compact_code_unwrap(), false); 224 | t.insert( 225 | >::hashed_key_for(alice()), 226 | AccountInfo::<::Index, _> { 227 | data: (111 * DOLLARS, 0u128, 0u128, 0u128), 228 | .. Default::default() 229 | }.encode(), 230 | ); 231 | t.insert( 232 | >::hashed_key_for(bob()), 233 | AccountInfo::<::Index, _> { 234 | data: (0 * DOLLARS, 0u128, 0u128, 0u128), 235 | .. Default::default() 236 | }.encode(), 237 | ); 238 | t.insert( 239 | >::hashed_key().to_vec(), 240 | (111 * DOLLARS).encode() 241 | ); 242 | t.insert(>::hashed_key_for(0), vec![0u8; 32]); 243 | 244 | let r = executor_call:: _>( 245 | &mut t, 246 | "Core_initialize_block", 247 | &vec![].and(&from_block_number(1u32)), 248 | true, 249 | None, 250 | ).0; 251 | assert!(r.is_ok()); 252 | 253 | let fees = t.execute_with(|| transfer_fee(&xt())); 254 | 255 | let r = executor_call:: _>( 256 | &mut t, 257 | "BlockBuilder_apply_extrinsic", 258 | &vec![].and(&xt()), 259 | true, 260 | None, 261 | ).0; 262 | assert!(r.is_ok()); 263 | 264 | t.execute_with(|| { 265 | assert_eq!(Balances::total_balance(&alice()), 42 * DOLLARS - fees); 266 | assert_eq!(Balances::total_balance(&bob()), 69 * DOLLARS); 267 | }); 268 | } 269 | 270 | #[test] 271 | fn successful_execution_with_foreign_code_gives_ok() { 272 | let mut t = new_test_ext(bloaty_code_unwrap(), false); 273 | t.insert( 274 | >::hashed_key_for(alice()), 275 | AccountInfo::<::Index, _> { 276 | data: (111 * DOLLARS, 0u128, 0u128, 0u128), 277 | .. Default::default() 278 | }.encode(), 279 | ); 280 | t.insert( 281 | >::hashed_key_for(bob()), 282 | AccountInfo::<::Index, _> { 283 | data: (0 * DOLLARS, 0u128, 0u128, 0u128), 284 | .. Default::default() 285 | }.encode(), 286 | ); 287 | t.insert( 288 | >::hashed_key().to_vec(), 289 | (111 * DOLLARS).encode() 290 | ); 291 | t.insert(>::hashed_key_for(0), vec![0u8; 32]); 292 | 293 | let r = executor_call:: _>( 294 | &mut t, 295 | "Core_initialize_block", 296 | &vec![].and(&from_block_number(1u32)), 297 | true, 298 | None, 299 | ).0; 300 | assert!(r.is_ok()); 301 | 302 | let fees = t.execute_with(|| transfer_fee(&xt())); 303 | 304 | let r = executor_call:: _>( 305 | &mut t, 306 | "BlockBuilder_apply_extrinsic", 307 | &vec![].and(&xt()), 308 | true, 309 | None, 310 | ).0; 311 | assert!(r.is_ok()); 312 | 313 | t.execute_with(|| { 314 | assert_eq!(Balances::total_balance(&alice()), 42 * DOLLARS - fees); 315 | assert_eq!(Balances::total_balance(&bob()), 69 * DOLLARS); 316 | }); 317 | } 318 | 319 | #[test] 320 | fn full_native_block_import_works() { 321 | let mut t = new_test_ext(compact_code_unwrap(), false); 322 | 323 | let (block1, block2) = blocks(); 324 | 325 | let mut alice_last_known_balance: Balance = Default::default(); 326 | let mut fees = t.execute_with(|| transfer_fee(&xt())); 327 | 328 | let transfer_weight = default_transfer_call().get_dispatch_info().weight; 329 | let timestamp_weight = pallet_timestamp::Call::set::(Default::default()).get_dispatch_info().weight; 330 | 331 | executor_call:: _>( 332 | &mut t, 333 | "Core_execute_block", 334 | &block1.0, 335 | true, 336 | None, 337 | ).0.unwrap(); 338 | 339 | t.execute_with(|| { 340 | assert_eq!(Balances::total_balance(&alice()), 42 * DOLLARS - fees); 341 | assert_eq!(Balances::total_balance(&bob()), 169 * DOLLARS); 342 | alice_last_known_balance = Balances::total_balance(&alice()); 343 | let events = vec![ 344 | EventRecord { 345 | phase: Phase::ApplyExtrinsic(0), 346 | event: Event::System(frame_system::Event::ExtrinsicSuccess( 347 | DispatchInfo { weight: timestamp_weight, class: DispatchClass::Mandatory, ..Default::default() } 348 | )), 349 | topics: vec![], 350 | }, 351 | EventRecord { 352 | phase: Phase::ApplyExtrinsic(1), 353 | event: Event::Balances(pallet_balances::Event::Transfer( 354 | alice().into(), 355 | bob().into(), 356 | 69 * DOLLARS, 357 | )), 358 | topics: vec![], 359 | }, 360 | EventRecord { 361 | phase: Phase::ApplyExtrinsic(1), 362 | event: Event::Treasury(pallet_treasury::RawEvent::Deposit(fees * 8 / 10)), 363 | topics: vec![], 364 | }, 365 | EventRecord { 366 | phase: Phase::ApplyExtrinsic(1), 367 | event: Event::System(frame_system::Event::ExtrinsicSuccess( 368 | DispatchInfo { weight: transfer_weight, ..Default::default() } 369 | )), 370 | topics: vec![], 371 | }, 372 | ]; 373 | assert_eq!(System::events(), events); 374 | }); 375 | 376 | fees = t.execute_with(|| transfer_fee(&xt())); 377 | 378 | executor_call:: _>( 379 | &mut t, 380 | "Core_execute_block", 381 | &block2.0, 382 | true, 383 | None, 384 | ).0.unwrap(); 385 | 386 | t.execute_with(|| { 387 | assert_eq!( 388 | Balances::total_balance(&alice()), 389 | alice_last_known_balance - 10 * DOLLARS - fees, 390 | ); 391 | assert_eq!( 392 | Balances::total_balance(&bob()), 393 | 179 * DOLLARS - fees, 394 | ); 395 | let events = vec![ 396 | EventRecord { 397 | phase: Phase::ApplyExtrinsic(0), 398 | event: Event::System(frame_system::Event::ExtrinsicSuccess( 399 | DispatchInfo { weight: timestamp_weight, class: DispatchClass::Mandatory, ..Default::default() } 400 | )), 401 | topics: vec![], 402 | }, 403 | EventRecord { 404 | phase: Phase::ApplyExtrinsic(1), 405 | event: Event::Balances( 406 | pallet_balances::Event::Transfer( 407 | bob().into(), 408 | alice().into(), 409 | 5 * DOLLARS, 410 | ) 411 | ), 412 | topics: vec![], 413 | }, 414 | EventRecord { 415 | phase: Phase::ApplyExtrinsic(1), 416 | event: Event::Treasury(pallet_treasury::RawEvent::Deposit(fees * 8 / 10)), 417 | topics: vec![], 418 | }, 419 | EventRecord { 420 | phase: Phase::ApplyExtrinsic(1), 421 | event: Event::System(frame_system::Event::ExtrinsicSuccess( 422 | DispatchInfo { weight: transfer_weight, ..Default::default() } 423 | )), 424 | topics: vec![], 425 | }, 426 | EventRecord { 427 | phase: Phase::ApplyExtrinsic(2), 428 | event: Event::Balances( 429 | pallet_balances::Event::Transfer( 430 | alice().into(), 431 | bob().into(), 432 | 15 * DOLLARS, 433 | ) 434 | ), 435 | topics: vec![], 436 | }, 437 | EventRecord { 438 | phase: Phase::ApplyExtrinsic(2), 439 | event: Event::Treasury(pallet_treasury::RawEvent::Deposit(fees * 8 / 10)), 440 | topics: vec![], 441 | }, 442 | EventRecord { 443 | phase: Phase::ApplyExtrinsic(2), 444 | event: Event::System(frame_system::Event::ExtrinsicSuccess( 445 | DispatchInfo { weight: transfer_weight, ..Default::default() } 446 | )), 447 | topics: vec![], 448 | }, 449 | ]; 450 | assert_eq!(System::events(), events); 451 | }); 452 | } 453 | 454 | #[test] 455 | fn full_wasm_block_import_works() { 456 | let mut t = new_test_ext(compact_code_unwrap(), false); 457 | 458 | let (block1, block2) = blocks(); 459 | 460 | let mut alice_last_known_balance: Balance = Default::default(); 461 | let mut fees = t.execute_with(|| transfer_fee(&xt())); 462 | 463 | executor_call:: _>( 464 | &mut t, 465 | "Core_execute_block", 466 | &block1.0, 467 | false, 468 | None, 469 | ).0.unwrap(); 470 | 471 | t.execute_with(|| { 472 | assert_eq!(Balances::total_balance(&alice()), 42 * DOLLARS - fees); 473 | assert_eq!(Balances::total_balance(&bob()), 169 * DOLLARS); 474 | alice_last_known_balance = Balances::total_balance(&alice()); 475 | }); 476 | 477 | fees = t.execute_with(|| transfer_fee(&xt())); 478 | 479 | executor_call:: _>( 480 | &mut t, 481 | "Core_execute_block", 482 | &block2.0, 483 | false, 484 | None, 485 | ).0.unwrap(); 486 | 487 | t.execute_with(|| { 488 | assert_eq!( 489 | Balances::total_balance(&alice()), 490 | alice_last_known_balance - 10 * DOLLARS - fees, 491 | ); 492 | assert_eq!( 493 | Balances::total_balance(&bob()), 494 | 179 * DOLLARS - 1 * fees, 495 | ); 496 | }); 497 | } 498 | 499 | const CODE_TRANSFER: &str = r#" 500 | (module 501 | ;; seal_call( 502 | ;; callee_ptr: u32, 503 | ;; callee_len: u32, 504 | ;; gas: u64, 505 | ;; value_ptr: u32, 506 | ;; value_len: u32, 507 | ;; input_data_ptr: u32, 508 | ;; input_data_len: u32, 509 | ;; output_ptr: u32, 510 | ;; output_len_ptr: u32 511 | ;; ) -> u32 512 | (import "seal0" "seal_call" (func $seal_call (param i32 i32 i64 i32 i32 i32 i32 i32 i32) (result i32))) 513 | (import "seal0" "seal_input" (func $seal_input (param i32 i32))) 514 | (import "env" "memory" (memory 1 1)) 515 | (func (export "deploy") 516 | ) 517 | (func (export "call") 518 | (block $fail 519 | ;; Load input data to contract memory 520 | (call $seal_input 521 | (i32.const 0) 522 | (i32.const 52) 523 | ) 524 | 525 | ;; fail if the input size is not != 4 526 | (br_if $fail 527 | (i32.ne 528 | (i32.const 4) 529 | (i32.load (i32.const 52)) 530 | ) 531 | ) 532 | 533 | (br_if $fail 534 | (i32.ne 535 | (i32.load8_u (i32.const 0)) 536 | (i32.const 0) 537 | ) 538 | ) 539 | (br_if $fail 540 | (i32.ne 541 | (i32.load8_u (i32.const 1)) 542 | (i32.const 1) 543 | ) 544 | ) 545 | (br_if $fail 546 | (i32.ne 547 | (i32.load8_u (i32.const 2)) 548 | (i32.const 2) 549 | ) 550 | ) 551 | (br_if $fail 552 | (i32.ne 553 | (i32.load8_u (i32.const 3)) 554 | (i32.const 3) 555 | ) 556 | ) 557 | 558 | (drop 559 | (call $seal_call 560 | (i32.const 4) ;; Pointer to "callee" address. 561 | (i32.const 32) ;; Length of "callee" address. 562 | (i64.const 0) ;; How much gas to devote for the execution. 0 = all. 563 | (i32.const 36) ;; Pointer to the buffer with value to transfer 564 | (i32.const 16) ;; Length of the buffer with value to transfer. 565 | (i32.const 0) ;; Pointer to input data buffer address 566 | (i32.const 0) ;; Length of input data buffer 567 | (i32.const 4294967295) ;; u32 max value is the sentinel value: do not copy output 568 | (i32.const 0) ;; Length is ignored in this case 569 | ) 570 | ) 571 | 572 | (return) 573 | ) 574 | unreachable 575 | ) 576 | ;; Destination AccountId to transfer the funds. 577 | ;; Represented by H256 (32 bytes long) in little endian. 578 | (data (i32.const 4) 579 | "\09\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00" 580 | "\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00" 581 | "\00\00\00\00" 582 | ) 583 | ;; Amount of value to transfer. 584 | ;; Represented by u128 (16 bytes long) in little endian. 585 | (data (i32.const 36) 586 | "\06\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00" 587 | "\00\00" 588 | ) 589 | ;; Length of the input buffer 590 | (data (i32.const 52) "\04") 591 | ) 592 | "#; 593 | 594 | #[test] 595 | fn deploying_wasm_contract_should_work() { 596 | let transfer_code = wat::parse_str(CODE_TRANSFER).unwrap(); 597 | let transfer_ch = ::Hashing::hash(&transfer_code); 598 | 599 | let addr = pallet_contracts::Pallet::::contract_address( 600 | &charlie(), 601 | &transfer_ch, 602 | &[], 603 | ); 604 | 605 | let subsistence = pallet_contracts::Pallet::::subsistence_threshold(); 606 | 607 | let time = 42 * 1000; 608 | let b = construct_block( 609 | &mut new_test_ext(compact_code_unwrap(), false), 610 | 1, 611 | GENESIS_HASH.into(), 612 | vec![ 613 | CheckedExtrinsic { 614 | signed: None, 615 | function: Call::Timestamp(pallet_timestamp::Call::set(time)), 616 | }, 617 | CheckedExtrinsic { 618 | signed: Some((charlie(), signed_extra(0, 0))), 619 | function: Call::Contracts( 620 | pallet_contracts::Call::instantiate_with_code::( 621 | 1000 * DOLLARS + subsistence, 622 | 500_000_000, 623 | transfer_code, 624 | Vec::new(), 625 | Vec::new(), 626 | ) 627 | ), 628 | }, 629 | CheckedExtrinsic { 630 | signed: Some((charlie(), signed_extra(1, 0))), 631 | function: Call::Contracts( 632 | pallet_contracts::Call::call::( 633 | sp_runtime::MultiAddress::Id(addr.clone()), 634 | 10, 635 | 500_000_000, 636 | vec![0x00, 0x01, 0x02, 0x03] 637 | ) 638 | ), 639 | }, 640 | ], 641 | (time / SLOT_DURATION).into(), 642 | ); 643 | 644 | let mut t = new_test_ext(compact_code_unwrap(), false); 645 | 646 | executor_call:: _>( 647 | &mut t, 648 | "Core_execute_block", 649 | &b.0, 650 | false, 651 | None, 652 | ).0.unwrap(); 653 | 654 | t.execute_with(|| { 655 | // Verify that the contract does exist by querying some of its storage items 656 | // It does not matter that the storage item itself does not exist. 657 | assert!( 658 | &pallet_contracts::Pallet::::get_storage(addr, Default::default()).is_ok() 659 | ); 660 | }); 661 | } 662 | 663 | #[test] 664 | fn wasm_big_block_import_fails() { 665 | let mut t = new_test_ext(compact_code_unwrap(), false); 666 | 667 | set_heap_pages(&mut t.ext(), 4); 668 | 669 | let result = executor_call:: _>( 670 | &mut t, 671 | "Core_execute_block", 672 | &block_with_size(42, 0, 120_000).0, 673 | false, 674 | None, 675 | ).0; 676 | assert!(result.is_err()); // Err(Wasmi(Trap(Trap { kind: Host(AllocatorOutOfSpace) }))) 677 | } 678 | 679 | #[test] 680 | fn native_big_block_import_succeeds() { 681 | let mut t = new_test_ext(compact_code_unwrap(), false); 682 | 683 | executor_call:: _>( 684 | &mut t, 685 | "Core_execute_block", 686 | &block_with_size(42, 0, 120_000).0, 687 | true, 688 | None, 689 | ).0.unwrap(); 690 | } 691 | 692 | #[test] 693 | fn native_big_block_import_fails_on_fallback() { 694 | let mut t = new_test_ext(compact_code_unwrap(), false); 695 | 696 | // We set the heap pages to 8 because we know that should give an OOM in WASM with the given block. 697 | set_heap_pages(&mut t.ext(), 8); 698 | 699 | assert!( 700 | executor_call:: _>( 701 | &mut t, 702 | "Core_execute_block", 703 | &block_with_size(42, 0, 120_000).0, 704 | false, 705 | None, 706 | ).0.is_err() 707 | ); 708 | } 709 | 710 | #[test] 711 | fn panic_execution_gives_error() { 712 | let mut t = new_test_ext(bloaty_code_unwrap(), false); 713 | t.insert( 714 | >::hashed_key_for(alice()), 715 | AccountInfo::<::Index, _> { 716 | data: (0 * DOLLARS, 0u128, 0u128, 0u128), 717 | .. Default::default() 718 | }.encode(), 719 | ); 720 | t.insert(>::hashed_key().to_vec(), 0_u128.encode()); 721 | t.insert(>::hashed_key_for(0), vec![0u8; 32]); 722 | 723 | let r = executor_call:: _>( 724 | &mut t, 725 | "Core_initialize_block", 726 | &vec![].and(&from_block_number(1u32)), 727 | false, 728 | None, 729 | ).0; 730 | assert!(r.is_ok()); 731 | let r = executor_call:: _>( 732 | &mut t, 733 | "BlockBuilder_apply_extrinsic", 734 | &vec![].and(&xt()), 735 | false, 736 | None, 737 | ).0.unwrap().into_encoded(); 738 | let r = ApplyExtrinsicResult::decode(&mut &r[..]).unwrap(); 739 | assert_eq!(r, Err(InvalidTransaction::Payment.into())); 740 | } 741 | 742 | #[test] 743 | fn successful_execution_gives_ok() { 744 | let mut t = new_test_ext(compact_code_unwrap(), false); 745 | t.insert( 746 | >::hashed_key_for(alice()), 747 | AccountInfo::<::Index, _> { 748 | data: (111 * DOLLARS, 0u128, 0u128, 0u128), 749 | .. Default::default() 750 | }.encode(), 751 | ); 752 | t.insert( 753 | >::hashed_key_for(bob()), 754 | AccountInfo::<::Index, _> { 755 | data: (0 * DOLLARS, 0u128, 0u128, 0u128), 756 | .. Default::default() 757 | }.encode(), 758 | ); 759 | t.insert( 760 | >::hashed_key().to_vec(), 761 | (111 * DOLLARS).encode() 762 | ); 763 | t.insert(>::hashed_key_for(0), vec![0u8; 32]); 764 | 765 | let r = executor_call:: _>( 766 | &mut t, 767 | "Core_initialize_block", 768 | &vec![].and(&from_block_number(1u32)), 769 | false, 770 | None, 771 | ).0; 772 | assert!(r.is_ok()); 773 | t.execute_with(|| { 774 | assert_eq!(Balances::total_balance(&alice()), 111 * DOLLARS); 775 | }); 776 | 777 | let fees = t.execute_with(|| transfer_fee(&xt())); 778 | 779 | let r = executor_call:: _>( 780 | &mut t, 781 | "BlockBuilder_apply_extrinsic", 782 | &vec![].and(&xt()), 783 | false, 784 | None, 785 | ).0.unwrap().into_encoded(); 786 | ApplyExtrinsicResult::decode(&mut &r[..]) 787 | .unwrap() 788 | .expect("Extrinsic could not be applied") 789 | .expect("Extrinsic failed"); 790 | 791 | t.execute_with(|| { 792 | assert_eq!(Balances::total_balance(&alice()), 42 * DOLLARS - fees); 793 | assert_eq!(Balances::total_balance(&bob()), 69 * DOLLARS); 794 | }); 795 | } 796 | 797 | #[test] 798 | fn full_native_block_import_works_with_changes_trie() { 799 | let block1 = changes_trie_block(); 800 | let block_data = block1.0; 801 | let block = Block::decode(&mut &block_data[..]).unwrap(); 802 | 803 | let mut t = new_test_ext(compact_code_unwrap(), true); 804 | executor_call:: _>( 805 | &mut t, 806 | "Core_execute_block", 807 | &block.encode(), 808 | true, 809 | None, 810 | ).0.unwrap(); 811 | 812 | assert!(t.ext().storage_changes_root(&GENESIS_HASH).unwrap().is_some()); 813 | } 814 | 815 | #[test] 816 | fn full_wasm_block_import_works_with_changes_trie() { 817 | let block1 = changes_trie_block(); 818 | 819 | let mut t = new_test_ext(compact_code_unwrap(), true); 820 | executor_call:: _>( 821 | &mut t, 822 | "Core_execute_block", 823 | &block1.0, 824 | false, 825 | None, 826 | ).0.unwrap(); 827 | 828 | assert!(t.ext().storage_changes_root(&GENESIS_HASH).unwrap().is_some()); 829 | } 830 | 831 | #[test] 832 | fn should_import_block_with_test_client() { 833 | use node_testing::client::{ 834 | ClientBlockImportExt, TestClientBuilderExt, TestClientBuilder, 835 | sp_consensus::BlockOrigin, 836 | }; 837 | 838 | let mut client = TestClientBuilder::new().build(); 839 | let block1 = changes_trie_block(); 840 | let block_data = block1.0; 841 | let block = node_primitives::Block::decode(&mut &block_data[..]).unwrap(); 842 | 843 | futures::executor::block_on(client.import(BlockOrigin::Own, block)).unwrap(); 844 | } 845 | -------------------------------------------------------------------------------- /executor/tests/common.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2019 TrustBase Network 2 | // This file is part of TrustBase library. 3 | // 4 | // The TrustBase library is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU Lesser General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // The TrustBase library is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU Lesser General Public License for more details. 13 | 14 | use codec::{Encode, Decode}; 15 | use frame_system::offchain::AppCrypto; 16 | use frame_support::Hashable; 17 | use sp_state_machine::TestExternalities as CoreTestExternalities; 18 | use sp_consensus_babe::{BABE_ENGINE_ID, Slot, digests::{PreDigest, SecondaryPlainPreDigest}}; 19 | use sp_core::{ 20 | NeverNativeValue, NativeOrEncoded, 21 | crypto::KeyTypeId, 22 | sr25519::Signature, 23 | traits::{CodeExecutor, RuntimeCode}, 24 | }; 25 | use sp_runtime::{ 26 | ApplyExtrinsicResult, 27 | MultiSigner, 28 | MultiSignature, 29 | Digest, 30 | DigestItem, 31 | traits::{Header as HeaderT, BlakeTwo256}, 32 | }; 33 | use sc_executor::{NativeExecutor, WasmExecutionMethod}; 34 | use sc_executor::error::Result; 35 | 36 | use node_executor::Executor; 37 | use node_runtime::{ 38 | Header, Block, UncheckedExtrinsic, CheckedExtrinsic, Runtime, BuildStorage, 39 | constants::currency::*, 40 | }; 41 | use node_primitives::{Hash, BlockNumber}; 42 | use node_testing::keyring::*; 43 | use sp_externalities::Externalities; 44 | 45 | pub const TEST_KEY_TYPE_ID: KeyTypeId = KeyTypeId(*b"test"); 46 | 47 | pub mod sr25519 { 48 | mod app_sr25519 { 49 | use sp_application_crypto::{app_crypto, sr25519}; 50 | use super::super::TEST_KEY_TYPE_ID; 51 | app_crypto!(sr25519, TEST_KEY_TYPE_ID); 52 | } 53 | 54 | pub type AuthorityId = app_sr25519::Public; 55 | } 56 | 57 | pub struct TestAuthorityId; 58 | impl AppCrypto for TestAuthorityId { 59 | type RuntimeAppPublic = sr25519::AuthorityId; 60 | type GenericSignature = Signature; 61 | type GenericPublic = sp_core::sr25519::Public; 62 | } 63 | 64 | /// The wasm runtime code. 65 | /// 66 | /// `compact` since it is after post-processing with wasm-gc which performs tree-shaking thus 67 | /// making the binary slimmer. There is a convention to use compact version of the runtime 68 | /// as canonical. This is why `native_executor_instance` also uses the compact version of the 69 | /// runtime. 70 | pub fn compact_code_unwrap() -> &'static [u8] { 71 | node_runtime::WASM_BINARY.expect("Development wasm binary is not available. \ 72 | Testing is only supported with the flag disabled.") 73 | } 74 | 75 | pub const GENESIS_HASH: [u8; 32] = [69u8; 32]; 76 | 77 | pub const SPEC_VERSION: u32 = node_runtime::VERSION.spec_version; 78 | 79 | pub const TRANSACTION_VERSION: u32 = node_runtime::VERSION.transaction_version; 80 | 81 | pub type TestExternalities = CoreTestExternalities; 82 | 83 | pub fn sign(xt: CheckedExtrinsic) -> UncheckedExtrinsic { 84 | node_testing::keyring::sign(xt, SPEC_VERSION, TRANSACTION_VERSION, GENESIS_HASH) 85 | } 86 | 87 | pub fn default_transfer_call() -> pallet_balances::Call { 88 | pallet_balances::Call::transfer::(bob().into(), 69 * DOLLARS) 89 | } 90 | 91 | pub fn from_block_number(n: u32) -> Header { 92 | Header::new(n, Default::default(), Default::default(), [69; 32].into(), Default::default()) 93 | } 94 | 95 | pub fn executor() -> NativeExecutor { 96 | NativeExecutor::new(WasmExecutionMethod::Interpreted, None, 8) 97 | } 98 | 99 | pub fn executor_call< 100 | R:Decode + Encode + PartialEq, 101 | NC: FnOnce() -> std::result::Result> + std::panic::UnwindSafe 102 | >( 103 | t: &mut TestExternalities, 104 | method: &str, 105 | data: &[u8], 106 | use_native: bool, 107 | native_call: Option, 108 | ) -> (Result>, bool) { 109 | let mut t = t.ext(); 110 | 111 | let code = t.storage(sp_core::storage::well_known_keys::CODE).unwrap(); 112 | let heap_pages = t.storage(sp_core::storage::well_known_keys::HEAP_PAGES); 113 | let runtime_code = RuntimeCode { 114 | code_fetcher: &sp_core::traits::WrappedRuntimeCode(code.as_slice().into()), 115 | hash: sp_core::blake2_256(&code).to_vec(), 116 | heap_pages: heap_pages.and_then(|hp| Decode::decode(&mut &hp[..]).ok()), 117 | }; 118 | 119 | executor().call::( 120 | &mut t, 121 | &runtime_code, 122 | method, 123 | data, 124 | use_native, 125 | native_call, 126 | ) 127 | } 128 | 129 | pub fn new_test_ext(code: &[u8], support_changes_trie: bool) -> TestExternalities { 130 | let mut ext = TestExternalities::new_with_code( 131 | code, 132 | node_testing::genesis::config(support_changes_trie, Some(code)).build_storage().unwrap(), 133 | ); 134 | ext.changes_trie_storage().insert(0, GENESIS_HASH.into(), Default::default()); 135 | ext 136 | } 137 | 138 | /// Construct a fake block. 139 | /// 140 | /// `extrinsics` must be a list of valid extrinsics, i.e. none of the extrinsics for example 141 | /// can report `ExhaustResources`. Otherwise, this function panics. 142 | pub fn construct_block( 143 | env: &mut TestExternalities, 144 | number: BlockNumber, 145 | parent_hash: Hash, 146 | extrinsics: Vec, 147 | babe_slot: Slot, 148 | ) -> (Vec, Hash) { 149 | use sp_trie::{TrieConfiguration, trie_types::Layout}; 150 | 151 | // sign extrinsics. 152 | let extrinsics = extrinsics.into_iter().map(sign).collect::>(); 153 | 154 | // calculate the header fields that we can. 155 | let extrinsics_root = 156 | Layout::::ordered_trie_root(extrinsics.iter().map(Encode::encode)) 157 | .to_fixed_bytes() 158 | .into(); 159 | 160 | let header = Header { 161 | parent_hash, 162 | number, 163 | extrinsics_root, 164 | state_root: Default::default(), 165 | digest: Digest { 166 | logs: vec![ 167 | DigestItem::PreRuntime( 168 | BABE_ENGINE_ID, 169 | PreDigest::SecondaryPlain(SecondaryPlainPreDigest { 170 | slot: babe_slot, 171 | authority_index: 42, 172 | }).encode() 173 | ), 174 | ], 175 | }, 176 | }; 177 | 178 | // execute the block to get the real header. 179 | executor_call:: _>( 180 | env, 181 | "Core_initialize_block", 182 | &header.encode(), 183 | true, 184 | None, 185 | ).0.unwrap(); 186 | 187 | for extrinsic in extrinsics.iter() { 188 | // Try to apply the `extrinsic`. It should be valid, in the sense that it passes 189 | // all pre-inclusion checks. 190 | let r = executor_call:: _>( 191 | env, 192 | "BlockBuilder_apply_extrinsic", 193 | &extrinsic.encode(), 194 | true, 195 | None, 196 | ).0.expect("application of an extrinsic failed").into_encoded(); 197 | match ApplyExtrinsicResult::decode(&mut &r[..]).expect("apply result deserialization failed") { 198 | Ok(_) => {}, 199 | Err(e) => panic!("Applying extrinsic failed: {:?}", e), 200 | } 201 | } 202 | 203 | let header = match executor_call:: _>( 204 | env, 205 | "BlockBuilder_finalize_block", 206 | &[0u8;0], 207 | true, 208 | None, 209 | ).0.unwrap() { 210 | NativeOrEncoded::Native(_) => unreachable!(), 211 | NativeOrEncoded::Encoded(h) => Header::decode(&mut &h[..]).unwrap(), 212 | }; 213 | 214 | let hash = header.blake2_256(); 215 | (Block { header, extrinsics }.encode(), hash.into()) 216 | } 217 | -------------------------------------------------------------------------------- /executor/tests/fees.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2019 TrustBase Network 2 | // This file is part of TrustBase library. 3 | // 4 | // The TrustBase library is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU Lesser General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // The TrustBase library is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU Lesser General Public License for more details. 13 | 14 | use codec::{Encode, Joiner}; 15 | use frame_support::{ 16 | traits::Currency, 17 | weights::{GetDispatchInfo, constants::ExtrinsicBaseWeight, IdentityFee, WeightToFeePolynomial}, 18 | }; 19 | use sp_core::NeverNativeValue; 20 | use sp_runtime::{Perbill, traits::One}; 21 | use node_runtime::{ 22 | CheckedExtrinsic, Call, Runtime, Balances, TransactionPayment, Multiplier, 23 | TransactionByteFee, 24 | constants::{time::SLOT_DURATION, currency::*}, 25 | }; 26 | use node_primitives::Balance; 27 | use node_testing::keyring::*; 28 | 29 | pub mod common; 30 | use self::common::{*, sign}; 31 | 32 | #[test] 33 | fn fee_multiplier_increases_and_decreases_on_big_weight() { 34 | let mut t = new_test_ext(compact_code_unwrap(), false); 35 | 36 | // initial fee multiplier must be one. 37 | let mut prev_multiplier = Multiplier::one(); 38 | 39 | t.execute_with(|| { 40 | assert_eq!(TransactionPayment::next_fee_multiplier(), prev_multiplier); 41 | }); 42 | 43 | let mut tt = new_test_ext(compact_code_unwrap(), false); 44 | 45 | let time1 = 42 * 1000; 46 | // big one in terms of weight. 47 | let block1 = construct_block( 48 | &mut tt, 49 | 1, 50 | GENESIS_HASH.into(), 51 | vec![ 52 | CheckedExtrinsic { 53 | signed: None, 54 | function: Call::Timestamp(pallet_timestamp::Call::set(time1)), 55 | }, 56 | CheckedExtrinsic { 57 | signed: Some((charlie(), signed_extra(0, 0))), 58 | function: Call::System(frame_system::Call::fill_block(Perbill::from_percent(60))), 59 | } 60 | ], 61 | (time1 / SLOT_DURATION).into(), 62 | ); 63 | 64 | let time2 = 52 * 1000; 65 | // small one in terms of weight. 66 | let block2 = construct_block( 67 | &mut tt, 68 | 2, 69 | block1.1.clone(), 70 | vec![ 71 | CheckedExtrinsic { 72 | signed: None, 73 | function: Call::Timestamp(pallet_timestamp::Call::set(time2)), 74 | }, 75 | CheckedExtrinsic { 76 | signed: Some((charlie(), signed_extra(1, 0))), 77 | function: Call::System(frame_system::Call::remark(vec![0; 1])), 78 | } 79 | ], 80 | (time2 / SLOT_DURATION).into(), 81 | ); 82 | 83 | println!( 84 | "++ Block 1 size: {} / Block 2 size {}", 85 | block1.0.encode().len(), 86 | block2.0.encode().len(), 87 | ); 88 | 89 | // execute a big block. 90 | executor_call:: _>( 91 | &mut t, 92 | "Core_execute_block", 93 | &block1.0, 94 | true, 95 | None, 96 | ).0.unwrap(); 97 | 98 | // weight multiplier is increased for next block. 99 | t.execute_with(|| { 100 | let fm = TransactionPayment::next_fee_multiplier(); 101 | println!("After a big block: {:?} -> {:?}", prev_multiplier, fm); 102 | assert!(fm > prev_multiplier); 103 | prev_multiplier = fm; 104 | }); 105 | 106 | // execute a big block. 107 | executor_call:: _>( 108 | &mut t, 109 | "Core_execute_block", 110 | &block2.0, 111 | true, 112 | None, 113 | ).0.unwrap(); 114 | 115 | // weight multiplier is increased for next block. 116 | t.execute_with(|| { 117 | let fm = TransactionPayment::next_fee_multiplier(); 118 | println!("After a small block: {:?} -> {:?}", prev_multiplier, fm); 119 | assert!(fm < prev_multiplier); 120 | }); 121 | } 122 | 123 | fn new_account_info(free_dollars: u128) -> Vec { 124 | frame_system::AccountInfo { 125 | nonce: 0u32, 126 | consumers: 0, 127 | providers: 0, 128 | sufficients: 0, 129 | data: (free_dollars * DOLLARS, 0 * DOLLARS, 0 * DOLLARS, 0 * DOLLARS), 130 | }.encode() 131 | } 132 | 133 | #[test] 134 | fn transaction_fee_is_correct() { 135 | // This uses the exact values of trustbase-node. 136 | // 137 | // weight of transfer call as of now: 1_000_000 138 | // if weight of the cheapest weight would be 10^7, this would be 10^9, which is: 139 | // - 1 MILLICENTS in trustbase node. 140 | // - 1 milli-dot based on current polkadot runtime. 141 | // (this baed on assigning 0.1 CENT to the cheapest tx with `weight = 100`) 142 | let mut t = new_test_ext(compact_code_unwrap(), false); 143 | t.insert(>::hashed_key_for(alice()), new_account_info(100)); 144 | t.insert(>::hashed_key_for(bob()), new_account_info(10)); 145 | t.insert( 146 | >::hashed_key().to_vec(), 147 | (110 * DOLLARS).encode() 148 | ); 149 | t.insert(>::hashed_key_for(0), vec![0u8; 32]); 150 | 151 | let tip = 1_000_000; 152 | let xt = sign(CheckedExtrinsic { 153 | signed: Some((alice(), signed_extra(0, tip))), 154 | function: Call::Balances(default_transfer_call()), 155 | }); 156 | 157 | let r = executor_call:: _>( 158 | &mut t, 159 | "Core_initialize_block", 160 | &vec![].and(&from_block_number(1u32)), 161 | true, 162 | None, 163 | ).0; 164 | 165 | assert!(r.is_ok()); 166 | let r = executor_call:: _>( 167 | &mut t, 168 | "BlockBuilder_apply_extrinsic", 169 | &vec![].and(&xt.clone()), 170 | true, 171 | None, 172 | ).0; 173 | assert!(r.is_ok()); 174 | 175 | t.execute_with(|| { 176 | assert_eq!(Balances::total_balance(&bob()), (10 + 69) * DOLLARS); 177 | // Components deducted from alice's balances: 178 | // - Base fee 179 | // - Weight fee 180 | // - Length fee 181 | // - Tip 182 | // - Creation-fee of bob's account. 183 | let mut balance_alice = (100 - 69) * DOLLARS; 184 | 185 | let base_weight = ExtrinsicBaseWeight::get(); 186 | let base_fee = IdentityFee::::calc(&base_weight); 187 | 188 | let length_fee = TransactionByteFee::get() * (xt.clone().encode().len() as Balance); 189 | balance_alice -= length_fee; 190 | 191 | let weight = default_transfer_call().get_dispatch_info().weight; 192 | let weight_fee = IdentityFee::::calc(&weight); 193 | 194 | // we know that weight to fee multiplier is effect-less in block 1. 195 | // current weight of transfer = 200_000_000 196 | // Linear weight to fee is 1:1 right now (1 weight = 1 unit of balance) 197 | assert_eq!(weight_fee, weight as Balance); 198 | balance_alice -= base_fee; 199 | balance_alice -= weight_fee; 200 | balance_alice -= tip; 201 | 202 | assert_eq!(Balances::total_balance(&alice()), balance_alice); 203 | }); 204 | } 205 | 206 | #[test] 207 | #[should_panic] 208 | #[cfg(feature = "stress-test")] 209 | fn block_weight_capacity_report() { 210 | // Just report how many transfer calls you could fit into a block. The number should at least 211 | // be a few hundred (250 at the time of writing but can change over time). Runs until panic. 212 | use node_primitives::Index; 213 | 214 | // execution ext. 215 | let mut t = new_test_ext(compact_code_unwrap(), false); 216 | // setup ext. 217 | let mut tt = new_test_ext(compact_code_unwrap(), false); 218 | 219 | let factor = 50; 220 | let mut time = 10; 221 | let mut nonce: Index = 0; 222 | let mut block_number = 1; 223 | let mut previous_hash: node_primitives::Hash = GENESIS_HASH.into(); 224 | 225 | loop { 226 | let num_transfers = block_number * factor; 227 | let mut xts = (0..num_transfers).map(|i| CheckedExtrinsic { 228 | signed: Some((charlie(), signed_extra(nonce + i as Index, 0))), 229 | function: Call::Balances(pallet_balances::Call::transfer(bob().into(), 0)), 230 | }).collect::>(); 231 | 232 | xts.insert(0, CheckedExtrinsic { 233 | signed: None, 234 | function: Call::Timestamp(pallet_timestamp::Call::set(time * 1000)), 235 | }); 236 | 237 | // NOTE: this is super slow. Can probably be improved. 238 | let block = construct_block( 239 | &mut tt, 240 | block_number, 241 | previous_hash, 242 | xts, 243 | (time * 1000 / SLOT_DURATION).into(), 244 | ); 245 | 246 | let len = block.0.len(); 247 | print!( 248 | "++ Executing block with {} transfers. Block size = {} bytes / {} kb / {} mb", 249 | num_transfers, 250 | len, 251 | len / 1024, 252 | len / 1024 / 1024, 253 | ); 254 | 255 | let r = executor_call:: _>( 256 | &mut t, 257 | "Core_execute_block", 258 | &block.0, 259 | true, 260 | None, 261 | ).0; 262 | 263 | println!(" || Result = {:?}", r); 264 | assert!(r.is_ok()); 265 | 266 | previous_hash = block.1; 267 | nonce += num_transfers; 268 | time += 10; 269 | block_number += 1; 270 | } 271 | } 272 | 273 | #[test] 274 | #[should_panic] 275 | #[cfg(feature = "stress-test")] 276 | fn block_length_capacity_report() { 277 | // Just report how big a block can get. Executes until panic. Should be ignored unless if 278 | // manually inspected. The number should at least be a few megabytes (5 at the time of 279 | // writing but can change over time). 280 | use node_primitives::Index; 281 | 282 | // execution ext. 283 | let mut t = new_test_ext(compact_code_unwrap(), false); 284 | // setup ext. 285 | let mut tt = new_test_ext(compact_code_unwrap(), false); 286 | 287 | let factor = 256 * 1024; 288 | let mut time = 10; 289 | let mut nonce: Index = 0; 290 | let mut block_number = 1; 291 | let mut previous_hash: node_primitives::Hash = GENESIS_HASH.into(); 292 | 293 | loop { 294 | // NOTE: this is super slow. Can probably be improved. 295 | let block = construct_block( 296 | &mut tt, 297 | block_number, 298 | previous_hash, 299 | vec![ 300 | CheckedExtrinsic { 301 | signed: None, 302 | function: Call::Timestamp(pallet_timestamp::Call::set(time * 1000)), 303 | }, 304 | CheckedExtrinsic { 305 | signed: Some((charlie(), signed_extra(nonce, 0))), 306 | function: Call::System(frame_system::Call::remark(vec![0u8; (block_number * factor) as usize])), 307 | }, 308 | ], 309 | (time * 1000 / SLOT_DURATION).into(), 310 | ); 311 | 312 | let len = block.0.len(); 313 | print!( 314 | "++ Executing block with big remark. Block size = {} bytes / {} kb / {} mb", 315 | len, 316 | len / 1024, 317 | len / 1024 / 1024, 318 | ); 319 | 320 | let r = executor_call:: _>( 321 | &mut t, 322 | "Core_execute_block", 323 | &block.0, 324 | true, 325 | None, 326 | ).0; 327 | 328 | println!(" || Result = {:?}", r); 329 | assert!(r.is_ok()); 330 | 331 | previous_hash = block.1; 332 | nonce += 1; 333 | time += 10; 334 | block_number += 1; 335 | } 336 | } 337 | -------------------------------------------------------------------------------- /executor/tests/submit_transaction.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2019 TrustBase Network 2 | // This file is part of TrustBase library. 3 | // 4 | // The TrustBase library is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU Lesser General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // The TrustBase library is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU Lesser General Public License for more details. 13 | 14 | use std::sync::Arc; 15 | use node_runtime::{ 16 | Executive, Indices, Runtime, UncheckedExtrinsic, 17 | }; 18 | use sp_application_crypto::AppKey; 19 | use sp_core::{ 20 | offchain::{ 21 | TransactionPoolExt, 22 | testing::TestTransactionPoolExt, 23 | }, 24 | }; 25 | use sp_keystore::{KeystoreExt, SyncCryptoStore, testing::KeyStore}; 26 | use frame_system::{ 27 | offchain::{ 28 | Signer, 29 | SubmitTransaction, 30 | SendSignedTransaction, 31 | } 32 | }; 33 | use codec::Decode; 34 | 35 | pub mod common; 36 | use self::common::*; 37 | 38 | #[test] 39 | fn should_submit_unsigned_transaction() { 40 | let mut t = new_test_ext(compact_code_unwrap(), false); 41 | let (pool, state) = TestTransactionPoolExt::new(); 42 | t.register_extension(TransactionPoolExt::new(pool)); 43 | 44 | t.execute_with(|| { 45 | let signature = Default::default(); 46 | let heartbeat_data = pallet_im_online::Heartbeat { 47 | block_number: 1, 48 | network_state: Default::default(), 49 | session_index: 1, 50 | authority_index: 0, 51 | validators_len: 0, 52 | }; 53 | 54 | let call = pallet_im_online::Call::heartbeat(heartbeat_data, signature); 55 | SubmitTransaction::>::submit_unsigned_transaction(call.into()) 56 | .unwrap(); 57 | 58 | assert_eq!(state.read().transactions.len(), 1) 59 | }); 60 | } 61 | 62 | const PHRASE: &str = "news slush supreme milk chapter athlete soap sausage put clutch what kitten"; 63 | 64 | #[test] 65 | fn should_submit_signed_transaction() { 66 | let mut t = new_test_ext(compact_code_unwrap(), false); 67 | let (pool, state) = TestTransactionPoolExt::new(); 68 | t.register_extension(TransactionPoolExt::new(pool)); 69 | 70 | let keystore = KeyStore::new(); 71 | SyncCryptoStore::sr25519_generate_new( 72 | &keystore, 73 | sr25519::AuthorityId::ID, 74 | Some(&format!("{}/hunter1", PHRASE)) 75 | ).unwrap(); 76 | SyncCryptoStore::sr25519_generate_new( 77 | &keystore, 78 | sr25519::AuthorityId::ID, 79 | Some(&format!("{}/hunter2", PHRASE)) 80 | ).unwrap(); 81 | SyncCryptoStore::sr25519_generate_new( 82 | &keystore, 83 | sr25519::AuthorityId::ID, 84 | Some(&format!("{}/hunter3", PHRASE)) 85 | ).unwrap(); 86 | t.register_extension(KeystoreExt(Arc::new(keystore))); 87 | 88 | t.execute_with(|| { 89 | let results = Signer::::all_accounts() 90 | .send_signed_transaction(|_| { 91 | pallet_balances::Call::transfer(Default::default(), Default::default()) 92 | }); 93 | 94 | let len = results.len(); 95 | assert_eq!(len, 3); 96 | assert_eq!(results.into_iter().filter_map(|x| x.1.ok()).count(), len); 97 | assert_eq!(state.read().transactions.len(), len); 98 | }); 99 | } 100 | 101 | #[test] 102 | fn should_submit_signed_twice_from_the_same_account() { 103 | let mut t = new_test_ext(compact_code_unwrap(), false); 104 | let (pool, state) = TestTransactionPoolExt::new(); 105 | t.register_extension(TransactionPoolExt::new(pool)); 106 | 107 | let keystore = KeyStore::new(); 108 | SyncCryptoStore::sr25519_generate_new( 109 | &keystore, 110 | sr25519::AuthorityId::ID, 111 | Some(&format!("{}/hunter1", PHRASE)) 112 | ).unwrap(); 113 | SyncCryptoStore::sr25519_generate_new( 114 | &keystore, 115 | sr25519::AuthorityId::ID, 116 | Some(&format!("{}/hunter2", PHRASE)) 117 | ).unwrap(); 118 | t.register_extension(KeystoreExt(Arc::new(keystore))); 119 | 120 | t.execute_with(|| { 121 | let result = Signer::::any_account() 122 | .send_signed_transaction(|_| { 123 | pallet_balances::Call::transfer(Default::default(), Default::default()) 124 | }); 125 | 126 | assert!(result.is_some()); 127 | assert_eq!(state.read().transactions.len(), 1); 128 | 129 | // submit another one from the same account. The nonce should be incremented. 130 | let result = Signer::::any_account() 131 | .send_signed_transaction(|_| { 132 | pallet_balances::Call::transfer(Default::default(), Default::default()) 133 | }); 134 | 135 | assert!(result.is_some()); 136 | assert_eq!(state.read().transactions.len(), 2); 137 | 138 | // now check that the transaction nonces are not equal 139 | let s = state.read(); 140 | fn nonce(tx: UncheckedExtrinsic) -> frame_system::CheckNonce { 141 | let extra = tx.signature.unwrap().2; 142 | extra.4 143 | } 144 | let nonce1 = nonce(UncheckedExtrinsic::decode(&mut &*s.transactions[0]).unwrap()); 145 | let nonce2 = nonce(UncheckedExtrinsic::decode(&mut &*s.transactions[1]).unwrap()); 146 | assert!( 147 | nonce1 != nonce2, 148 | "Transactions should have different nonces. Got: {:?}", nonce1 149 | ); 150 | }); 151 | } 152 | 153 | #[test] 154 | fn should_submit_signed_twice_from_all_accounts() { 155 | let mut t = new_test_ext(compact_code_unwrap(), false); 156 | let (pool, state) = TestTransactionPoolExt::new(); 157 | t.register_extension(TransactionPoolExt::new(pool)); 158 | 159 | let keystore = KeyStore::new(); 160 | keystore.sr25519_generate_new( 161 | sr25519::AuthorityId::ID, 162 | Some(&format!("{}/hunter1", PHRASE)) 163 | ).unwrap(); 164 | keystore.sr25519_generate_new( 165 | sr25519::AuthorityId::ID, 166 | Some(&format!("{}/hunter2", PHRASE)) 167 | ).unwrap(); 168 | t.register_extension(KeystoreExt(Arc::new(keystore))); 169 | 170 | t.execute_with(|| { 171 | let results = Signer::::all_accounts() 172 | .send_signed_transaction(|_| { 173 | pallet_balances::Call::transfer(Default::default(), Default::default()) 174 | }); 175 | 176 | let len = results.len(); 177 | assert_eq!(len, 2); 178 | assert_eq!(results.into_iter().filter_map(|x| x.1.ok()).count(), len); 179 | assert_eq!(state.read().transactions.len(), 2); 180 | 181 | // submit another one from the same account. The nonce should be incremented. 182 | let results = Signer::::all_accounts() 183 | .send_signed_transaction(|_| { 184 | pallet_balances::Call::transfer(Default::default(), Default::default()) 185 | }); 186 | 187 | let len = results.len(); 188 | assert_eq!(len, 2); 189 | assert_eq!(results.into_iter().filter_map(|x| x.1.ok()).count(), len); 190 | assert_eq!(state.read().transactions.len(), 4); 191 | 192 | // now check that the transaction nonces are not equal 193 | let s = state.read(); 194 | fn nonce(tx: UncheckedExtrinsic) -> frame_system::CheckNonce { 195 | let extra = tx.signature.unwrap().2; 196 | extra.4 197 | } 198 | let nonce1 = nonce(UncheckedExtrinsic::decode(&mut &*s.transactions[0]).unwrap()); 199 | let nonce2 = nonce(UncheckedExtrinsic::decode(&mut &*s.transactions[1]).unwrap()); 200 | let nonce3 = nonce(UncheckedExtrinsic::decode(&mut &*s.transactions[2]).unwrap()); 201 | let nonce4 = nonce(UncheckedExtrinsic::decode(&mut &*s.transactions[3]).unwrap()); 202 | assert!( 203 | nonce1 != nonce3, 204 | "Transactions should have different nonces. Got: 1st tx nonce: {:?}, 2nd nonce: {:?}", nonce1, nonce3 205 | ); 206 | assert!( 207 | nonce2 != nonce4, 208 | "Transactions should have different nonces. Got: 1st tx nonce: {:?}, 2nd tx nonce: {:?}", nonce2, nonce4 209 | ); 210 | }); 211 | } 212 | 213 | #[test] 214 | fn submitted_transaction_should_be_valid() { 215 | use codec::Encode; 216 | use sp_runtime::transaction_validity::{TransactionSource, TransactionTag}; 217 | use sp_runtime::traits::StaticLookup; 218 | 219 | let mut t = new_test_ext(compact_code_unwrap(), false); 220 | let (pool, state) = TestTransactionPoolExt::new(); 221 | t.register_extension(TransactionPoolExt::new(pool)); 222 | 223 | let keystore = KeyStore::new(); 224 | SyncCryptoStore::sr25519_generate_new( 225 | &keystore, 226 | sr25519::AuthorityId::ID, Some(&format!("{}/hunter1", PHRASE)) 227 | ).unwrap(); 228 | t.register_extension(KeystoreExt(Arc::new(keystore))); 229 | 230 | t.execute_with(|| { 231 | let results = Signer::::all_accounts() 232 | .send_signed_transaction(|_| { 233 | pallet_balances::Call::transfer(Default::default(), Default::default()) 234 | }); 235 | let len = results.len(); 236 | assert_eq!(len, 1); 237 | assert_eq!(results.into_iter().filter_map(|x| x.1.ok()).count(), len); 238 | }); 239 | 240 | // check that transaction is valid, but reset environment storage, 241 | // since CreateTransaction increments the nonce 242 | let tx0 = state.read().transactions[0].clone(); 243 | let mut t = new_test_ext(compact_code_unwrap(), false); 244 | t.execute_with(|| { 245 | let source = TransactionSource::External; 246 | let extrinsic = UncheckedExtrinsic::decode(&mut &*tx0).unwrap(); 247 | // add balance to the account 248 | let author = extrinsic.signature.clone().unwrap().0; 249 | let address = Indices::lookup(author).unwrap(); 250 | let data = pallet_balances::AccountData { free: 5_000_000_000_000, ..Default::default() }; 251 | let account = frame_system::AccountInfo { data, .. Default::default() }; 252 | >::insert(&address, account); 253 | 254 | // check validity 255 | let res = Executive::validate_transaction(source, extrinsic).unwrap(); 256 | 257 | // We ignore res.priority since this number can change based on updates to weights and such. 258 | assert_eq!(res.requires, Vec::::new()); 259 | assert_eq!(res.provides, vec![(address, 0).encode()]); 260 | assert_eq!(res.longevity, 2048); 261 | assert_eq!(res.propagate, true); 262 | }); 263 | } 264 | -------------------------------------------------------------------------------- /file_header.txt: -------------------------------------------------------------------------------- 1 | // Copyright 2019 TrustBase Network 2 | // This file is part of TrustBase library. 3 | // 4 | // The TrustBase library is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU Lesser General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // The TrustBase library is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU Lesser General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU Lesser General Public License 15 | // along with the TrustBase library. If not, see . -------------------------------------------------------------------------------- /inspect/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "node-inspect" 3 | version = "0.8.0" 4 | authors = ["trust dev"] 5 | edition = "2018" 6 | 7 | license = 'Apache-2.0' 8 | 9 | [package.metadata.docs.rs] 10 | targets = ["x86_64-unknown-linux-gnu"] 11 | 12 | [dependencies] 13 | codec = { package = "parity-scale-codec", version = "2.0.0" } 14 | derive_more = "0.99" 15 | log = "0.4.8" 16 | sc-cli = { version = "0.9.0", git = "https://github.com/paritytech/substrate" } 17 | sc-client-api = { version = "3.0.0", git = "https://github.com/paritytech/substrate" } 18 | sc-service = { version = "0.9.0", default-features = false, git = "https://github.com/paritytech/substrate" } 19 | sp-blockchain = { version = "3.0.0", git = "https://github.com/paritytech/substrate" } 20 | sp-core = { version = "3.0.0", git = "https://github.com/paritytech/substrate" } 21 | sp-runtime = { version = "3.0.0", git = "https://github.com/paritytech/substrate" } 22 | structopt = "0.3.8" 23 | -------------------------------------------------------------------------------- /inspect/src/cli.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2019 TrustBase Network 2 | // This file is part of TrustBase library. 3 | // 4 | // The TrustBase library is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU Lesser General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // The TrustBase library is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU Lesser General Public License for more details. 13 | 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program. If not, see . 16 | 17 | //! Structs to easily compose inspect sub-command for CLI. 18 | 19 | use std::fmt::Debug; 20 | use sc_cli::{ImportParams, SharedParams}; 21 | use structopt::StructOpt; 22 | 23 | /// The `inspect` command used to print decoded chain data. 24 | #[derive(Debug, StructOpt)] 25 | pub struct InspectCmd { 26 | #[allow(missing_docs)] 27 | #[structopt(flatten)] 28 | pub command: InspectSubCmd, 29 | 30 | #[allow(missing_docs)] 31 | #[structopt(flatten)] 32 | pub shared_params: SharedParams, 33 | 34 | #[allow(missing_docs)] 35 | #[structopt(flatten)] 36 | pub import_params: ImportParams, 37 | } 38 | 39 | /// A possible inspect sub-commands. 40 | #[derive(Debug, StructOpt)] 41 | pub enum InspectSubCmd { 42 | /// Decode block with native version of runtime and print out the details. 43 | Block { 44 | /// Address of the block to print out. 45 | /// 46 | /// Can be either a block hash (no 0x prefix) or a number to retrieve existing block, 47 | /// or a 0x-prefixed bytes hex string, representing SCALE encoding of 48 | /// a block. 49 | #[structopt(value_name = "HASH or NUMBER or BYTES")] 50 | input: String, 51 | }, 52 | /// Decode extrinsic with native version of runtime and print out the details. 53 | Extrinsic { 54 | /// Address of an extrinsic to print out. 55 | /// 56 | /// Can be either a block hash (no 0x prefix) or number and the index, in the form 57 | /// of `{block}:{index}` or a 0x-prefixed bytes hex string, 58 | /// representing SCALE encoding of an extrinsic. 59 | #[structopt(value_name = "BLOCK:INDEX or BYTES")] 60 | input: String, 61 | }, 62 | } 63 | -------------------------------------------------------------------------------- /inspect/src/command.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2019 TrustBase Network 2 | // This file is part of TrustBase library. 3 | // 4 | // The TrustBase library is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU Lesser General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // The TrustBase library is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU Lesser General Public License for more details. 13 | 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program. If not, see . 16 | 17 | //! Command ran by the CLI 18 | 19 | use crate::cli::{InspectCmd, InspectSubCmd}; 20 | use crate::Inspector; 21 | use sc_cli::{CliConfiguration, ImportParams, Result, SharedParams}; 22 | use sc_service::{new_full_client, Configuration, NativeExecutionDispatch}; 23 | use sp_runtime::traits::Block; 24 | use std::str::FromStr; 25 | 26 | impl InspectCmd { 27 | /// Run the inspect command, passing the inspector. 28 | pub fn run(&self, config: Configuration) -> Result<()> 29 | where 30 | B: Block, 31 | B::Hash: FromStr, 32 | RA: Send + Sync + 'static, 33 | EX: NativeExecutionDispatch + 'static, 34 | { 35 | let client = new_full_client::(&config, None)?; 36 | let inspect = Inspector::::new(client); 37 | 38 | match &self.command { 39 | InspectSubCmd::Block { input } => { 40 | let input = input.parse()?; 41 | let res = inspect.block(input).map_err(|e| format!("{}", e))?; 42 | println!("{}", res); 43 | Ok(()) 44 | } 45 | InspectSubCmd::Extrinsic { input } => { 46 | let input = input.parse()?; 47 | let res = inspect.extrinsic(input).map_err(|e| format!("{}", e))?; 48 | println!("{}", res); 49 | Ok(()) 50 | } 51 | } 52 | } 53 | } 54 | 55 | impl CliConfiguration for InspectCmd { 56 | fn shared_params(&self) -> &SharedParams { 57 | &self.shared_params 58 | } 59 | 60 | fn import_params(&self) -> Option<&ImportParams> { 61 | Some(&self.import_params) 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /inspect/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2019 TrustBase Network 2 | // This file is part of TrustBase library. 3 | // 4 | // The TrustBase library is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU Lesser General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // The TrustBase library is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU Lesser General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program. If not, see . 16 | 17 | //! A CLI extension for trustbase node, adding sub-command to pretty print debug info 18 | //! about blocks and extrinsics. 19 | //! 20 | //! The blocks and extrinsics can either be retrieved from the database (on-chain), 21 | //! or a raw SCALE-encoding can be provided. 22 | 23 | #![warn(missing_docs)] 24 | 25 | pub mod cli; 26 | pub mod command; 27 | 28 | use std::{ 29 | fmt, 30 | fmt::Debug, 31 | marker::PhantomData, 32 | str::FromStr, 33 | }; 34 | use codec::{Encode, Decode}; 35 | use sc_client_api::BlockBackend; 36 | use sp_blockchain::HeaderBackend; 37 | use sp_core::hexdisplay::HexDisplay; 38 | use sp_runtime::{ 39 | generic::BlockId, 40 | traits::{Block, HashFor, NumberFor, Hash} 41 | }; 42 | 43 | /// A helper type for a generic block input. 44 | pub type BlockAddressFor = BlockAddress< 45 | as Hash>::Output, 46 | NumberFor 47 | >; 48 | 49 | /// A Pretty formatter implementation. 50 | pub trait PrettyPrinter { 51 | /// Nicely format block. 52 | fn fmt_block(&self, fmt: &mut fmt::Formatter, block: &TBlock) -> fmt::Result; 53 | /// Nicely format extrinsic. 54 | fn fmt_extrinsic(&self, fmt: &mut fmt::Formatter, extrinsic: &TBlock::Extrinsic) -> fmt::Result; 55 | } 56 | 57 | /// Default dummy debug printer. 58 | #[derive(Default)] 59 | pub struct DebugPrinter; 60 | impl PrettyPrinter for DebugPrinter { 61 | fn fmt_block(&self, fmt: &mut fmt::Formatter, block: &TBlock) -> fmt::Result { 62 | writeln!(fmt, "Header:")?; 63 | writeln!(fmt, "{:?}", block.header())?; 64 | writeln!(fmt, "Block bytes: {:?}", HexDisplay::from(&block.encode()))?; 65 | writeln!(fmt, "Extrinsics ({})", block.extrinsics().len())?; 66 | for (idx, ex) in block.extrinsics().iter().enumerate() { 67 | writeln!(fmt, "- {}:", idx)?; 68 | >::fmt_extrinsic(self, fmt, ex)?; 69 | } 70 | Ok(()) 71 | } 72 | 73 | fn fmt_extrinsic(&self, fmt: &mut fmt::Formatter, extrinsic: &TBlock::Extrinsic) -> fmt::Result { 74 | writeln!(fmt, " {:#?}", extrinsic)?; 75 | writeln!(fmt, " Bytes: {:?}", HexDisplay::from(&extrinsic.encode()))?; 76 | Ok(()) 77 | } 78 | } 79 | 80 | /// Aggregated error for `Inspector` operations. 81 | #[derive(Debug, derive_more::From, derive_more::Display)] 82 | pub enum Error { 83 | /// Could not decode Block or Extrinsic. 84 | Codec(codec::Error), 85 | /// Error accessing blockchain DB. 86 | Blockchain(sp_blockchain::Error), 87 | /// Given block has not been found. 88 | NotFound(String), 89 | } 90 | 91 | impl std::error::Error for Error { 92 | fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { 93 | match *self { 94 | Self::Codec(ref e) => Some(e), 95 | Self::Blockchain(ref e) => Some(e), 96 | Self::NotFound(_) => None, 97 | } 98 | } 99 | } 100 | 101 | /// A helper trait to access block headers and bodies. 102 | pub trait ChainAccess: 103 | HeaderBackend + 104 | BlockBackend 105 | {} 106 | 107 | impl ChainAccess for T where 108 | TBlock: Block, 109 | T: sp_blockchain::HeaderBackend + sc_client_api::BlockBackend, 110 | {} 111 | 112 | /// Blockchain inspector. 113 | pub struct Inspector = DebugPrinter> { 114 | printer: TPrinter, 115 | chain: Box>, 116 | _block: PhantomData, 117 | } 118 | 119 | impl> Inspector { 120 | /// Create new instance of the inspector with default printer. 121 | pub fn new( 122 | chain: impl ChainAccess + 'static, 123 | ) -> Self where TPrinter: Default { 124 | Self::with_printer(chain, Default::default()) 125 | } 126 | 127 | /// Customize pretty-printing of the data. 128 | pub fn with_printer( 129 | chain: impl ChainAccess + 'static, 130 | printer: TPrinter, 131 | ) -> Self { 132 | Inspector { 133 | chain: Box::new(chain) as _, 134 | printer, 135 | _block: Default::default(), 136 | } 137 | } 138 | 139 | /// Get a pretty-printed block. 140 | pub fn block(&self, input: BlockAddressFor) -> Result { 141 | struct BlockPrinter<'a, A, B>(A, &'a B); 142 | impl<'a, A: Block, B: PrettyPrinter> fmt::Display for BlockPrinter<'a, A, B> { 143 | fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { 144 | self.1.fmt_block(fmt, &self.0) 145 | } 146 | } 147 | 148 | let block = self.get_block(input)?; 149 | Ok(format!("{}", BlockPrinter(block, &self.printer))) 150 | } 151 | 152 | fn get_block(&self, input: BlockAddressFor) -> Result { 153 | Ok(match input { 154 | BlockAddress::Bytes(bytes) => { 155 | TBlock::decode(&mut &*bytes)? 156 | }, 157 | BlockAddress::Number(number) => { 158 | let id = BlockId::number(number); 159 | let not_found = format!("Could not find block {:?}", id); 160 | let body = self.chain.block_body(&id)? 161 | .ok_or_else(|| Error::NotFound(not_found.clone()))?; 162 | let header = self.chain.header(id)? 163 | .ok_or_else(|| Error::NotFound(not_found.clone()))?; 164 | TBlock::new(header, body) 165 | }, 166 | BlockAddress::Hash(hash) => { 167 | let id = BlockId::hash(hash); 168 | let not_found = format!("Could not find block {:?}", id); 169 | let body = self.chain.block_body(&id)? 170 | .ok_or_else(|| Error::NotFound(not_found.clone()))?; 171 | let header = self.chain.header(id)? 172 | .ok_or_else(|| Error::NotFound(not_found.clone()))?; 173 | TBlock::new(header, body) 174 | }, 175 | }) 176 | } 177 | 178 | /// Get a pretty-printed extrinsic. 179 | pub fn extrinsic( 180 | &self, 181 | input: ExtrinsicAddress< as Hash>::Output, NumberFor>, 182 | ) -> Result { 183 | struct ExtrinsicPrinter<'a, A: Block, B>(A::Extrinsic, &'a B); 184 | impl<'a, A: Block, B: PrettyPrinter> fmt::Display for ExtrinsicPrinter<'a, A, B> { 185 | fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { 186 | self.1.fmt_extrinsic(fmt, &self.0) 187 | } 188 | } 189 | 190 | let ext = match input { 191 | ExtrinsicAddress::Block(block, index) => { 192 | let block = self.get_block(block)?; 193 | block.extrinsics() 194 | .get(index) 195 | .cloned() 196 | .ok_or_else(|| Error::NotFound(format!( 197 | "Could not find extrinsic {} in block {:?}", index, block 198 | )))? 199 | }, 200 | ExtrinsicAddress::Bytes(bytes) => { 201 | TBlock::Extrinsic::decode(&mut &*bytes)? 202 | } 203 | }; 204 | 205 | Ok(format!("{}", ExtrinsicPrinter(ext, &self.printer))) 206 | } 207 | } 208 | 209 | /// A block to retrieve. 210 | #[derive(Debug, Clone, PartialEq)] 211 | pub enum BlockAddress { 212 | /// Get block by hash. 213 | Hash(Hash), 214 | /// Get block by number. 215 | Number(Number), 216 | /// Raw SCALE-encoded bytes. 217 | Bytes(Vec), 218 | } 219 | 220 | impl FromStr for BlockAddress { 221 | type Err = String; 222 | 223 | fn from_str(s: &str) -> Result { 224 | // try to parse hash first 225 | if let Ok(hash) = s.parse() { 226 | return Ok(Self::Hash(hash)) 227 | } 228 | 229 | // then number 230 | if let Ok(number) = s.parse() { 231 | return Ok(Self::Number(number)) 232 | } 233 | 234 | // then assume it's bytes (hex-encoded) 235 | sp_core::bytes::from_hex(s) 236 | .map(Self::Bytes) 237 | .map_err(|e| format!( 238 | "Given string does not look like hash or number. It could not be parsed as bytes either: {}", 239 | e 240 | )) 241 | } 242 | } 243 | 244 | /// An extrinsic address to decode and print out. 245 | #[derive(Debug, Clone, PartialEq)] 246 | pub enum ExtrinsicAddress { 247 | /// Extrinsic as part of existing block. 248 | Block(BlockAddress, usize), 249 | /// Raw SCALE-encoded extrinsic bytes. 250 | Bytes(Vec), 251 | } 252 | 253 | impl FromStr for ExtrinsicAddress { 254 | type Err = String; 255 | 256 | fn from_str(s: &str) -> Result { 257 | // first try raw bytes 258 | if let Ok(bytes) = sp_core::bytes::from_hex(s).map(Self::Bytes) { 259 | return Ok(bytes) 260 | } 261 | 262 | // split by a bunch of different characters 263 | let mut it = s.split(|c| c == '.' || c == ':' || c == ' '); 264 | let block = it.next() 265 | .expect("First element of split iterator is never empty; qed") 266 | .parse()?; 267 | 268 | let index = it.next() 269 | .ok_or_else(|| format!("Extrinsic index missing: example \"5:0\""))? 270 | .parse() 271 | .map_err(|e| format!("Invalid index format: {}", e))?; 272 | 273 | Ok(Self::Block(block, index)) 274 | } 275 | } 276 | 277 | #[cfg(test)] 278 | mod tests { 279 | use super::*; 280 | use sp_core::hash::H160 as Hash; 281 | 282 | #[test] 283 | fn should_parse_block_strings() { 284 | type BlockAddress = super::BlockAddress; 285 | 286 | let b0 = BlockAddress::from_str("3BfC20f0B9aFcAcE800D73D2191166FF16540258"); 287 | let b1 = BlockAddress::from_str("1234"); 288 | let b2 = BlockAddress::from_str("0"); 289 | let b3 = BlockAddress::from_str("0x0012345f"); 290 | 291 | 292 | assert_eq!(b0, Ok(BlockAddress::Hash( 293 | "3BfC20f0B9aFcAcE800D73D2191166FF16540258".parse().unwrap() 294 | ))); 295 | assert_eq!(b1, Ok(BlockAddress::Number(1234))); 296 | assert_eq!(b2, Ok(BlockAddress::Number(0))); 297 | assert_eq!(b3, Ok(BlockAddress::Bytes(vec![0, 0x12, 0x34, 0x5f]))); 298 | } 299 | 300 | #[test] 301 | fn should_parse_extrinsic_address() { 302 | type BlockAddress = super::BlockAddress; 303 | type ExtrinsicAddress = super::ExtrinsicAddress; 304 | 305 | let e0 = ExtrinsicAddress::from_str("1234"); 306 | let b0 = ExtrinsicAddress::from_str("3BfC20f0B9aFcAcE800D73D2191166FF16540258:5"); 307 | let b1 = ExtrinsicAddress::from_str("1234:0"); 308 | let b2 = ExtrinsicAddress::from_str("0 0"); 309 | let b3 = ExtrinsicAddress::from_str("0x0012345f"); 310 | 311 | 312 | assert_eq!(e0, Err("Extrinsic index missing: example \"5:0\"".into())); 313 | assert_eq!(b0, Ok(ExtrinsicAddress::Block( 314 | BlockAddress::Hash("3BfC20f0B9aFcAcE800D73D2191166FF16540258".parse().unwrap()), 315 | 5 316 | ))); 317 | assert_eq!(b1, Ok(ExtrinsicAddress::Block( 318 | BlockAddress::Number(1234), 319 | 0 320 | ))); 321 | assert_eq!(b2, Ok(ExtrinsicAddress::Block( 322 | BlockAddress::Number(0), 323 | 0 324 | ))); 325 | assert_eq!(b3, Ok(ExtrinsicAddress::Bytes(vec![0, 0x12, 0x34, 0x5f]))); 326 | } 327 | } 328 | -------------------------------------------------------------------------------- /primitives/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "node-primitives" 3 | version = "2.0.0" 4 | authors = ["trust dev"] 5 | edition = "2018" 6 | license = "Apache-2.0" 7 | 8 | [package.metadata.docs.rs] 9 | targets = ["x86_64-unknown-linux-gnu"] 10 | 11 | [dependencies] 12 | codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } 13 | frame-system = { version = "3.0.0", default-features = false, git = "https://github.com/paritytech/substrate" } 14 | sp-application-crypto = { version = "3.0.0", default-features = false, git = "https://github.com/paritytech/substrate" } 15 | sp-core = { version = "3.0.0", default-features = false, git = "https://github.com/paritytech/substrate" } 16 | sp-runtime = { version = "3.0.0", default-features = false, git = "https://github.com/paritytech/substrate" } 17 | 18 | [dev-dependencies] 19 | sp-serializer = { version = "3.0.0", git = "https://github.com/paritytech/substrate" } 20 | pretty_assertions = "0.6.1" 21 | 22 | [features] 23 | default = ["std"] 24 | std = [ 25 | "codec/std", 26 | "frame-system/std", 27 | "sp-application-crypto/std", 28 | "sp-core/std", 29 | "sp-runtime/std", 30 | ] 31 | -------------------------------------------------------------------------------- /primitives/src/lib.rs: -------------------------------------------------------------------------------- 1 | // This file is part of Substrate. 2 | 3 | // Copyright (C) 2018-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 | //! Low-level types used throughout the Substrate code. 19 | 20 | #![warn(missing_docs)] 21 | 22 | #![cfg_attr(not(feature = "std"), no_std)] 23 | 24 | use sp_runtime::{ 25 | generic, traits::{Verify, BlakeTwo256, IdentifyAccount}, OpaqueExtrinsic, MultiSignature 26 | }; 27 | 28 | /// An index to a block. 29 | pub type BlockNumber = u32; 30 | 31 | /// Alias to 512-bit hash when used in the context of a transaction signature on the chain. 32 | pub type Signature = MultiSignature; 33 | 34 | /// Some way of identifying an account on the chain. We intentionally make it equivalent 35 | /// to the public key of our transaction signing scheme. 36 | pub type AccountId = <::Signer as IdentifyAccount>::AccountId; 37 | 38 | /// The type for looking up accounts. We don't expect more than 4 billion of them. 39 | pub type AccountIndex = u32; 40 | 41 | /// Balance of an account. 42 | pub type Balance = u128; 43 | 44 | /// Type used for expressing timestamp. 45 | pub type Moment = u64; 46 | 47 | /// Index of a transaction in the chain. 48 | pub type Index = u32; 49 | 50 | /// A hash of some data used by the chain. 51 | pub type Hash = sp_core::H256; 52 | 53 | /// A timestamp: milliseconds since the unix epoch. 54 | /// `u64` is enough to represent a duration of half a billion years, when the 55 | /// time scale is milliseconds. 56 | pub type Timestamp = u64; 57 | 58 | /// Digest item type. 59 | pub type DigestItem = generic::DigestItem; 60 | /// Header type. 61 | pub type Header = generic::Header; 62 | /// Block type. 63 | pub type Block = generic::Block; 64 | /// Block ID. 65 | pub type BlockId = generic::BlockId; 66 | 67 | /// App-specific crypto used for reporting equivocation/misbehavior in BABE and 68 | /// GRANDPA. Any rewards for misbehavior reporting will be paid out to this 69 | /// account. 70 | pub mod report { 71 | use super::{Signature, Verify}; 72 | use frame_system::offchain::AppCrypto; 73 | use sp_core::crypto::{key_types, KeyTypeId}; 74 | 75 | /// Key type for the reporting module. Used for reporting BABE and GRANDPA 76 | /// equivocations. 77 | pub const KEY_TYPE: KeyTypeId = key_types::REPORTING; 78 | 79 | mod app { 80 | use sp_application_crypto::{app_crypto, sr25519}; 81 | app_crypto!(sr25519, super::KEY_TYPE); 82 | } 83 | 84 | /// Identity of the equivocation/misbehavior reporter. 85 | pub type ReporterId = app::Public; 86 | 87 | /// An `AppCrypto` type to allow submitting signed transactions using the reporting 88 | /// application key as signer. 89 | pub struct ReporterAppCrypto; 90 | 91 | impl AppCrypto<::Signer, Signature> for ReporterAppCrypto { 92 | type RuntimeAppPublic = ReporterId; 93 | type GenericSignature = sp_core::sr25519::Signature; 94 | type GenericPublic = sp_core::sr25519::Public; 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /rpc-client/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "node-rpc-client" 3 | version = "2.0.0" 4 | authors = ["trust dev"] 5 | edition = "2018" 6 | license = "Apache-2.0" 7 | 8 | 9 | [package.metadata.docs.rs] 10 | targets = ["x86_64-unknown-linux-gnu"] 11 | 12 | [dependencies] 13 | futures = "0.1.29" 14 | hyper = "~0.12.35" 15 | jsonrpc-core-client = { version = "15.1.0", default-features = false, features = ["http"] } 16 | log = "0.4.8" 17 | node-primitives = { version = "2.0.0", path = "../primitives" } 18 | sp-tracing = { version = "3.0.0", git = "https://github.com/paritytech/substrate" } 19 | sc-rpc = { version = "3.0.0", git = "https://github.com/paritytech/substrate" } 20 | -------------------------------------------------------------------------------- /rpc-client/src/main.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2019 TrustBase Network 2 | // This file is part of TrustBase library. 3 | // 4 | // The TrustBase library is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU Lesser General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // The TrustBase library is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU Lesser General Public License for more details. 13 | 14 | #![warn(missing_docs)] 15 | 16 | //! Example trustbase RPC client code. 17 | //! 18 | //! This module shows how you can write a Rust RPC client that connects to a running 19 | //! trustbase node and use statically typed RPC wrappers. 20 | 21 | use futures::Future; 22 | use hyper::rt; 23 | use node_primitives::Hash; 24 | use sc_rpc::author::{ 25 | AuthorClient, 26 | hash::ExtrinsicOrHash, 27 | }; 28 | use jsonrpc_core_client::{ 29 | transports::http, 30 | RpcError, 31 | }; 32 | 33 | fn main() { 34 | sp_tracing::try_init_simple(); 35 | 36 | rt::run(rt::lazy(|| { 37 | let uri = "http://localhost:9933"; 38 | 39 | http::connect(uri) 40 | .and_then(|client: AuthorClient| { 41 | remove_all_extrinsics(client) 42 | }) 43 | .map_err(|e| { 44 | println!("Error: {:?}", e); 45 | }) 46 | })) 47 | } 48 | 49 | /// Remove all pending extrinsics from the node. 50 | /// 51 | /// The example code takes `AuthorClient` and first: 52 | /// 1. Calls the `pending_extrinsics` method to get all extrinsics in the pool. 53 | /// 2. Then calls `remove_extrinsic` passing the obtained raw extrinsics. 54 | /// 55 | /// As the result of running the code the entire content of the transaction pool is going 56 | /// to be removed and the extrinsics are going to be temporarily banned. 57 | fn remove_all_extrinsics(client: AuthorClient) -> impl Future { 58 | client.pending_extrinsics() 59 | .and_then(move |pending| { 60 | client.remove_extrinsic( 61 | pending.into_iter().map(|tx| ExtrinsicOrHash::Extrinsic(tx.into())).collect() 62 | ) 63 | }) 64 | .map(|removed| { 65 | println!("Removed extrinsics: {:?}", removed); 66 | }) 67 | } 68 | -------------------------------------------------------------------------------- /rpc/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "node-rpc" 3 | version = "2.0.0" 4 | authors = ["trust dev"] 5 | edition = "2018" 6 | license = "Apache-2.0" 7 | 8 | [package.metadata.docs.rs] 9 | targets = ["x86_64-unknown-linux-gnu"] 10 | 11 | [dependencies] 12 | jsonrpc-core = "15.1.0" 13 | node-primitives = { version = "2.0.0", path = "../primitives" } 14 | pallet-contracts-rpc = { version = "3.0.0", git = "https://github.com/paritytech/substrate" } 15 | pallet-mmr-rpc = { version = "3.0.0", git = "https://github.com/paritytech/substrate" } 16 | pallet-transaction-payment-rpc = { version = "3.0.0", git = "https://github.com/paritytech/substrate" } 17 | sc-client-api = { version = "3.0.0", git = "https://github.com/paritytech/substrate" } 18 | sc-consensus-babe = { version = "0.9.0", git = "https://github.com/paritytech/substrate" } 19 | sc-consensus-babe-rpc = { version = "0.9.0", git = "https://github.com/paritytech/substrate" } 20 | sc-consensus-epochs = { version = "0.9.0", git = "https://github.com/paritytech/substrate" } 21 | sc-chain-spec = { version = "3.0.0", git = "https://github.com/paritytech/substrate" } 22 | sc-finality-grandpa = { version = "0.9.0", git = "https://github.com/paritytech/substrate" } 23 | sc-finality-grandpa-rpc = { version = "0.9.0", git = "https://github.com/paritytech/substrate" } 24 | sc-keystore = { version = "3.0.0", git = "https://github.com/paritytech/substrate" } 25 | sc-rpc-api = { version = "0.9.0", git = "https://github.com/paritytech/substrate" } 26 | sc-rpc = { version = "3.0.0", git = "https://github.com/paritytech/substrate" } 27 | sc-sync-state-rpc = { version = "0.9.0", git = "https://github.com/paritytech/substrate" } 28 | sp-api = { version = "3.0.0", git = "https://github.com/paritytech/substrate" } 29 | sp-block-builder = { version = "3.0.0", git = "https://github.com/paritytech/substrate" } 30 | sp-blockchain = { version = "3.0.0", git = "https://github.com/paritytech/substrate" } 31 | sp-keystore = { version = "0.9.0", git = "https://github.com/paritytech/substrate" } 32 | sp-consensus = { version = "0.9.0", git = "https://github.com/paritytech/substrate" } 33 | sp-consensus-babe = { version = "0.9.0", git = "https://github.com/paritytech/substrate" } 34 | sp-runtime = { version = "3.0.0", git = "https://github.com/paritytech/substrate" } 35 | sp-transaction-pool = { version = "3.0.0", git = "https://github.com/paritytech/substrate" } 36 | substrate-frame-rpc-system = { version = "3.0.0", git = "https://github.com/paritytech/substrate" } 37 | -------------------------------------------------------------------------------- /rpc/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2019 TrustBase Network 2 | // This file is part of TrustBase library. 3 | // 4 | // The TrustBase library is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU Lesser General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // The TrustBase library is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU Lesser General Public License for more details. 13 | 14 | //! A collection of node-specific RPC methods. 15 | //! 16 | //! Since `trustbase` core functionality makes no assumptions 17 | //! about the modules used inside the runtime, so do 18 | //! RPC methods defined in `sc-rpc` crate. 19 | //! It means that `client/rpc` can't have any methods that 20 | //! need some strong assumptions about the particular runtime. 21 | //! 22 | //! The RPCs available in this crate however can make some assumptions 23 | //! about how the runtime is constructed and what FRAME pallets 24 | //! are part of it. Therefore all node-runtime-specific RPCs can 25 | //! be placed here or imported from corresponding FRAME RPC definitions. 26 | 27 | #![warn(missing_docs)] 28 | 29 | use std::sync::Arc; 30 | 31 | use sp_keystore::SyncCryptoStorePtr; 32 | use node_primitives::{Block, BlockNumber, AccountId, Index, Balance, Hash}; 33 | use sc_consensus_babe::{Config, Epoch}; 34 | use sc_consensus_babe_rpc::BabeRpcHandler; 35 | use sc_consensus_epochs::SharedEpochChanges; 36 | use sc_finality_grandpa::{ 37 | SharedVoterState, SharedAuthoritySet, FinalityProofProvider, GrandpaJustificationStream 38 | }; 39 | use sc_finality_grandpa_rpc::GrandpaRpcHandler; 40 | pub use sc_rpc_api::DenyUnsafe; 41 | use sp_api::ProvideRuntimeApi; 42 | use sp_block_builder::BlockBuilder; 43 | use sp_blockchain::{Error as BlockChainError, HeaderMetadata, HeaderBackend}; 44 | use sp_consensus::SelectChain; 45 | use sp_consensus_babe::BabeApi; 46 | use sc_rpc::SubscriptionTaskExecutor; 47 | use sp_transaction_pool::TransactionPool; 48 | use sc_client_api::AuxStore; 49 | 50 | /// Light client extra dependencies. 51 | pub struct LightDeps { 52 | /// The client instance to use. 53 | pub client: Arc, 54 | /// Transaction pool instance. 55 | pub pool: Arc

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

, 92 | /// The SelectChain Strategy 93 | pub select_chain: SC, 94 | /// A copy of the chain spec. 95 | pub chain_spec: Box, 96 | /// Whether to deny unsafe calls 97 | pub deny_unsafe: DenyUnsafe, 98 | /// BABE specific dependencies. 99 | pub babe: BabeDeps, 100 | /// GRANDPA specific dependencies. 101 | pub grandpa: GrandpaDeps, 102 | } 103 | 104 | /// A IO handler that uses all Full RPC extensions. 105 | pub type IoHandler = jsonrpc_core::IoHandler; 106 | 107 | /// Instantiate all Full RPC extensions. 108 | pub fn create_full( 109 | deps: FullDeps, 110 | ) -> jsonrpc_core::IoHandler where 111 | C: ProvideRuntimeApi + HeaderBackend + AuxStore + 112 | HeaderMetadata + Sync + Send + 'static, 113 | C::Api: substrate_frame_rpc_system::AccountNonceApi, 114 | C::Api: pallet_contracts_rpc::ContractsRuntimeApi, 115 | // C::Api: pallet_mmr_rpc::MmrRuntimeApi::Hash>, 116 | C::Api: pallet_transaction_payment_rpc::TransactionPaymentRuntimeApi, 117 | C::Api: BabeApi, 118 | C::Api: BlockBuilder, 119 | P: TransactionPool + 'static, 120 | SC: SelectChain +'static, 121 | B: sc_client_api::Backend + Send + Sync + 'static, 122 | B::State: sc_client_api::backend::StateBackend>, 123 | { 124 | use substrate_frame_rpc_system::{FullSystem, SystemApi}; 125 | use pallet_contracts_rpc::{Contracts, ContractsApi}; 126 | // use pallet_mmr_rpc::{MmrApi, Mmr}; 127 | use pallet_transaction_payment_rpc::{TransactionPayment, TransactionPaymentApi}; 128 | 129 | let mut io = jsonrpc_core::IoHandler::default(); 130 | let FullDeps { 131 | client, 132 | pool, 133 | select_chain, 134 | chain_spec, 135 | deny_unsafe, 136 | babe, 137 | grandpa, 138 | } = deps; 139 | 140 | let BabeDeps { 141 | keystore, 142 | babe_config, 143 | shared_epoch_changes, 144 | } = babe; 145 | let GrandpaDeps { 146 | shared_voter_state, 147 | shared_authority_set, 148 | justification_stream, 149 | subscription_executor, 150 | finality_provider, 151 | } = grandpa; 152 | 153 | io.extend_with( 154 | SystemApi::to_delegate(FullSystem::new(client.clone(), pool, deny_unsafe)) 155 | ); 156 | // Making synchronous calls in light client freezes the browser currently, 157 | // more context: https://github.com/paritytech/substrate/pull/3480 158 | // These RPCs should use an asynchronous caller instead. 159 | io.extend_with( 160 | ContractsApi::to_delegate(Contracts::new(client.clone())) 161 | ); 162 | io.extend_with( 163 | TransactionPaymentApi::to_delegate(TransactionPayment::new(client.clone())) 164 | ); 165 | io.extend_with( 166 | sc_consensus_babe_rpc::BabeApi::to_delegate( 167 | BabeRpcHandler::new( 168 | client.clone(), 169 | shared_epoch_changes.clone(), 170 | keystore, 171 | babe_config, 172 | select_chain, 173 | deny_unsafe, 174 | ), 175 | ) 176 | ); 177 | io.extend_with( 178 | sc_finality_grandpa_rpc::GrandpaApi::to_delegate( 179 | GrandpaRpcHandler::new( 180 | shared_authority_set.clone(), 181 | shared_voter_state, 182 | justification_stream, 183 | subscription_executor, 184 | finality_provider, 185 | ) 186 | ) 187 | ); 188 | 189 | io.extend_with( 190 | sc_sync_state_rpc::SyncStateRpcApi::to_delegate( 191 | sc_sync_state_rpc::SyncStateRpcHandler::new( 192 | chain_spec, 193 | client, 194 | shared_authority_set, 195 | shared_epoch_changes, 196 | deny_unsafe, 197 | ) 198 | ) 199 | ); 200 | 201 | io 202 | } 203 | 204 | /// Instantiate all Light RPC extensions. 205 | pub fn create_light( 206 | deps: LightDeps, 207 | ) -> jsonrpc_core::IoHandler where 208 | C: sp_blockchain::HeaderBackend, 209 | C: Send + Sync + 'static, 210 | F: sc_client_api::light::Fetcher + 'static, 211 | P: TransactionPool + 'static, 212 | M: jsonrpc_core::Metadata + Default, 213 | { 214 | use substrate_frame_rpc_system::{LightSystem, SystemApi}; 215 | 216 | let LightDeps { 217 | client, 218 | pool, 219 | remote_blockchain, 220 | fetcher 221 | } = deps; 222 | let mut io = jsonrpc_core::IoHandler::default(); 223 | io.extend_with( 224 | SystemApi::::to_delegate(LightSystem::new(client, remote_blockchain, fetcher, pool)) 225 | ); 226 | 227 | io 228 | } 229 | -------------------------------------------------------------------------------- /runtime/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "node-runtime" 3 | build = "build.rs" 4 | edition = "2018" 5 | version = "2.0.0" 6 | authors = ["trust dev"] 7 | license = 'Apache-2.0' 8 | 9 | [package.metadata.docs.rs] 10 | targets = ["x86_64-unknown-linux-gnu"] 11 | 12 | [dependencies] 13 | 14 | # third-party dependencies 15 | codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } 16 | static_assertions = "1.1.0" 17 | hex-literal = { version = "0.3.1", optional = true } 18 | log = { version = "0.4.14", default-features = false } 19 | 20 | # primitives 21 | sp-authority-discovery = { version = "3.0.0", default-features = false, git = "https://github.com/paritytech/substrate" } 22 | sp-consensus-babe = { version = "0.9.0", default-features = false, git = "https://github.com/paritytech/substrate" } 23 | sp-block-builder = { git = "https://github.com/paritytech/substrate", default-features = false, version = "3.0.0"} 24 | sp-inherents = { version = "3.0.0", default-features = false, git = "https://github.com/paritytech/substrate" } 25 | node-primitives = { version = "2.0.0", default-features = false, path = "../primitives" } 26 | sp-offchain = { version = "3.0.0", default-features = false, git = "https://github.com/paritytech/substrate" } 27 | sp-core = { version = "3.0.0", default-features = false, git = "https://github.com/paritytech/substrate" } 28 | sp-std = { version = "3.0.0", default-features = false, git = "https://github.com/paritytech/substrate" } 29 | sp-api = { version = "3.0.0", default-features = false, git = "https://github.com/paritytech/substrate" } 30 | sp-runtime = { version = "3.0.0", default-features = false, git = "https://github.com/paritytech/substrate" } 31 | sp-staking = { version = "3.0.0", default-features = false, git = "https://github.com/paritytech/substrate" } 32 | sp-keyring = { version = "3.0.0", optional = true, git = "https://github.com/paritytech/substrate" } 33 | sp-session = { version = "3.0.0", default-features = false, git = "https://github.com/paritytech/substrate" } 34 | sp-transaction-pool = { version = "3.0.0", default-features = false, git = "https://github.com/paritytech/substrate" } 35 | sp-version = { version = "3.0.0", default-features = false, git = "https://github.com/paritytech/substrate" } 36 | sp-npos-elections = { version = "3.0.0", default-features = false, git = "https://github.com/paritytech/substrate" } 37 | 38 | # frame dependencies 39 | frame-executive = { version = "3.0.0", default-features = false, git = "https://github.com/paritytech/substrate" } 40 | frame-benchmarking = { version = "3.1.0", default-features = false, git = "https://github.com/paritytech/substrate", optional = true } 41 | frame-support = { version = "3.0.0", default-features = false, git = "https://github.com/paritytech/substrate" } 42 | frame-system = { version = "3.0.0", default-features = false, git = "https://github.com/paritytech/substrate" } 43 | frame-system-benchmarking = { version = "3.0.0", default-features = false, git = "https://github.com/paritytech/substrate", optional = true } 44 | frame-election-provider-support = { version = "3.0.0", default-features = false, git = "https://github.com/paritytech/substrate" } 45 | frame-system-rpc-runtime-api = { version = "3.0.0", default-features = false, git = "https://github.com/paritytech/substrate" } 46 | frame-try-runtime = { version = "0.9.0", default-features = false, git = "https://github.com/paritytech/substrate", optional = true } 47 | pallet-assets = { version = "3.0.0", default-features = false, git = "https://github.com/paritytech/substrate" } 48 | pallet-authority-discovery = { version = "3.0.0", default-features = false, git = "https://github.com/paritytech/substrate" } 49 | pallet-authorship = { version = "3.0.0", default-features = false, git = "https://github.com/paritytech/substrate" } 50 | pallet-babe = { version = "3.0.0", default-features = false, git = "https://github.com/paritytech/substrate" } 51 | pallet-balances = { version = "3.0.0", default-features = false, git = "https://github.com/paritytech/substrate" } 52 | pallet-bounties = { version = "3.0.0", default-features = false, git = "https://github.com/paritytech/substrate" } 53 | pallet-collective = { version = "3.0.0", default-features = false, git = "https://github.com/paritytech/substrate" } 54 | pallet-contracts = { version = "3.0.0", default-features = false, git = "https://github.com/paritytech/substrate" } 55 | pallet-contracts-primitives = { version = "3.0.0", default-features = false, git = "https://github.com/paritytech/substrate" } 56 | pallet-contracts-rpc-runtime-api = { version = "3.0.0", default-features = false, git = "https://github.com/paritytech/substrate" } 57 | pallet-democracy = { version = "3.0.0", default-features = false, git = "https://github.com/paritytech/substrate" } 58 | pallet-election-provider-multi-phase = { version = "3.0.0", default-features = false, git = "https://github.com/paritytech/substrate" } 59 | pallet-elections-phragmen = { version = "4.0.0", default-features = false, git = "https://github.com/paritytech/substrate" } 60 | pallet-gilt = { version = "3.0.0", default-features = false, git = "https://github.com/paritytech/substrate" } 61 | pallet-grandpa = { version = "3.1.0", default-features = false, git = "https://github.com/paritytech/substrate" } 62 | pallet-im-online = { version = "3.0.0", default-features = false, git = "https://github.com/paritytech/substrate" } 63 | pallet-indices = { version = "3.0.0", default-features = false, git = "https://github.com/paritytech/substrate" } 64 | pallet-identity = { version = "3.0.0", default-features = false, git = "https://github.com/paritytech/substrate" } 65 | pallet-lottery = { version = "3.0.0", default-features = false, git = "https://github.com/paritytech/substrate" } 66 | pallet-membership = { version = "3.0.0", default-features = false, git = "https://github.com/paritytech/substrate" } 67 | pallet-mmr = { version = "3.0.0", default-features = false, git = "https://github.com/paritytech/substrate" } 68 | pallet-multisig = { version = "3.0.0", default-features = false, git = "https://github.com/paritytech/substrate" } 69 | pallet-offences = { version = "3.0.0", default-features = false, git = "https://github.com/paritytech/substrate" } 70 | pallet-offences-benchmarking = { version = "3.0.0", git = "https://github.com/paritytech/substrate", default-features = false, optional = true } 71 | pallet-proxy = { version = "3.0.0", default-features = false, git = "https://github.com/paritytech/substrate" } 72 | pallet-randomness-collective-flip = { version = "3.0.0", default-features = false, git = "https://github.com/paritytech/substrate" } 73 | pallet-recovery = { version = "3.0.0", default-features = false, git = "https://github.com/paritytech/substrate" } 74 | pallet-session = { version = "3.0.0", features = ["historical"], git = "https://github.com/paritytech/substrate", default-features = false } 75 | pallet-session-benchmarking = { version = "3.0.0", git = "https://github.com/paritytech/substrate", default-features = false, optional = true } 76 | pallet-staking = { version = "3.0.0", default-features = false, git = "https://github.com/paritytech/substrate" } 77 | pallet-staking-reward-curve = { version = "3.0.0", default-features = false, git = "https://github.com/paritytech/substrate" } 78 | pallet-scheduler = { version = "3.0.0", default-features = false, git = "https://github.com/paritytech/substrate" } 79 | pallet-society = { version = "3.0.0", default-features = false, git = "https://github.com/paritytech/substrate" } 80 | pallet-sudo = { version = "3.0.0", default-features = false, git = "https://github.com/paritytech/substrate" } 81 | pallet-timestamp = { version = "3.0.0", default-features = false, git = "https://github.com/paritytech/substrate" } 82 | pallet-tips = { version = "3.0.0", default-features = false, git = "https://github.com/paritytech/substrate" } 83 | pallet-treasury = { version = "3.0.0", default-features = false, git = "https://github.com/paritytech/substrate" } 84 | pallet-utility = { version = "3.0.0", default-features = false, git = "https://github.com/paritytech/substrate" } 85 | pallet-transaction-payment = { version = "3.0.0", default-features = false, git = "https://github.com/paritytech/substrate" } 86 | pallet-transaction-payment-rpc-runtime-api = { version = "3.0.0", default-features = false, git = "https://github.com/paritytech/substrate" } 87 | pallet-transaction-storage = { version = "3.0.0", default-features = false, git = "https://github.com/paritytech/substrate" } 88 | pallet-uniques = { version = "3.0.0", default-features = false, git = "https://github.com/paritytech/substrate" } 89 | pallet-vesting = { version = "3.0.0", default-features = false, git = "https://github.com/paritytech/substrate" } 90 | 91 | max-encoded-len = { version = "3.0.0", default-features = false, git = "https://github.com/paritytech/substrate", features = [ "derive" ] } 92 | [build-dependencies] 93 | substrate-wasm-builder = { version = "4.0.0", git = "https://github.com/paritytech/substrate" } 94 | 95 | [dev-dependencies] 96 | sp-io = { version = "3.0.0", git = "https://github.com/paritytech/substrate" } 97 | 98 | [features] 99 | default = ["std"] 100 | with-tracing = [ "frame-executive/with-tracing" ] 101 | std = [ 102 | "sp-authority-discovery/std", 103 | "pallet-assets/std", 104 | "pallet-authority-discovery/std", 105 | "pallet-authorship/std", 106 | "sp-consensus-babe/std", 107 | "pallet-babe/std", 108 | "pallet-balances/std", 109 | "pallet-bounties/std", 110 | "sp-block-builder/std", 111 | "codec/std", 112 | "pallet-collective/std", 113 | "pallet-contracts/std", 114 | "pallet-contracts-primitives/std", 115 | "pallet-contracts-rpc-runtime-api/std", 116 | "pallet-democracy/std", 117 | "pallet-elections-phragmen/std", 118 | "frame-executive/std", 119 | "pallet-gilt/std", 120 | "pallet-grandpa/std", 121 | "pallet-im-online/std", 122 | "pallet-indices/std", 123 | "sp-inherents/std", 124 | "pallet-lottery/std", 125 | "pallet-membership/std", 126 | "pallet-mmr/std", 127 | "pallet-multisig/std", 128 | "pallet-identity/std", 129 | "pallet-scheduler/std", 130 | "node-primitives/std", 131 | "sp-offchain/std", 132 | "pallet-offences/std", 133 | "pallet-proxy/std", 134 | "sp-core/std", 135 | "pallet-randomness-collective-flip/std", 136 | "sp-std/std", 137 | "pallet-session/std", 138 | "sp-api/std", 139 | "sp-runtime/std", 140 | "sp-staking/std", 141 | "pallet-staking/std", 142 | "sp-keyring", 143 | "sp-session/std", 144 | "pallet-sudo/std", 145 | "frame-support/std", 146 | "frame-benchmarking/std", 147 | "frame-system-rpc-runtime-api/std", 148 | "frame-system/std", 149 | "pallet-election-provider-multi-phase/std", 150 | "pallet-timestamp/std", 151 | "pallet-tips/std", 152 | "pallet-transaction-payment-rpc-runtime-api/std", 153 | "pallet-transaction-payment/std", 154 | "pallet-transaction-storage/std", 155 | "pallet-treasury/std", 156 | "sp-transaction-pool/std", 157 | "pallet-utility/std", 158 | "sp-version/std", 159 | "pallet-society/std", 160 | "pallet-recovery/std", 161 | "pallet-uniques/std", 162 | "pallet-vesting/std", 163 | "log/std", 164 | "frame-try-runtime/std", 165 | "sp-npos-elections/std", 166 | "max-encoded-len/std", 167 | ] 168 | runtime-benchmarks = [ 169 | "frame-benchmarking", 170 | "frame-support/runtime-benchmarks", 171 | "frame-system/runtime-benchmarks", 172 | "pallet-election-provider-multi-phase/runtime-benchmarks", 173 | "sp-runtime/runtime-benchmarks", 174 | "pallet-assets/runtime-benchmarks", 175 | "pallet-babe/runtime-benchmarks", 176 | "pallet-balances/runtime-benchmarks", 177 | "pallet-bounties/runtime-benchmarks", 178 | "pallet-collective/runtime-benchmarks", 179 | "pallet-contracts/runtime-benchmarks", 180 | "pallet-democracy/runtime-benchmarks", 181 | "pallet-elections-phragmen/runtime-benchmarks", 182 | "pallet-gilt/runtime-benchmarks", 183 | "pallet-grandpa/runtime-benchmarks", 184 | "pallet-identity/runtime-benchmarks", 185 | "pallet-im-online/runtime-benchmarks", 186 | "pallet-indices/runtime-benchmarks", 187 | "pallet-lottery/runtime-benchmarks", 188 | "pallet-membership/runtime-benchmarks", 189 | "pallet-mmr/runtime-benchmarks", 190 | "pallet-multisig/runtime-benchmarks", 191 | "pallet-proxy/runtime-benchmarks", 192 | "pallet-scheduler/runtime-benchmarks", 193 | "pallet-society/runtime-benchmarks", 194 | "pallet-staking/runtime-benchmarks", 195 | "pallet-timestamp/runtime-benchmarks", 196 | "pallet-tips/runtime-benchmarks", 197 | "pallet-transaction-storage/runtime-benchmarks", 198 | "pallet-treasury/runtime-benchmarks", 199 | "pallet-utility/runtime-benchmarks", 200 | "pallet-uniques/runtime-benchmarks", 201 | "pallet-vesting/runtime-benchmarks", 202 | "pallet-offences-benchmarking", 203 | "pallet-session-benchmarking", 204 | "frame-system-benchmarking", 205 | "hex-literal", 206 | ] 207 | try-runtime = [ 208 | "frame-executive/try-runtime", 209 | "frame-try-runtime", 210 | "frame-system/try-runtime", 211 | "pallet-assets/try-runtime", 212 | "pallet-authority-discovery/try-runtime", 213 | "pallet-authorship/try-runtime", 214 | "pallet-babe/try-runtime", 215 | "pallet-balances/try-runtime", 216 | "pallet-bounties/try-runtime", 217 | "pallet-collective/try-runtime", 218 | "pallet-contracts/try-runtime", 219 | "pallet-democracy/try-runtime", 220 | "pallet-elections-phragmen/try-runtime", 221 | "pallet-grandpa/try-runtime", 222 | "pallet-im-online/try-runtime", 223 | "pallet-indices/try-runtime", 224 | "pallet-lottery/try-runtime", 225 | "pallet-membership/try-runtime", 226 | "pallet-mmr/try-runtime", 227 | "pallet-multisig/try-runtime", 228 | "pallet-identity/try-runtime", 229 | "pallet-scheduler/try-runtime", 230 | "pallet-offences/try-runtime", 231 | "pallet-proxy/try-runtime", 232 | "pallet-randomness-collective-flip/try-runtime", 233 | "pallet-session/try-runtime", 234 | "pallet-staking/try-runtime", 235 | "pallet-sudo/try-runtime", 236 | "pallet-election-provider-multi-phase/try-runtime", 237 | "pallet-timestamp/try-runtime", 238 | "pallet-tips/try-runtime", 239 | "pallet-transaction-payment/try-runtime", 240 | "pallet-treasury/try-runtime", 241 | "pallet-utility/try-runtime", 242 | "pallet-society/try-runtime", 243 | "pallet-recovery/try-runtime", 244 | "pallet-uniques/try-runtime", 245 | "pallet-vesting/try-runtime", 246 | "pallet-gilt/try-runtime", 247 | ] 248 | # Make contract callable functions marked as __unstable__ available. Do not enable 249 | # on live chains as those are subject to change. 250 | contracts-unstable-interface = [ 251 | "pallet-contracts/unstable-interface" 252 | ] 253 | -------------------------------------------------------------------------------- /runtime/build.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2019 TrustBase Network 2 | // This file is part of TrustBase library. 3 | // 4 | // The TrustBase library is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU Lesser General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // The TrustBase library is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU Lesser General Public License for more details. 13 | 14 | use substrate_wasm_builder::WasmBuilder; 15 | 16 | fn main() { 17 | WasmBuilder::new() 18 | .with_current_project() 19 | .export_heap_base() 20 | .import_memory() 21 | .build() 22 | } 23 | -------------------------------------------------------------------------------- /runtime/src/constants.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2019 TrustBase Network 2 | // This file is part of TrustBase library. 3 | // 4 | // The TrustBase library is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU Lesser General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // The TrustBase library is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU Lesser General Public License for more details. 13 | 14 | //! A set of constant values used in trustbase runtime. 15 | 16 | /// Money matters. 17 | pub mod currency { 18 | use node_primitives::Balance; 19 | 20 | pub const MILLICENTS: Balance = 1_000_000_000; 21 | pub const CENTS: Balance = 1_000 * MILLICENTS; // assume this is worth about a cent. 22 | pub const DOLLARS: Balance = 100 * CENTS; 23 | 24 | pub const fn deposit(items: u32, bytes: u32) -> Balance { 25 | items as Balance * 15 * CENTS + (bytes as Balance) * 6 * CENTS 26 | } 27 | } 28 | 29 | /// Time. 30 | pub mod time { 31 | use node_primitives::{Moment, BlockNumber}; 32 | 33 | /// Since BABE is probabilistic this is the average expected block time that 34 | /// we are targeting. Blocks will be produced at a minimum duration defined 35 | /// by `SLOT_DURATION`, but some slots will not be allocated to any 36 | /// authority and hence no block will be produced. We expect to have this 37 | /// block time on average following the defined slot duration and the value 38 | /// of `c` configured for BABE (where `1 - c` represents the probability of 39 | /// a slot being empty). 40 | /// This value is only used indirectly to define the unit constants below 41 | /// that are expressed in blocks. The rest of the code should use 42 | /// `SLOT_DURATION` instead (like the Timestamp pallet for calculating the 43 | /// minimum period). 44 | /// 45 | /// If using BABE with secondary slots (default) then all of the slots will 46 | /// always be assigned, in which case `MILLISECS_PER_BLOCK` and 47 | /// `SLOT_DURATION` should have the same value. 48 | /// 49 | /// 50 | pub const MILLISECS_PER_BLOCK: Moment = 3000; 51 | pub const SECS_PER_BLOCK: Moment = MILLISECS_PER_BLOCK / 1000; 52 | 53 | // NOTE: Currently it is not possible to change the slot duration after the chain has started. 54 | // Attempting to do so will brick block production. 55 | pub const SLOT_DURATION: Moment = MILLISECS_PER_BLOCK; 56 | 57 | // 1 in 4 blocks (on average, not counting collisions) will be primary BABE blocks. 58 | pub const PRIMARY_PROBABILITY: (u64, u64) = (1, 4); 59 | 60 | // NOTE: Currently it is not possible to change the epoch duration after the chain has started. 61 | // Attempting to do so will brick block production. 62 | pub const EPOCH_DURATION_IN_BLOCKS: BlockNumber = 10 * MINUTES; 63 | pub const EPOCH_DURATION_IN_SLOTS: u64 = { 64 | const SLOT_FILL_RATE: f64 = MILLISECS_PER_BLOCK as f64 / SLOT_DURATION as f64; 65 | 66 | (EPOCH_DURATION_IN_BLOCKS as f64 * SLOT_FILL_RATE) as u64 67 | }; 68 | 69 | // These time units are defined in number of blocks. 70 | pub const MINUTES: BlockNumber = 60 / (SECS_PER_BLOCK as BlockNumber); 71 | pub const HOURS: BlockNumber = MINUTES * 60; 72 | pub const DAYS: BlockNumber = HOURS * 24; 73 | } 74 | -------------------------------------------------------------------------------- /runtime/src/impls.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2019 TrustBase Network 2 | // This file is part of TrustBase library. 3 | // 4 | // The TrustBase library is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU Lesser General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // The TrustBase library is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU Lesser General Public License for more details. 13 | 14 | //! Some configurable implementations as associated type for the trustbase runtime. 15 | 16 | use frame_support::traits::{OnUnbalanced, Currency}; 17 | use crate::{Balances, Authorship, NegativeImbalance}; 18 | 19 | pub struct Author; 20 | impl OnUnbalanced for Author { 21 | fn on_nonzero_unbalanced(amount: NegativeImbalance) { 22 | Balances::resolve_creating(&Authorship::author(), amount); 23 | } 24 | } 25 | 26 | #[cfg(test)] 27 | mod multiplier_tests { 28 | use sp_runtime::{assert_eq_error_rate, FixedPointNumber, traits::Convert}; 29 | use pallet_transaction_payment::{Multiplier, TargetedFeeAdjustment}; 30 | 31 | use crate::{ 32 | constants::{currency::*, time::*}, 33 | TransactionPayment, Runtime, TargetBlockFullness, 34 | AdjustmentVariable, System, MinimumMultiplier, 35 | RuntimeBlockWeights as BlockWeights, 36 | }; 37 | use frame_support::weights::{Weight, WeightToFeePolynomial, DispatchClass}; 38 | 39 | fn max_normal() -> Weight { 40 | BlockWeights::get().get(DispatchClass::Normal).max_total 41 | .unwrap_or_else(|| BlockWeights::get().max_block) 42 | } 43 | 44 | fn min_multiplier() -> Multiplier { 45 | MinimumMultiplier::get() 46 | } 47 | 48 | fn target() -> Weight { 49 | TargetBlockFullness::get() * max_normal() 50 | } 51 | 52 | // update based on runtime impl. 53 | fn runtime_multiplier_update(fm: Multiplier) -> Multiplier { 54 | TargetedFeeAdjustment::< 55 | Runtime, 56 | TargetBlockFullness, 57 | AdjustmentVariable, 58 | MinimumMultiplier, 59 | >::convert(fm) 60 | } 61 | 62 | // update based on reference impl. 63 | fn truth_value_update(block_weight: Weight, previous: Multiplier) -> Multiplier { 64 | let accuracy = Multiplier::accuracy() as f64; 65 | let previous_float = previous.into_inner() as f64 / accuracy; 66 | // bump if it is zero. 67 | let previous_float = previous_float.max(min_multiplier().into_inner() as f64 / accuracy); 68 | 69 | // maximum tx weight 70 | let m = max_normal() as f64; 71 | // block weight always truncated to max weight 72 | let block_weight = (block_weight as f64).min(m); 73 | let v: f64 = AdjustmentVariable::get().to_fraction(); 74 | 75 | // Ideal saturation in terms of weight 76 | let ss = target() as f64; 77 | // Current saturation in terms of weight 78 | let s = block_weight; 79 | 80 | let t1 = v * (s/m - ss/m); 81 | let t2 = v.powi(2) * (s/m - ss/m).powi(2) / 2.0; 82 | let next_float = previous_float * (1.0 + t1 + t2); 83 | Multiplier::from_float(next_float) 84 | } 85 | 86 | fn run_with_system_weight(w: Weight, assertions: F) where F: Fn() -> () { 87 | let mut t: sp_io::TestExternalities = 88 | frame_system::GenesisConfig::default().build_storage::().unwrap().into(); 89 | t.execute_with(|| { 90 | System::set_block_consumed_resources(w, 0); 91 | assertions() 92 | }); 93 | } 94 | 95 | #[test] 96 | fn truth_value_update_poc_works() { 97 | let fm = Multiplier::saturating_from_rational(1, 2); 98 | let test_set = vec![ 99 | (0, fm.clone()), 100 | (100, fm.clone()), 101 | (1000, fm.clone()), 102 | (target(), fm.clone()), 103 | (max_normal() / 2, fm.clone()), 104 | (max_normal(), fm.clone()), 105 | ]; 106 | test_set.into_iter().for_each(|(w, fm)| { 107 | run_with_system_weight(w, || { 108 | assert_eq_error_rate!( 109 | truth_value_update(w, fm), 110 | runtime_multiplier_update(fm), 111 | // Error is only 1 in 100^18 112 | Multiplier::from_inner(100), 113 | ); 114 | }) 115 | }) 116 | } 117 | 118 | #[test] 119 | fn multiplier_can_grow_from_zero() { 120 | // if the min is too small, then this will not change, and we are doomed forever. 121 | // the weight is 1/100th bigger than target. 122 | run_with_system_weight(target() * 101 / 100, || { 123 | let next = runtime_multiplier_update(min_multiplier()); 124 | assert!(next > min_multiplier(), "{:?} !>= {:?}", next, min_multiplier()); 125 | }) 126 | } 127 | 128 | #[test] 129 | fn multiplier_cannot_go_below_limit() { 130 | // will not go any further below even if block is empty. 131 | run_with_system_weight(0, || { 132 | let next = runtime_multiplier_update(min_multiplier()); 133 | assert_eq!(next, min_multiplier()); 134 | }) 135 | } 136 | 137 | #[test] 138 | fn time_to_reach_zero() { 139 | // blocks per 24h in trustbase-node: 28,800 (k) 140 | // s* = 0.1875 141 | // The bound from the research in an empty chain is: 142 | // v <~ (p / k(0 - s*)) 143 | // p > v * k * -0.1875 144 | // to get p == -1 we'd need 145 | // -1 > 0.00001 * k * -0.1875 146 | // 1 < 0.00001 * k * 0.1875 147 | // 10^9 / 1875 < k 148 | // k > 533_333 ~ 18,5 days. 149 | run_with_system_weight(0, || { 150 | // start from 1, the default. 151 | let mut fm = Multiplier::one(); 152 | let mut iterations: u64 = 0; 153 | loop { 154 | let next = runtime_multiplier_update(fm); 155 | fm = next; 156 | if fm == min_multiplier() { break; } 157 | iterations += 1; 158 | } 159 | assert!(iterations > 533_333); 160 | }) 161 | } 162 | 163 | #[test] 164 | fn min_change_per_day() { 165 | run_with_system_weight(max_normal(), || { 166 | let mut fm = Multiplier::one(); 167 | // See the example in the doc of `TargetedFeeAdjustment`. are at least 0.234, hence 168 | // `fm > 1.234`. 169 | for _ in 0..DAYS { 170 | let next = runtime_multiplier_update(fm); 171 | fm = next; 172 | } 173 | assert!(fm > Multiplier::saturating_from_rational(1234, 1000)); 174 | }) 175 | } 176 | 177 | #[test] 178 | #[ignore] 179 | fn congested_chain_simulation() { 180 | // `cargo test congested_chain_simulation -- --nocapture` to get some insight. 181 | 182 | // almost full. The entire quota of normal transactions is taken. 183 | let block_weight = BlockWeights::get().get(DispatchClass::Normal).max_total.unwrap() - 100; 184 | 185 | // Default trustbase weight. 186 | let tx_weight = frame_support::weights::constants::ExtrinsicBaseWeight::get(); 187 | 188 | run_with_system_weight(block_weight, || { 189 | // initial value configured on module 190 | let mut fm = Multiplier::one(); 191 | assert_eq!(fm, TransactionPayment::next_fee_multiplier()); 192 | 193 | let mut iterations: u64 = 0; 194 | loop { 195 | let next = runtime_multiplier_update(fm); 196 | // if no change, panic. This should never happen in this case. 197 | if fm == next { panic!("The fee should ever increase"); } 198 | fm = next; 199 | iterations += 1; 200 | let fee = 201 | ::WeightToFee::calc(&tx_weight); 202 | let adjusted_fee = fm.saturating_mul_acc_int(fee); 203 | println!( 204 | "iteration {}, new fm = {:?}. Fee at this point is: {} units / {} millicents, \ 205 | {} cents, {} dollars", 206 | iterations, 207 | fm, 208 | adjusted_fee, 209 | adjusted_fee / MILLICENTS, 210 | adjusted_fee / CENTS, 211 | adjusted_fee / DOLLARS, 212 | ); 213 | } 214 | }); 215 | } 216 | 217 | #[test] 218 | fn stateless_weight_mul() { 219 | let fm = Multiplier::saturating_from_rational(1, 2); 220 | run_with_system_weight(target() / 4, || { 221 | let next = runtime_multiplier_update(fm); 222 | assert_eq_error_rate!( 223 | next, 224 | truth_value_update(target() / 4 , fm), 225 | Multiplier::from_inner(100), 226 | ); 227 | 228 | // Light block. Multiplier is reduced a little. 229 | assert!(next < fm); 230 | }); 231 | 232 | run_with_system_weight(target() / 2, || { 233 | let next = runtime_multiplier_update(fm); 234 | assert_eq_error_rate!( 235 | next, 236 | truth_value_update(target() / 2 , fm), 237 | Multiplier::from_inner(100), 238 | ); 239 | // Light block. Multiplier is reduced a little. 240 | assert!(next < fm); 241 | 242 | }); 243 | run_with_system_weight(target(), || { 244 | let next = runtime_multiplier_update(fm); 245 | assert_eq_error_rate!( 246 | next, 247 | truth_value_update(target(), fm), 248 | Multiplier::from_inner(100), 249 | ); 250 | // ideal. No changes. 251 | assert_eq!(next, fm) 252 | }); 253 | run_with_system_weight(target() * 2, || { 254 | // More than ideal. Fee is increased. 255 | let next = runtime_multiplier_update(fm); 256 | assert_eq_error_rate!( 257 | next, 258 | truth_value_update(target() * 2 , fm), 259 | Multiplier::from_inner(100), 260 | ); 261 | 262 | // Heavy block. Fee is increased a little. 263 | assert!(next > fm); 264 | }); 265 | } 266 | 267 | #[test] 268 | fn weight_mul_grow_on_big_block() { 269 | run_with_system_weight(target() * 2, || { 270 | let mut original = Multiplier::zero(); 271 | let mut next = Multiplier::default(); 272 | 273 | (0..1_000).for_each(|_| { 274 | next = runtime_multiplier_update(original); 275 | assert_eq_error_rate!( 276 | next, 277 | truth_value_update(target() * 2, original), 278 | Multiplier::from_inner(100), 279 | ); 280 | // must always increase 281 | assert!(next > original, "{:?} !>= {:?}", next, original); 282 | original = next; 283 | }); 284 | }); 285 | } 286 | 287 | #[test] 288 | fn weight_mul_decrease_on_small_block() { 289 | run_with_system_weight(target() / 2, || { 290 | let mut original = Multiplier::saturating_from_rational(1, 2); 291 | let mut next; 292 | 293 | for _ in 0..100 { 294 | // decreases 295 | next = runtime_multiplier_update(original); 296 | assert!(next < original, "{:?} !<= {:?}", next, original); 297 | original = next; 298 | } 299 | }) 300 | } 301 | 302 | #[test] 303 | fn weight_to_fee_should_not_overflow_on_large_weights() { 304 | let kb = 1024 as Weight; 305 | let mb = kb * kb; 306 | let max_fm = Multiplier::saturating_from_integer(i128::max_value()); 307 | 308 | // check that for all values it can compute, correctly. 309 | vec![ 310 | 0, 311 | 1, 312 | 10, 313 | 1000, 314 | kb, 315 | 10 * kb, 316 | 100 * kb, 317 | mb, 318 | 10 * mb, 319 | 2147483647, 320 | 4294967295, 321 | BlockWeights::get().max_block / 2, 322 | BlockWeights::get().max_block, 323 | Weight::max_value() / 2, 324 | Weight::max_value(), 325 | ].into_iter().for_each(|i| { 326 | run_with_system_weight(i, || { 327 | let next = runtime_multiplier_update(Multiplier::one()); 328 | let truth = truth_value_update(i, Multiplier::one()); 329 | assert_eq_error_rate!( 330 | truth, 331 | next, 332 | Multiplier::from_inner(50_000_000) 333 | ); 334 | }); 335 | }); 336 | 337 | // Some values that are all above the target and will cause an increase. 338 | let t = target(); 339 | vec![t + 100, t * 2, t * 4] 340 | .into_iter() 341 | .for_each(|i| { 342 | run_with_system_weight(i, || { 343 | let fm = runtime_multiplier_update(max_fm); 344 | // won't grow. The convert saturates everything. 345 | assert_eq!(fm, max_fm); 346 | }) 347 | }); 348 | } 349 | } 350 | -------------------------------------------------------------------------------- /scripts/init.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | 5 | echo "*** Initializing WASM build environment" 6 | 7 | if [ -z $CI_PROJECT_NAME ] ; then 8 | rustup update nightly 9 | rustup update stable 10 | fi 11 | 12 | rustup target add wasm32-unknown-unknown --toolchain nightly 13 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2019 TrustBase Network 2 | // This file is part of TrustBase library. 3 | // 4 | // The TrustBase library is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU Lesser General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | // 9 | 10 | fn main() -> node_cli::Result<()> { 11 | node_cli::run() 12 | } 13 | -------------------------------------------------------------------------------- /testing/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "node-testing" 3 | version = "2.0.0" 4 | authors = ["trust dev"] 5 | license = 'Apache-2.0' 6 | edition = "2018" 7 | publish = true 8 | 9 | [package.metadata.docs.rs] 10 | targets = ["x86_64-unknown-linux-gnu"] 11 | 12 | [dependencies] 13 | pallet-balances = { version = "3.0.0", git = "https://github.com/paritytech/substrate" } 14 | sc-service = { version = "0.9.0", features = ["test-helpers", "db"], git = "https://github.com/paritytech/substrate" } 15 | sc-client-db = { version = "0.9.0", git = "https://github.com/paritytech/substrate", features = ["kvdb-rocksdb", "parity-db"] } 16 | sc-client-api = { version = "3.0.0", git = "https://github.com/paritytech/substrate" } 17 | codec = { package = "parity-scale-codec", version = "2.0.0" } 18 | pallet-contracts = { version = "3.0.0", git = "https://github.com/paritytech/substrate" } 19 | pallet-grandpa = { version = "3.1.0", git = "https://github.com/paritytech/substrate" } 20 | pallet-indices = { version = "3.0.0", git = "https://github.com/paritytech/substrate" } 21 | sp-keyring = { version = "3.0.0", git = "https://github.com/paritytech/substrate" } 22 | node-executor = { version = "2.0.0", git = "https://github.com/paritytech/substrate" } 23 | node-primitives = { version = "2.0.0", git = "https://github.com/paritytech/substrate" } 24 | node-runtime = { version = "2.0.0", git = "https://github.com/paritytech/substrate" } 25 | sp-core = { version = "3.0.0", git = "https://github.com/paritytech/substrate" } 26 | sp-io = { version = "3.0.0", git = "https://github.com/paritytech/substrate" } 27 | frame-support = { version = "3.0.0", git = "https://github.com/paritytech/substrate" } 28 | pallet-session = { version = "3.0.0", git = "https://github.com/paritytech/substrate" } 29 | pallet-society = { version = "3.0.0", git = "https://github.com/paritytech/substrate" } 30 | sp-runtime = { version = "3.0.0", git = "https://github.com/paritytech/substrate" } 31 | pallet-staking = { version = "3.0.0", git = "https://github.com/paritytech/substrate" } 32 | sc-executor = { version = "0.9.0", git = "https://github.com/paritytech/substrate", features = ["wasmtime"] } 33 | sp-consensus = { version = "0.9.0", git = "https://github.com/paritytech/substrate" } 34 | frame-system = { version = "3.0.0", git = "https://github.com/paritytech/substrate" } 35 | substrate-test-client = { version = "2.0.0", git = "https://github.com/paritytech/substrate" } 36 | pallet-timestamp = { version = "3.0.0", git = "https://github.com/paritytech/substrate" } 37 | pallet-transaction-payment = { version = "3.0.0", git = "https://github.com/paritytech/substrate" } 38 | pallet-treasury = { version = "3.0.0", git = "https://github.com/paritytech/substrate" } 39 | sp-api = { version = "3.0.0", git = "https://github.com/paritytech/substrate" } 40 | sp-timestamp = { version = "3.0.0", default-features = false, git = "https://github.com/paritytech/substrate" } 41 | sp-block-builder = { version = "3.0.0", git = "https://github.com/paritytech/substrate" } 42 | sc-block-builder = { version = "0.9.0", git = "https://github.com/paritytech/substrate" } 43 | sp-inherents = { version = "3.0.0", git = "https://github.com/paritytech/substrate" } 44 | sp-blockchain = { version = "3.0.0", git = "https://github.com/paritytech/substrate" } 45 | log = "0.4.8" 46 | tempfile = "3.1.0" 47 | fs_extra = "1" 48 | futures = "0.3.1" 49 | 50 | [dev-dependencies] 51 | criterion = "0.3.0" 52 | sc-cli = { version = "0.9.0", git = "https://github.com/paritytech/substrate" } 53 | -------------------------------------------------------------------------------- /testing/src/bench.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2019 TrustBase Network 2 | // This file is part of TrustBase library. 3 | // 4 | // The TrustBase library is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU Lesser General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // The TrustBase library is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU Lesser General Public License for more details. 13 | //! Benchmarking module. 14 | //! 15 | //! Utilities to do full-scale benchmarks involving database. With `BenchDb` you 16 | //! can pregenerate seed database and `clone` it for every iteration of your benchmarks 17 | //! or tests to get consistent, smooth benchmark experience! 18 | 19 | use std::{sync::Arc, path::{Path, PathBuf}, collections::BTreeMap}; 20 | 21 | use node_primitives::Block; 22 | use crate::client::{Client, Backend}; 23 | use crate::keyring::*; 24 | use sc_client_db::PruningMode; 25 | use sc_executor::{NativeExecutor, WasmExecutionMethod}; 26 | use sp_consensus::{ 27 | BlockOrigin, BlockImport, BlockImportParams, 28 | ForkChoiceStrategy, ImportResult, ImportedAux 29 | }; 30 | use sp_runtime::{ 31 | generic::BlockId, 32 | OpaqueExtrinsic, 33 | traits::{Block as BlockT, Verify, Zero, IdentifyAccount}, 34 | }; 35 | use codec::{Decode, Encode}; 36 | use node_runtime::{ 37 | Call, 38 | CheckedExtrinsic, 39 | constants::currency::DOLLARS, 40 | UncheckedExtrinsic, 41 | MinimumPeriod, 42 | SystemCall, 43 | BalancesCall, 44 | AccountId, 45 | Signature, 46 | }; 47 | use sp_core::{ExecutionContext, blake2_256, traits::SpawnNamed, Pair, Public, sr25519, ed25519}; 48 | use sp_api::ProvideRuntimeApi; 49 | use sp_block_builder::BlockBuilder; 50 | use sp_inherents::InherentData; 51 | use sc_client_api::{ 52 | ExecutionStrategy, BlockBackend, 53 | execution_extensions::{ExecutionExtensions, ExecutionStrategies}, 54 | }; 55 | use sc_block_builder::BlockBuilderProvider; 56 | use futures::executor; 57 | 58 | /// Keyring full of accounts for benching. 59 | /// 60 | /// Accounts are ordered: 61 | /// //endowed-user//00 62 | /// //endowed-user//01 63 | /// ... 64 | /// //endowed-user//N 65 | #[derive(Clone)] 66 | pub struct BenchKeyring { 67 | accounts: BTreeMap, 68 | } 69 | 70 | #[derive(Clone)] 71 | enum BenchPair { 72 | Sr25519(sr25519::Pair), 73 | Ed25519(ed25519::Pair), 74 | } 75 | 76 | impl BenchPair { 77 | fn sign(&self, payload: &[u8]) -> Signature { 78 | match self { 79 | Self::Sr25519(pair) => pair.sign(payload).into(), 80 | Self::Ed25519(pair) => pair.sign(payload).into(), 81 | } 82 | } 83 | } 84 | 85 | /// Drop system cache. 86 | /// 87 | /// Will panic if cache drop is impossbile. 88 | pub fn drop_system_cache() { 89 | #[cfg(target_os = "windows")] { 90 | log::warn!( 91 | target: "bench-logistics", 92 | "Clearing system cache on windows is not supported. Benchmark might totally be wrong.", 93 | ); 94 | return; 95 | } 96 | 97 | std::process::Command::new("sync") 98 | .output() 99 | .expect("Failed to execute system cache clear"); 100 | 101 | #[cfg(target_os = "linux")] { 102 | log::trace!(target: "bench-logistics", "Clearing system cache..."); 103 | std::process::Command::new("echo") 104 | .args(&["3", ">", "/proc/sys/vm/drop_caches", "2>", "/dev/null"]) 105 | .output() 106 | .expect("Failed to execute system cache clear"); 107 | 108 | let temp = tempfile::tempdir().expect("Failed to spawn tempdir"); 109 | let temp_file_path = format!("of={}/buf", temp.path().to_string_lossy()); 110 | 111 | // this should refill write cache with 2GB of garbage 112 | std::process::Command::new("dd") 113 | .args(&["if=/dev/urandom", &temp_file_path, "bs=64M", "count=32"]) 114 | .output() 115 | .expect("Failed to execute dd for cache clear"); 116 | 117 | // remove tempfile of previous command 118 | std::process::Command::new("rm") 119 | .arg(&temp_file_path) 120 | .output() 121 | .expect("Failed to remove temp file"); 122 | 123 | std::process::Command::new("sync") 124 | .output() 125 | .expect("Failed to execute system cache clear"); 126 | 127 | log::trace!(target: "bench-logistics", "Clearing system cache done!"); 128 | } 129 | 130 | #[cfg(target_os = "macos")] { 131 | log::trace!(target: "bench-logistics", "Clearing system cache..."); 132 | if let Err(err) = std::process::Command::new("purge").output() { 133 | log::error!("purge error {:?}: ", err); 134 | panic!("Could not clear system cache. Run under sudo?"); 135 | } 136 | log::trace!(target: "bench-logistics", "Clearing system cache done!"); 137 | } 138 | } 139 | 140 | /// Pre-initialized benchmarking database. 141 | /// 142 | /// This is prepared database with genesis and keyring 143 | /// that can be cloned and then used for any benchmarking. 144 | pub struct BenchDb { 145 | keyring: BenchKeyring, 146 | directory_guard: Guard, 147 | database_type: DatabaseType, 148 | } 149 | 150 | impl Clone for BenchDb { 151 | fn clone(&self) -> Self { 152 | let keyring = self.keyring.clone(); 153 | let database_type = self.database_type; 154 | let dir = tempfile::tempdir().expect("temp dir creation failed"); 155 | 156 | let seed_dir = self.directory_guard.0.path(); 157 | 158 | log::trace!( 159 | target: "bench-logistics", 160 | "Copying seed db from {} to {}", 161 | seed_dir.to_string_lossy(), 162 | dir.path().to_string_lossy(), 163 | ); 164 | let seed_db_files = std::fs::read_dir(seed_dir) 165 | .expect("failed to list file in seed dir") 166 | .map(|f_result| 167 | f_result.expect("failed to read file in seed db") 168 | .path() 169 | ).collect::>(); 170 | fs_extra::copy_items( 171 | &seed_db_files, 172 | dir.path(), 173 | &fs_extra::dir::CopyOptions::new(), 174 | ).expect("Copy of seed database is ok"); 175 | 176 | // We clear system cache after db clone but before any warmups. 177 | // This populates system cache with some data unrelated to actual 178 | // data we will be quering further under benchmark (like what 179 | // would have happened in real system that queries random entries 180 | // from database). 181 | drop_system_cache(); 182 | 183 | BenchDb { keyring, directory_guard: Guard(dir), database_type } 184 | } 185 | } 186 | 187 | /// Type of block for generation 188 | #[derive(Debug, PartialEq, Clone, Copy)] 189 | pub enum BlockType { 190 | /// Bunch of random transfers. 191 | RandomTransfersKeepAlive, 192 | /// Bunch of random transfers that drain all of the source balance. 193 | RandomTransfersReaping, 194 | /// Bunch of "no-op" calls. 195 | Noop, 196 | } 197 | 198 | impl BlockType { 199 | /// Create block content description with specified number of transactions. 200 | pub fn to_content(self, size: Option) -> BlockContent { 201 | BlockContent { 202 | block_type: self, 203 | size, 204 | } 205 | } 206 | } 207 | 208 | /// Content of the generated block. 209 | #[derive(Clone, Debug)] 210 | pub struct BlockContent { 211 | block_type: BlockType, 212 | size: Option, 213 | } 214 | 215 | /// Type of backend database. 216 | #[derive(Debug, PartialEq, Clone, Copy)] 217 | pub enum DatabaseType { 218 | /// RocksDb backend. 219 | RocksDb, 220 | /// Parity DB backend. 221 | ParityDb, 222 | } 223 | 224 | impl DatabaseType { 225 | fn into_settings(self, path: PathBuf) -> sc_client_db::DatabaseSettingsSrc { 226 | match self { 227 | Self::RocksDb => sc_client_db::DatabaseSettingsSrc::RocksDb { 228 | path, 229 | cache_size: 512, 230 | }, 231 | Self::ParityDb => sc_client_db::DatabaseSettingsSrc::ParityDb { 232 | path, 233 | } 234 | } 235 | } 236 | } 237 | 238 | /// Benchmarking task executor. 239 | /// 240 | /// Uses multiple threads as the regular executable. 241 | #[derive(Debug, Clone)] 242 | pub struct TaskExecutor { 243 | pool: executor::ThreadPool, 244 | } 245 | 246 | impl TaskExecutor { 247 | fn new() -> Self { 248 | Self { 249 | pool: executor::ThreadPool::new() 250 | .expect("Failed to create task executor") 251 | } 252 | } 253 | } 254 | 255 | impl SpawnNamed for TaskExecutor { 256 | fn spawn(&self, _: &'static str, future: futures::future::BoxFuture<'static, ()>) { 257 | self.pool.spawn_ok(future); 258 | } 259 | 260 | fn spawn_blocking(&self, _: &'static str, future: futures::future::BoxFuture<'static, ()>) { 261 | self.pool.spawn_ok(future); 262 | } 263 | } 264 | 265 | /// Iterator for block content. 266 | pub struct BlockContentIterator<'a> { 267 | iteration: usize, 268 | content: BlockContent, 269 | runtime_version: sc_executor::RuntimeVersion, 270 | genesis_hash: node_primitives::Hash, 271 | keyring: &'a BenchKeyring, 272 | } 273 | 274 | impl<'a> BlockContentIterator<'a> { 275 | fn new(content: BlockContent, keyring: &'a BenchKeyring, client: &Client) -> Self { 276 | let runtime_version = client.runtime_version_at(&BlockId::number(0)) 277 | .expect("There should be runtime version at 0"); 278 | 279 | let genesis_hash = client.block_hash(Zero::zero()) 280 | .expect("Database error?") 281 | .expect("Genesis block always exists; qed") 282 | .into(); 283 | 284 | BlockContentIterator { 285 | iteration: 0, 286 | content, 287 | keyring, 288 | runtime_version, 289 | genesis_hash, 290 | } 291 | } 292 | } 293 | 294 | impl<'a> Iterator for BlockContentIterator<'a> { 295 | type Item = OpaqueExtrinsic; 296 | 297 | fn next(&mut self) -> Option { 298 | if self.content.size.map(|size| size <= self.iteration).unwrap_or(false) { 299 | return None; 300 | } 301 | 302 | let sender = self.keyring.at(self.iteration); 303 | let receiver = get_account_id_from_seed::( 304 | &format!("random-user//{}", self.iteration) 305 | ); 306 | 307 | let signed = self.keyring.sign( 308 | CheckedExtrinsic { 309 | signed: Some((sender, signed_extra(0, node_runtime::ExistentialDeposit::get() + 1))), 310 | function: match self.content.block_type { 311 | BlockType::RandomTransfersKeepAlive => { 312 | Call::Balances( 313 | BalancesCall::transfer_keep_alive( 314 | sp_runtime::MultiAddress::Id(receiver), 315 | node_runtime::ExistentialDeposit::get() + 1, 316 | ) 317 | ) 318 | }, 319 | BlockType::RandomTransfersReaping => { 320 | Call::Balances( 321 | BalancesCall::transfer( 322 | sp_runtime::MultiAddress::Id(receiver), 323 | // Transfer so that ending balance would be 1 less than existential deposit 324 | // so that we kill the sender account. 325 | 100*DOLLARS - (node_runtime::ExistentialDeposit::get() - 1), 326 | ) 327 | ) 328 | }, 329 | BlockType::Noop => { 330 | Call::System( 331 | SystemCall::remark(Vec::new()) 332 | ) 333 | }, 334 | }, 335 | }, 336 | self.runtime_version.spec_version, 337 | self.runtime_version.transaction_version, 338 | self.genesis_hash.into(), 339 | ); 340 | 341 | let encoded = Encode::encode(&signed); 342 | 343 | let opaque = OpaqueExtrinsic::decode(&mut &encoded[..]) 344 | .expect("Failed to decode opaque"); 345 | 346 | self.iteration += 1; 347 | 348 | Some(opaque) 349 | } 350 | } 351 | 352 | impl BenchDb { 353 | /// New immutable benchmarking database. 354 | /// 355 | /// See [`BenchDb::new`] method documentation for more information about the purpose 356 | /// of this structure. 357 | pub fn with_key_types( 358 | database_type: DatabaseType, 359 | keyring_length: usize, 360 | key_types: KeyTypes, 361 | ) -> Self { 362 | let keyring = BenchKeyring::new(keyring_length, key_types); 363 | 364 | let dir = tempfile::tempdir().expect("temp dir creation failed"); 365 | log::trace!( 366 | target: "bench-logistics", 367 | "Created seed db at {}", 368 | dir.path().to_string_lossy(), 369 | ); 370 | let (_client, _backend, _task_executor) = Self::bench_client( 371 | database_type, 372 | dir.path(), 373 | Profile::Native, 374 | &keyring, 375 | ); 376 | let directory_guard = Guard(dir); 377 | 378 | BenchDb { keyring, directory_guard, database_type } 379 | } 380 | 381 | /// New immutable benchmarking database. 382 | /// 383 | /// This will generate database files in random temporary directory 384 | /// and keep it there until struct is dropped. 385 | /// 386 | /// You can `clone` this database or you can `create_context` from it 387 | /// (which also does `clone`) to run actual operation against new database 388 | /// which will be identical to the original. 389 | pub fn new(database_type: DatabaseType, keyring_length: usize) -> Self { 390 | Self::with_key_types(database_type, keyring_length, KeyTypes::Sr25519) 391 | } 392 | 393 | // This should return client that is doing everything that full node 394 | // is doing. 395 | // 396 | // - This client should use best wasm execution method. 397 | // - This client should work with real database only. 398 | fn bench_client( 399 | database_type: DatabaseType, 400 | dir: &std::path::Path, 401 | profile: Profile, 402 | keyring: &BenchKeyring, 403 | ) -> (Client, std::sync::Arc, TaskExecutor) { 404 | let db_config = sc_client_db::DatabaseSettings { 405 | state_cache_size: 16*1024*1024, 406 | state_cache_child_ratio: Some((0, 100)), 407 | state_pruning: PruningMode::ArchiveAll, 408 | source: database_type.into_settings(dir.into()), 409 | keep_blocks: sc_client_db::KeepBlocks::All, 410 | transaction_storage: sc_client_db::TransactionStorageMode::BlockBody, 411 | }; 412 | let task_executor = TaskExecutor::new(); 413 | 414 | let backend = sc_service::new_db_backend(db_config).expect("Should not fail"); 415 | let client = sc_service::new_client( 416 | backend.clone(), 417 | NativeExecutor::new(WasmExecutionMethod::Compiled, None, 8), 418 | &keyring.generate_genesis(), 419 | None, 420 | None, 421 | ExecutionExtensions::new(profile.into_execution_strategies(), None, None), 422 | Box::new(task_executor.clone()), 423 | None, 424 | None, 425 | Default::default(), 426 | ).expect("Should not fail"); 427 | 428 | (client, backend, task_executor) 429 | } 430 | 431 | /// Generate list of required inherents. 432 | /// 433 | /// Uses already instantiated Client. 434 | pub fn generate_inherents(&mut self, client: &Client) -> Vec { 435 | let mut inherent_data = InherentData::new(); 436 | let timestamp = 1 * MinimumPeriod::get(); 437 | 438 | inherent_data 439 | .put_data(sp_timestamp::INHERENT_IDENTIFIER, ×tamp) 440 | .expect("Put timestamp failed"); 441 | 442 | client.runtime_api() 443 | .inherent_extrinsics_with_context( 444 | &BlockId::number(0), 445 | ExecutionContext::BlockConstruction, 446 | inherent_data, 447 | ).expect("Get inherents failed") 448 | } 449 | 450 | /// Iterate over some block content with transaction signed using this database keyring. 451 | pub fn block_content(&self, content: BlockContent, client: &Client) -> BlockContentIterator { 452 | BlockContentIterator::new(content, &self.keyring, client) 453 | } 454 | 455 | /// Get cliet for this database operations. 456 | pub fn client(&mut self) -> Client { 457 | let (client, _backend, _task_executor) = Self::bench_client( 458 | self.database_type, 459 | self.directory_guard.path(), 460 | Profile::Wasm, 461 | &self.keyring, 462 | ); 463 | 464 | client 465 | } 466 | 467 | /// Generate new block using this database. 468 | pub fn generate_block(&mut self, content: BlockContent) -> Block { 469 | let client = self.client(); 470 | 471 | let mut block = client 472 | .new_block(Default::default()) 473 | .expect("Block creation failed"); 474 | 475 | for extrinsic in self.generate_inherents(&client) { 476 | block.push(extrinsic).expect("Push inherent failed"); 477 | } 478 | 479 | let start = std::time::Instant::now(); 480 | for opaque in self.block_content(content, &client) { 481 | match block.push(opaque) { 482 | Err(sp_blockchain::Error::ApplyExtrinsicFailed( 483 | sp_blockchain::ApplyExtrinsicFailed::Validity(e) 484 | )) if e.exhausted_resources() => { 485 | break; 486 | }, 487 | Err(err) => panic!("Error pushing transaction: {:?}", err), 488 | Ok(_) => {}, 489 | } 490 | }; 491 | 492 | let block = block.build().expect("Block build failed").block; 493 | 494 | log::info!( 495 | target: "bench-logistics", 496 | "Block construction: {:#?} ({} tx)", 497 | start.elapsed(), block.extrinsics.len() 498 | ); 499 | 500 | block 501 | } 502 | 503 | /// Database path. 504 | pub fn path(&self) -> &Path { 505 | self.directory_guard.path() 506 | } 507 | 508 | /// Clone this database and create context for testing/benchmarking. 509 | pub fn create_context(&self, profile: Profile) -> BenchContext { 510 | let BenchDb { directory_guard, keyring, database_type } = self.clone(); 511 | let (client, backend, task_executor) = Self::bench_client( 512 | database_type, 513 | directory_guard.path(), 514 | profile, 515 | &keyring 516 | ); 517 | 518 | BenchContext { 519 | client: Arc::new(client), 520 | db_guard: directory_guard, 521 | backend, 522 | spawn_handle: Box::new(task_executor), 523 | } 524 | } 525 | } 526 | 527 | /// Key types to be used in benching keyring 528 | pub enum KeyTypes { 529 | /// sr25519 signing keys 530 | Sr25519, 531 | /// ed25519 signing keys 532 | Ed25519, 533 | } 534 | 535 | impl BenchKeyring { 536 | /// New keyring. 537 | /// 538 | /// `length` is the number of accounts generated. 539 | pub fn new(length: usize, key_types: KeyTypes) -> Self { 540 | let mut accounts = BTreeMap::new(); 541 | 542 | for n in 0..length { 543 | let seed = format!("//endowed-user/{}", n); 544 | let (account_id, pair) = match key_types { 545 | KeyTypes::Sr25519 => { 546 | let pair = sr25519::Pair::from_string(&seed, None).expect("failed to generate pair"); 547 | let account_id = AccountPublic::from(pair.public()).into_account(); 548 | (account_id, BenchPair::Sr25519(pair)) 549 | }, 550 | KeyTypes::Ed25519 => { 551 | let pair = ed25519::Pair::from_seed(&blake2_256(seed.as_bytes())); 552 | let account_id = AccountPublic::from(pair.public()).into_account(); 553 | (account_id, BenchPair::Ed25519(pair)) 554 | }, 555 | }; 556 | accounts.insert(account_id, pair); 557 | } 558 | 559 | Self { accounts } 560 | } 561 | 562 | /// Generated account id-s from keyring keypairs. 563 | pub fn collect_account_ids(&self) -> Vec { 564 | self.accounts.keys().cloned().collect() 565 | } 566 | 567 | /// Get account id at position `index` 568 | pub fn at(&self, index: usize) -> AccountId { 569 | self.accounts.keys().nth(index).expect("Failed to get account").clone() 570 | } 571 | 572 | /// Sign transaction with keypair from this keyring. 573 | pub fn sign( 574 | &self, 575 | xt: CheckedExtrinsic, 576 | spec_version: u32, 577 | tx_version: u32, 578 | genesis_hash: [u8; 32] 579 | ) -> UncheckedExtrinsic { 580 | match xt.signed { 581 | Some((signed, extra)) => { 582 | let payload = (xt.function, extra.clone(), spec_version, tx_version, genesis_hash, genesis_hash); 583 | let key = self.accounts.get(&signed).expect("Account id not found in keyring"); 584 | let signature = payload.using_encoded(|b| { 585 | if b.len() > 256 { 586 | key.sign(&sp_io::hashing::blake2_256(b)) 587 | } else { 588 | key.sign(b) 589 | } 590 | }).into(); 591 | UncheckedExtrinsic { 592 | signature: Some((sp_runtime::MultiAddress::Id(signed), signature, extra)), 593 | function: payload.0, 594 | } 595 | } 596 | None => UncheckedExtrinsic { 597 | signature: None, 598 | function: xt.function, 599 | }, 600 | } 601 | } 602 | 603 | /// Generate genesis with accounts from this keyring endowed with some balance. 604 | pub fn generate_genesis(&self) -> node_runtime::GenesisConfig { 605 | crate::genesis::config_endowed( 606 | false, 607 | Some(node_runtime::wasm_binary_unwrap()), 608 | self.collect_account_ids(), 609 | ) 610 | } 611 | } 612 | 613 | /// Profile for exetion strategies. 614 | #[derive(Clone, Copy, Debug)] 615 | pub enum Profile { 616 | /// As native as possible. 617 | Native, 618 | /// As wasm as possible. 619 | Wasm, 620 | } 621 | 622 | impl Profile { 623 | fn into_execution_strategies(self) -> ExecutionStrategies { 624 | match self { 625 | Profile::Wasm => ExecutionStrategies { 626 | syncing: ExecutionStrategy::AlwaysWasm, 627 | importing: ExecutionStrategy::AlwaysWasm, 628 | block_construction: ExecutionStrategy::AlwaysWasm, 629 | offchain_worker: ExecutionStrategy::AlwaysWasm, 630 | other: ExecutionStrategy::AlwaysWasm, 631 | }, 632 | Profile::Native => ExecutionStrategies { 633 | syncing: ExecutionStrategy::NativeElseWasm, 634 | importing: ExecutionStrategy::NativeElseWasm, 635 | block_construction: ExecutionStrategy::NativeElseWasm, 636 | offchain_worker: ExecutionStrategy::NativeElseWasm, 637 | other: ExecutionStrategy::NativeElseWasm, 638 | } 639 | } 640 | } 641 | } 642 | 643 | struct Guard(tempfile::TempDir); 644 | 645 | impl Guard { 646 | fn path(&self) -> &Path { 647 | self.0.path() 648 | } 649 | } 650 | 651 | /// Benchmarking/test context holding instantiated client and backend references. 652 | pub struct BenchContext { 653 | /// Node client. 654 | pub client: Arc, 655 | /// Node backend. 656 | pub backend: Arc, 657 | /// Spawn handle. 658 | pub spawn_handle: Box, 659 | 660 | db_guard: Guard, 661 | } 662 | 663 | type AccountPublic = ::Signer; 664 | 665 | fn get_from_seed(seed: &str) -> ::Public { 666 | TPublic::Pair::from_string(&format!("//{}", seed), None) 667 | .expect("static values are valid; qed") 668 | .public() 669 | } 670 | 671 | fn get_account_id_from_seed(seed: &str) -> AccountId 672 | where 673 | AccountPublic: From<::Public> 674 | { 675 | AccountPublic::from(get_from_seed::(seed)).into_account() 676 | } 677 | 678 | impl BenchContext { 679 | /// Import some block. 680 | pub fn import_block(&mut self, block: Block) { 681 | let mut import_params = BlockImportParams::new(BlockOrigin::NetworkBroadcast, block.header.clone()); 682 | import_params.body = Some(block.extrinsics().to_vec()); 683 | import_params.fork_choice = Some(ForkChoiceStrategy::LongestChain); 684 | 685 | assert_eq!(self.client.chain_info().best_number, 0); 686 | 687 | assert_eq!( 688 | futures::executor::block_on(self.client.import_block(import_params, Default::default())) 689 | .expect("Failed to import block"), 690 | ImportResult::Imported( 691 | ImportedAux { 692 | header_only: false, 693 | clear_justification_requests: false, 694 | needs_justification: false, 695 | bad_justification: false, 696 | is_new_best: true, 697 | } 698 | ) 699 | ); 700 | 701 | assert_eq!(self.client.chain_info().best_number, 1); 702 | } 703 | 704 | /// Database path for the current context. 705 | pub fn path(&self) -> &Path { 706 | self.db_guard.path() 707 | } 708 | } 709 | -------------------------------------------------------------------------------- /testing/src/client.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2019 TrustBase Network 2 | // This file is part of TrustBase library. 3 | // 4 | // The TrustBase library is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU Lesser General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // The TrustBase library is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU Lesser General Public License for more details. 13 | 14 | //! Utilities to build a `TestClient` for `node-runtime`. 15 | 16 | use sp_runtime::BuildStorage; 17 | use sc_service::client; 18 | /// Re-export test-client utilities. 19 | pub use substrate_test_client::*; 20 | 21 | /// Call executor for `node-runtime` `TestClient`. 22 | pub type Executor = sc_executor::NativeExecutor; 23 | 24 | /// Default backend type. 25 | pub type Backend = sc_client_db::Backend; 26 | 27 | /// Test client type. 28 | pub type Client = client::Client< 29 | Backend, 30 | client::LocalCallExecutor, 31 | node_primitives::Block, 32 | node_runtime::RuntimeApi, 33 | >; 34 | 35 | /// Transaction for node-runtime. 36 | pub type Transaction = sc_client_api::backend::TransactionFor; 37 | 38 | /// Genesis configuration parameters for `TestClient`. 39 | #[derive(Default)] 40 | pub struct GenesisParameters { 41 | support_changes_trie: bool, 42 | } 43 | 44 | impl substrate_test_client::GenesisInit for GenesisParameters { 45 | fn genesis_storage(&self) -> Storage { 46 | crate::genesis::config(self.support_changes_trie, None).build_storage().unwrap() 47 | } 48 | } 49 | 50 | /// A `test-runtime` extensions to `TestClientBuilder`. 51 | pub trait TestClientBuilderExt: Sized { 52 | /// Create test client builder. 53 | fn new() -> Self; 54 | 55 | /// Build the test client. 56 | fn build(self) -> Client; 57 | } 58 | 59 | impl TestClientBuilderExt for substrate_test_client::TestClientBuilder< 60 | node_primitives::Block, 61 | client::LocalCallExecutor, 62 | Backend, 63 | GenesisParameters, 64 | > { 65 | fn new() -> Self{ 66 | Self::default() 67 | } 68 | 69 | fn build(self) -> Client { 70 | self.build_with_native_executor(None).0 71 | } 72 | } 73 | 74 | 75 | -------------------------------------------------------------------------------- /testing/src/genesis.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2019 TrustBase Network 2 | // This file is part of TrustBase library. 3 | // 4 | // The TrustBase library is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU Lesser General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // The TrustBase library is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU Lesser General Public License for more details. 13 | 14 | //! Genesis Configuration. 15 | 16 | use crate::keyring::*; 17 | use sp_keyring::{Ed25519Keyring, Sr25519Keyring}; 18 | use node_runtime::{ 19 | GenesisConfig, BalancesConfig, SessionConfig, StakingConfig, SystemConfig, 20 | GrandpaConfig, IndicesConfig, SocietyConfig, wasm_binary_unwrap, 21 | AccountId, StakerStatus, BabeConfig, BABE_GENESIS_EPOCH_CONFIG, 22 | }; 23 | use node_runtime::constants::currency::*; 24 | use sp_core::ChangesTrieConfiguration; 25 | use sp_runtime::Perbill; 26 | 27 | /// Create genesis runtime configuration for tests. 28 | pub fn config(support_changes_trie: bool, code: Option<&[u8]>) -> GenesisConfig { 29 | config_endowed(support_changes_trie, code, Default::default()) 30 | } 31 | 32 | /// Create genesis runtime configuration for tests with some extra 33 | /// endowed accounts. 34 | pub fn config_endowed( 35 | support_changes_trie: bool, 36 | code: Option<&[u8]>, 37 | extra_endowed: Vec, 38 | ) -> GenesisConfig { 39 | 40 | let mut endowed = vec![ 41 | (alice(), 111 * DOLLARS), 42 | (bob(), 100 * DOLLARS), 43 | (charlie(), 100_000_000 * DOLLARS), 44 | (dave(), 111 * DOLLARS), 45 | (eve(), 101 * DOLLARS), 46 | (ferdie(), 100 * DOLLARS), 47 | ]; 48 | 49 | endowed.extend( 50 | extra_endowed.into_iter().map(|endowed| (endowed, 100*DOLLARS)) 51 | ); 52 | 53 | GenesisConfig { 54 | system: SystemConfig { 55 | changes_trie_config: if support_changes_trie { Some(ChangesTrieConfiguration { 56 | digest_interval: 2, 57 | digest_levels: 2, 58 | }) } else { None }, 59 | code: code.map(|x| x.to_vec()).unwrap_or_else(|| wasm_binary_unwrap().to_vec()), 60 | }, 61 | indices: IndicesConfig { 62 | indices: vec![], 63 | }, 64 | balances: BalancesConfig { 65 | balances: endowed, 66 | }, 67 | session: SessionConfig { 68 | keys: vec![ 69 | (dave(), alice(), to_session_keys( 70 | &Ed25519Keyring::Alice, 71 | &Sr25519Keyring::Alice, 72 | )), 73 | (eve(), bob(), to_session_keys( 74 | &Ed25519Keyring::Bob, 75 | &Sr25519Keyring::Bob, 76 | )), 77 | (ferdie(), charlie(), to_session_keys( 78 | &Ed25519Keyring::Charlie, 79 | &Sr25519Keyring::Charlie, 80 | )), 81 | ] 82 | }, 83 | staking: StakingConfig { 84 | stakers: vec![ 85 | (dave(), alice(), 111 * DOLLARS, StakerStatus::Validator), 86 | (eve(), bob(), 100 * DOLLARS, StakerStatus::Validator), 87 | (ferdie(), charlie(), 100 * DOLLARS, StakerStatus::Validator) 88 | ], 89 | validator_count: 3, 90 | minimum_validator_count: 0, 91 | slash_reward_fraction: Perbill::from_percent(10), 92 | invulnerables: vec![alice(), bob(), charlie()], 93 | .. Default::default() 94 | }, 95 | babe: BabeConfig { 96 | authorities: vec![], 97 | epoch_config: Some(BABE_GENESIS_EPOCH_CONFIG), 98 | }, 99 | grandpa: GrandpaConfig { 100 | authorities: vec![], 101 | }, 102 | im_online: Default::default(), 103 | authority_discovery: Default::default(), 104 | democracy: Default::default(), 105 | council: Default::default(), 106 | technical_committee: Default::default(), 107 | technical_membership: Default::default(), 108 | elections: Default::default(), 109 | sudo: Default::default(), 110 | treasury: Default::default(), 111 | society: SocietyConfig { 112 | members: vec![alice(), bob()], 113 | pot: 0, 114 | max_members: 999, 115 | }, 116 | vesting: Default::default(), 117 | gilt: Default::default(), 118 | transaction_storage: Default::default(), 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /testing/src/keyring.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2019 TrustBase Network 2 | // This file is part of TrustBase library. 3 | // 4 | // The TrustBase library is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU Lesser General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // The TrustBase library is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU Lesser General Public License for more details. 13 | 14 | //! Test accounts. 15 | 16 | use sp_keyring::{AccountKeyring, Sr25519Keyring, Ed25519Keyring}; 17 | use node_primitives::{AccountId, Balance, Index}; 18 | use node_runtime::{CheckedExtrinsic, UncheckedExtrinsic, SessionKeys, SignedExtra}; 19 | use sp_runtime::generic::Era; 20 | use codec::Encode; 21 | 22 | /// Alice's account id. 23 | pub fn alice() -> AccountId { 24 | AccountKeyring::Alice.into() 25 | } 26 | 27 | /// Bob's account id. 28 | pub fn bob() -> AccountId { 29 | AccountKeyring::Bob.into() 30 | } 31 | 32 | /// Charlie's account id. 33 | pub fn charlie() -> AccountId { 34 | AccountKeyring::Charlie.into() 35 | } 36 | 37 | /// Dave's account id. 38 | pub fn dave() -> AccountId { 39 | AccountKeyring::Dave.into() 40 | } 41 | 42 | /// Eve's account id. 43 | pub fn eve() -> AccountId { 44 | AccountKeyring::Eve.into() 45 | } 46 | 47 | /// Ferdie's account id. 48 | pub fn ferdie() -> AccountId { 49 | AccountKeyring::Ferdie.into() 50 | } 51 | 52 | /// Convert keyrings into `SessionKeys`. 53 | pub fn to_session_keys( 54 | ed25519_keyring: &Ed25519Keyring, 55 | sr25519_keyring: &Sr25519Keyring, 56 | ) -> SessionKeys { 57 | SessionKeys { 58 | grandpa: ed25519_keyring.to_owned().public().into(), 59 | babe: sr25519_keyring.to_owned().public().into(), 60 | im_online: sr25519_keyring.to_owned().public().into(), 61 | authority_discovery: sr25519_keyring.to_owned().public().into(), 62 | } 63 | } 64 | 65 | /// Returns transaction extra. 66 | pub fn signed_extra(nonce: Index, extra_fee: Balance) -> SignedExtra { 67 | ( 68 | frame_system::CheckSpecVersion::new(), 69 | frame_system::CheckTxVersion::new(), 70 | frame_system::CheckGenesis::new(), 71 | frame_system::CheckEra::from(Era::mortal(256, 0)), 72 | frame_system::CheckNonce::from(nonce), 73 | frame_system::CheckWeight::new(), 74 | pallet_transaction_payment::ChargeTransactionPayment::from(extra_fee), 75 | ) 76 | } 77 | 78 | /// Sign given `CheckedExtrinsic`. 79 | pub fn sign(xt: CheckedExtrinsic, spec_version: u32, tx_version: u32, genesis_hash: [u8; 32]) -> UncheckedExtrinsic { 80 | match xt.signed { 81 | Some((signed, extra)) => { 82 | let payload = (xt.function, extra.clone(), spec_version, tx_version, genesis_hash, genesis_hash); 83 | let key = AccountKeyring::from_account_id(&signed).unwrap(); 84 | let signature = payload.using_encoded(|b| { 85 | if b.len() > 256 { 86 | key.sign(&sp_io::hashing::blake2_256(b)) 87 | } else { 88 | key.sign(b) 89 | } 90 | }).into(); 91 | UncheckedExtrinsic { 92 | signature: Some((sp_runtime::MultiAddress::Id(signed), signature, extra)), 93 | function: payload.0, 94 | } 95 | } 96 | None => UncheckedExtrinsic { 97 | signature: None, 98 | function: xt.function, 99 | }, 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /testing/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2019 TrustBase Network 2 | // This file is part of TrustBase library. 3 | // 4 | // The TrustBase library is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU Lesser General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // The TrustBase library is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU Lesser General Public License for more details. 13 | 14 | //! A set of testing utilities for TrustBase Node. 15 | 16 | #![warn(missing_docs)] 17 | 18 | pub mod client; 19 | pub mod genesis; 20 | pub mod keyring; 21 | pub mod bench; 22 | --------------------------------------------------------------------------------