diff --git a/substrate/Cargo.lock b/substrate/Cargo.lock index 189f85013c..046712c0af 100644 --- a/substrate/Cargo.lock +++ b/substrate/Cargo.lock @@ -1449,6 +1449,7 @@ dependencies = [ "sc-executor", "sc-service", "sp-core", + "sp-externalities", "sp-runtime", "sp-state-machine", "structopt", @@ -4225,6 +4226,7 @@ dependencies = [ name = "pallet-im-online" version = "2.0.0-alpha.4" dependencies = [ + "frame-benchmarking", "frame-support", "frame-system", "pallet-authorship", diff --git a/substrate/bin/node/runtime/Cargo.toml b/substrate/bin/node/runtime/Cargo.toml index a5fad30837..bdbf4cce50 100644 --- a/substrate/bin/node/runtime/Cargo.toml +++ b/substrate/bin/node/runtime/Cargo.toml @@ -139,4 +139,7 @@ runtime-benchmarks = [ "pallet-identity/runtime-benchmarks", "pallet-balances/runtime-benchmarks", "pallet-vesting/runtime-benchmarks", + "pallet-session-benchmarking", + "pallet-staking/runtime-benchmarks", + "pallet-im-online/runtime-benchmarks", ] diff --git a/substrate/bin/node/runtime/src/lib.rs b/substrate/bin/node/runtime/src/lib.rs index b27ba6c9ac..48913b7771 100644 --- a/substrate/bin/node/runtime/src/lib.rs +++ b/substrate/bin/node/runtime/src/lib.rs @@ -864,6 +864,13 @@ impl_runtime_apis! { steps, repeat, ), + b"pallet-im-online" | b"im-online" => ImOnline::run_benchmark( + extrinsic, + lowest_range_values, + highest_range_values, + steps, + repeat, + ), b"pallet-identity" | b"identity" => Identity::run_benchmark( extrinsic, lowest_range_values, diff --git a/substrate/frame/im-online/Cargo.toml b/substrate/frame/im-online/Cargo.toml index 2b9e80ce4e..d8df22a0f5 100644 --- a/substrate/frame/im-online/Cargo.toml +++ b/substrate/frame/im-online/Cargo.toml @@ -22,6 +22,8 @@ sp-staking = { version = "2.0.0-alpha.4", default-features = false, path = "../. frame-support = { version = "2.0.0-alpha.4", default-features = false, path = "../support" } frame-system = { version = "2.0.0-alpha.4", default-features = false, path = "../system" } +frame-benchmarking = { version = "2.0.0-alpha.4", default-features = false, path = "../benchmarking", optional = true } + [features] default = ["std", "pallet-session/historical"] std = [ @@ -38,3 +40,4 @@ std = [ "frame-support/std", "frame-system/std", ] +runtime-benchmarks = ["frame-benchmarking"] diff --git a/substrate/frame/im-online/src/benchmarking.rs b/substrate/frame/im-online/src/benchmarking.rs new file mode 100644 index 0000000000..1269328634 --- /dev/null +++ b/substrate/frame/im-online/src/benchmarking.rs @@ -0,0 +1,123 @@ +// Copyright 2020 Parity Technologies (UK) Ltd. +// This file is part of Substrate. + +// Substrate 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. + +// Substrate 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 Substrate. If not, see . + +//! I'm Online pallet benchmarking. + +#![cfg(feature = "runtime-benchmarks")] + +use super::*; + +use frame_system::RawOrigin; +use frame_benchmarking::benchmarks; +use sp_core::offchain::{OpaquePeerId, OpaqueMultiaddr}; +use sp_runtime::traits::{ValidateUnsigned, Zero}; + +use crate::Module as ImOnline; + +const MAX_KEYS: u32 = 1000; +const MAX_EXTERNAL_ADDRESSES: u32 = 100; + +pub fn create_heartbeat(k: u32, e: u32) -> + Result<(crate::Heartbeat, ::Signature), &'static str> +{ + let mut keys = Vec::new(); + for _ in 0..k { + keys.push(T::AuthorityId::generate_pair(None)); + } + Keys::::put(keys.clone()); + + let network_state = OpaqueNetworkState { + peer_id: OpaquePeerId::default(), + external_addresses: vec![OpaqueMultiaddr::new(vec![0; 32]); e as usize], + }; + let input_heartbeat = Heartbeat { + block_number: T::BlockNumber::zero(), + network_state, + session_index: 0, + authority_index: k-1, + }; + + let encoded_heartbeat = input_heartbeat.encode(); + let authority_id = keys.get((k-1) as usize).ok_or("out of range")?; + let signature = authority_id.sign(&encoded_heartbeat).ok_or("couldn't make signature")?; + + Ok((input_heartbeat, signature)) +} + +benchmarks! { + _{ } + + heartbeat { + let k in 1 .. MAX_KEYS; + let e in 1 .. MAX_EXTERNAL_ADDRESSES; + let (input_heartbeat, signature) = create_heartbeat::(k, e)?; + }: _(RawOrigin::None, input_heartbeat, signature) + + validate_unsigned { + let k in 1 .. MAX_KEYS; + let e in 1 .. MAX_EXTERNAL_ADDRESSES; + let (input_heartbeat, signature) = create_heartbeat::(k, e)?; + let call = Call::heartbeat(input_heartbeat, signature); + }: { + ImOnline::::validate_unsigned(&call)?; + } +} + +#[cfg(test)] +mod tests { + use crate::*; + use super::SelectedBenchmark; + use crate::mock::*; + use frame_support::assert_ok; + + #[test] + fn test_heartbeat_benchmark() { + new_test_ext().execute_with(|| { + let k = 10; + + assert_eq!(ReceivedHeartbeats::iter_prefix(0).count(), 0); + + let selected_benchmark = SelectedBenchmark::heartbeat; + let c = vec![(frame_benchmarking::BenchmarkParameter::k, k)]; + let closure_to_benchmark = + >::instance( + &selected_benchmark, + &c + ).unwrap(); + + assert_ok!(closure_to_benchmark()); + + assert_eq!(ReceivedHeartbeats::iter_prefix(0).count(), 1); + }); + } + + #[test] + fn test_validate_unsigned_benchmark() { + new_test_ext().execute_with(|| { + let k = 10; + + let selected_benchmark = SelectedBenchmark::validate_unsigned; + let c = vec![(frame_benchmarking::BenchmarkParameter::k, k)]; + let closure_to_benchmark = + >::instance( + &selected_benchmark, + &c + ).unwrap(); + + assert_ok!(closure_to_benchmark()); + }); + } +} diff --git a/substrate/frame/im-online/src/lib.rs b/substrate/frame/im-online/src/lib.rs index a0a16c46f3..861c57e5b6 100644 --- a/substrate/frame/im-online/src/lib.rs +++ b/substrate/frame/im-online/src/lib.rs @@ -69,6 +69,7 @@ mod mock; mod tests; +mod benchmarking; use sp_application_crypto::RuntimeAppPublic; use codec::{Encode, Decode}; diff --git a/substrate/primitives/runtime/src/traits.rs b/substrate/primitives/runtime/src/traits.rs index 39e015505b..81b7733319 100644 --- a/substrate/primitives/runtime/src/traits.rs +++ b/substrate/primitives/runtime/src/traits.rs @@ -1293,6 +1293,16 @@ impl Printable for &str { } } +impl Printable for bool { + fn print(&self) { + if *self { + "true".print() + } else { + "false".print() + } + } +} + #[impl_for_tuples(1, 12)] impl Printable for Tuple { fn print(&self) { diff --git a/substrate/utils/frame/benchmarking-cli/Cargo.toml b/substrate/utils/frame/benchmarking-cli/Cargo.toml index 3535a542d9..3ba1b16481 100644 --- a/substrate/utils/frame/benchmarking-cli/Cargo.toml +++ b/substrate/utils/frame/benchmarking-cli/Cargo.toml @@ -16,6 +16,7 @@ sc-cli = { version = "0.8.0-alpha.4", path = "../../../client/cli" } sc-client = { version = "0.8.0-alpha.4", path = "../../../client" } sc-client-db = { version = "0.8.0-alpha.4", path = "../../../client/db" } sc-executor = { version = "0.8.0-alpha.4", path = "../../../client/executor" } +sp-externalities = { version = "0.8.0-alpha.4", path = "../../../primitives/externalities" } sp-runtime = { version = "2.0.0-alpha.4", path = "../../../primitives/runtime" } sp-state-machine = { version = "0.8.0-alpha.4", path = "../../../primitives/state-machine" } structopt = "0.3.8" diff --git a/substrate/utils/frame/benchmarking-cli/src/lib.rs b/substrate/utils/frame/benchmarking-cli/src/lib.rs index 79e7e689a6..b2aa4bd6a2 100644 --- a/substrate/utils/frame/benchmarking-cli/src/lib.rs +++ b/substrate/utils/frame/benchmarking-cli/src/lib.rs @@ -23,7 +23,12 @@ use sc_service::{Configuration, ChainSpec}; use sc_executor::{NativeExecutor, NativeExecutionDispatch}; use codec::{Encode, Decode}; use frame_benchmarking::BenchmarkResults; -use sp_core::tasks; +use sp_core::{ + tasks, + traits::KeystoreExt, + testing::KeyStore, +}; +use sp_externalities::Extensions; /// The `benchmark` command used to benchmark FRAME Pallets. #[derive(Debug, structopt::StructOpt, Clone)] @@ -106,6 +111,9 @@ impl BenchmarkCmd { 2, // The runtime instances cache size. ); + let mut extensions = Extensions::default(); + extensions.register(KeystoreExt(KeyStore::new())); + let result = StateMachine::<_, _, NumberFor, _>::new( &state, None, @@ -120,7 +128,7 @@ impl BenchmarkCmd { self.steps.clone(), self.repeat, ).encode(), - Default::default(), + extensions, &sp_state_machine::backend::BackendRuntimeCode::new(&state).runtime_code()?, tasks::executor(), )