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(),
)