// This file is part of Substrate. // Copyright (C) 2021 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // You should have received a copy of the GNU General Public License // along with this program. If not, see . #![deny(unused_extern_crates, missing_docs)] //! Basic example of end to end runtime tests. use grandpa::GrandpaBlockImport; use sc_consensus_babe::BabeBlockImport; use sc_consensus_manual_seal::consensus::babe::SlotTimestampProvider; use sc_executor::NativeElseWasmExecutor; use sc_service::{TFullBackend, TFullClient}; use sp_runtime::generic::Era; use test_runner::{ChainInfo, SignatureVerificationOverride}; type BlockImport = BabeBlockImport>; /// A unit struct which implements `NativeExecutionDispatch` feeding in the /// hard-coded runtime. pub struct ExecutorDispatch; impl sc_executor::NativeExecutionDispatch for ExecutorDispatch { type ExtendHostFunctions = (frame_benchmarking::benchmarking::HostFunctions, SignatureVerificationOverride); fn dispatch(method: &str, data: &[u8]) -> Option> { node_runtime::api::dispatch(method, data) } fn native_version() -> sc_executor::NativeVersion { node_runtime::native_version() } } /// ChainInfo implementation. struct NodeTemplateChainInfo; impl ChainInfo for NodeTemplateChainInfo { type Block = node_primitives::Block; type ExecutorDispatch = ExecutorDispatch; type Runtime = node_runtime::Runtime; type RuntimeApi = node_runtime::RuntimeApi; type SelectChain = sc_consensus::LongestChain, Self::Block>; type BlockImport = BlockImport< Self::Block, TFullBackend, TFullClient>, Self::SelectChain, >; type SignedExtras = node_runtime::SignedExtra; type InherentDataProviders = (SlotTimestampProvider, sp_consensus_babe::inherents::InherentDataProvider); fn signed_extras( from: ::AccountId, ) -> Self::SignedExtras { ( frame_system::CheckSpecVersion::::new(), frame_system::CheckTxVersion::::new(), frame_system::CheckGenesis::::new(), frame_system::CheckMortality::::from(Era::Immortal), frame_system::CheckNonce::::from( frame_system::Pallet::::account_nonce(from), ), frame_system::CheckWeight::::new(), pallet_transaction_payment::ChargeTransactionPayment::::from(0), ) } } #[cfg(test)] mod tests { use super::*; use node_cli::chain_spec::development_config; use sp_keyring::sr25519::Keyring::Alice; use sp_runtime::{traits::IdentifyAccount, MultiSigner}; use test_runner::{build_runtime, client_parts, task_executor, ConfigOrChainSpec, Node}; #[test] fn test_runner() { let tokio_runtime = build_runtime().unwrap(); let task_executor = task_executor(tokio_runtime.handle().clone()); let (rpc, task_manager, client, pool, command_sink, backend) = client_parts::< NodeTemplateChainInfo, >( ConfigOrChainSpec::ChainSpec(Box::new(development_config()), task_executor), ) .unwrap(); let node = Node::::new( rpc, task_manager, client, pool, command_sink, backend, ); tokio_runtime.block_on(async { // seals blocks node.seal_blocks(1).await; // submit extrinsics let alice = MultiSigner::from(Alice.public()).into_account(); let _hash = node .submit_extrinsic( frame_system::Call::remark((b"hello world").to_vec()), Some(alice), ) .await .unwrap(); // look ma, I can read state. let _events = node.with_state(|| frame_system::Pallet::::events()); // get access to the underlying client. let _client = node.client(); }) } }