Dynamic Benchmarking DB Whitelist (#6815)

* Add `get_whitelist` api

* add whitelisted caller

* Whitelist caller

* remove caller 0

* initial piping of origin (not actual value yet)

* remove attempt to pass origin around

* Add whitelist for `DidUpdate` storage on `pallet_timestamp`

* fix traits

* only add to whitelist if !contains

* PassBy not implemented error

* Whitelist read/writes explicitly per key

* update docs

* reduce trait constraint

* copy pasta

* Apply suggestions from code review

Co-authored-by: Guillaume Thiolliere <gui.thiolliere@gmail.com>
Co-authored-by: Alexander Popiak <alexander.popiak@parity.io>

* rename functions @apopiak

* missed some renaming

* enable doc tests

* Update docs

Co-authored-by: Guillaume Thiolliere <gui.thiolliere@gmail.com>
Co-authored-by: Alexander Popiak <alexander.popiak@parity.io>
This commit is contained in:
Shawn Tabrizi
2020-08-19 18:15:50 +02:00
committed by GitHub
parent 8b5ced7fa7
commit 481ad884d6
26 changed files with 421 additions and 205 deletions
+4
View File
@@ -1559,6 +1559,7 @@ version = "2.0.0-rc5"
dependencies = [ dependencies = [
"frame-support", "frame-support",
"frame-system", "frame-system",
"hex-literal",
"linregress", "linregress",
"parity-scale-codec", "parity-scale-codec",
"paste", "paste",
@@ -1567,6 +1568,7 @@ dependencies = [
"sp-runtime", "sp-runtime",
"sp-runtime-interface", "sp-runtime-interface",
"sp-std", "sp-std",
"sp-storage",
] ]
[[package]] [[package]]
@@ -8047,6 +8049,7 @@ dependencies = [
"sp-runtime-interface-test-wasm", "sp-runtime-interface-test-wasm",
"sp-state-machine", "sp-state-machine",
"sp-std", "sp-std",
"sp-storage",
"sp-tracing", "sp-tracing",
"sp-wasm-interface", "sp-wasm-interface",
"static_assertions", "static_assertions",
@@ -8176,6 +8179,7 @@ name = "sp-storage"
version = "2.0.0-rc5" version = "2.0.0-rc5"
dependencies = [ dependencies = [
"impl-serde 0.2.3", "impl-serde 0.2.3",
"parity-scale-codec",
"ref-cast", "ref-cast",
"serde", "serde",
"sp-debug-derive", "sp-debug-derive",
+8 -10
View File
@@ -1130,7 +1130,7 @@ impl_runtime_apis! {
repeat: u32, repeat: u32,
extra: bool, extra: bool,
) -> Result<Vec<frame_benchmarking::BenchmarkBatch>, sp_runtime::RuntimeString> { ) -> Result<Vec<frame_benchmarking::BenchmarkBatch>, sp_runtime::RuntimeString> {
use frame_benchmarking::{Benchmarking, BenchmarkBatch, add_benchmark}; use frame_benchmarking::{Benchmarking, BenchmarkBatch, add_benchmark, TrackedStorageKey};
// Trying to add benchmarks directly to the Session Pallet caused cyclic dependency issues. // Trying to add benchmarks directly to the Session Pallet caused cyclic dependency issues.
// To get around that, we separated the Session benchmarks into its own crate, which is why // To get around that, we separated the Session benchmarks into its own crate, which is why
// we need these two lines below. // we need these two lines below.
@@ -1142,21 +1142,19 @@ impl_runtime_apis! {
impl pallet_offences_benchmarking::Trait for Runtime {} impl pallet_offences_benchmarking::Trait for Runtime {}
impl frame_system_benchmarking::Trait for Runtime {} impl frame_system_benchmarking::Trait for Runtime {}
let whitelist: Vec<Vec<u8>> = vec![ let whitelist: Vec<TrackedStorageKey> = vec![
// Block Number // Block Number
hex_literal::hex!("26aa394eea5630e07c48ae0c9558cef702a5c1b19ab7a04f536c519aca4983ac").to_vec(), hex_literal::hex!("26aa394eea5630e07c48ae0c9558cef702a5c1b19ab7a04f536c519aca4983ac").to_vec().into(),
// Total Issuance // Total Issuance
hex_literal::hex!("c2261276cc9d1f8598ea4b6a74b15c2f57c875e4cff74148e4628f264b974c80").to_vec(), hex_literal::hex!("c2261276cc9d1f8598ea4b6a74b15c2f57c875e4cff74148e4628f264b974c80").to_vec().into(),
// Execution Phase // Execution Phase
hex_literal::hex!("26aa394eea5630e07c48ae0c9558cef7ff553b5a9862a516939d82b3d3d8661a").to_vec(), hex_literal::hex!("26aa394eea5630e07c48ae0c9558cef7ff553b5a9862a516939d82b3d3d8661a").to_vec().into(),
// Event Count // Event Count
hex_literal::hex!("26aa394eea5630e07c48ae0c9558cef70a98fdbe9ce6c55837576c60c7af3850").to_vec(), hex_literal::hex!("26aa394eea5630e07c48ae0c9558cef70a98fdbe9ce6c55837576c60c7af3850").to_vec().into(),
// System Events // System Events
hex_literal::hex!("26aa394eea5630e07c48ae0c9558cef780d41e5e16056765bc8461851072c9d7").to_vec(), hex_literal::hex!("26aa394eea5630e07c48ae0c9558cef780d41e5e16056765bc8461851072c9d7").to_vec().into(),
// Caller 0 Account
hex_literal::hex!("26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da946c154ffd9992e395af90b5b13cc6f295c77033fce8a9045824a6690bbf99c6db269502f0a8d1d2a008542d5690a0749").to_vec(),
// Treasury Account // Treasury Account
hex_literal::hex!("26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da95ecffd7b6c0f78751baa9d281e0bfa3a6d6f646c70792f74727372790000000000000000000000000000000000000000").to_vec(), hex_literal::hex!("26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da95ecffd7b6c0f78751baa9d281e0bfa3a6d6f646c70792f74727372790000000000000000000000000000000000000000").to_vec().into(),
]; ];
let mut batches = Vec::<BenchmarkBatch>::new(); let mut batches = Vec::<BenchmarkBatch>::new();
+23 -14
View File
@@ -24,7 +24,10 @@ use std::collections::HashMap;
use hash_db::{Prefix, Hasher}; use hash_db::{Prefix, Hasher};
use sp_trie::{MemoryDB, prefixed_key}; use sp_trie::{MemoryDB, prefixed_key};
use sp_core::{storage::ChildInfo, hexdisplay::HexDisplay}; use sp_core::{
storage::{ChildInfo, TrackedStorageKey},
hexdisplay::HexDisplay
};
use sp_runtime::traits::{Block as BlockT, HashFor}; use sp_runtime::traits::{Block as BlockT, HashFor};
use sp_runtime::Storage; use sp_runtime::Storage;
use sp_state_machine::{DBValue, backend::Backend as StateBackend, StorageCollection}; use sp_state_machine::{DBValue, backend::Backend as StateBackend, StorageCollection};
@@ -95,7 +98,7 @@ pub struct BenchmarkingState<B: BlockT> {
shared_cache: SharedCache<B>, // shared cache is always empty shared_cache: SharedCache<B>, // shared cache is always empty
key_tracker: RefCell<HashMap<Vec<u8>, KeyTracker>>, key_tracker: RefCell<HashMap<Vec<u8>, KeyTracker>>,
read_write_tracker: RefCell<ReadWriteTracker>, read_write_tracker: RefCell<ReadWriteTracker>,
whitelist: RefCell<Vec<Vec<u8>>>, whitelist: RefCell<Vec<TrackedStorageKey>>,
} }
impl<B: BlockT> BenchmarkingState<B> { impl<B: BlockT> BenchmarkingState<B> {
@@ -155,15 +158,14 @@ impl<B: BlockT> BenchmarkingState<B> {
fn add_whitelist_to_tracker(&self) { fn add_whitelist_to_tracker(&self) {
let mut key_tracker = self.key_tracker.borrow_mut(); let mut key_tracker = self.key_tracker.borrow_mut();
let whitelisted = KeyTracker {
has_been_read: true,
has_been_written: true,
};
let whitelist = self.whitelist.borrow(); let whitelist = self.whitelist.borrow();
whitelist.iter().for_each(|key| { whitelist.iter().for_each(|key| {
key_tracker.insert(key.to_vec(), whitelisted); let whitelisted = KeyTracker {
has_been_read: key.has_been_read,
has_been_written: key.has_been_written,
};
key_tracker.insert(key.key.clone(), whitelisted);
}); });
} }
@@ -181,18 +183,21 @@ impl<B: BlockT> BenchmarkingState<B> {
let maybe_tracker = key_tracker.get(key); let maybe_tracker = key_tracker.get(key);
let has_been_read = KeyTracker {
has_been_read: true,
has_been_written: false,
};
match maybe_tracker { match maybe_tracker {
None => { None => {
let has_been_read = KeyTracker {
has_been_read: true,
has_been_written: false,
};
key_tracker.insert(key.to_vec(), has_been_read); key_tracker.insert(key.to_vec(), has_been_read);
read_write_tracker.add_read(); read_write_tracker.add_read();
}, },
Some(tracker) => { Some(tracker) => {
if !tracker.has_been_read { if !tracker.has_been_read {
let has_been_read = KeyTracker {
has_been_read: true,
has_been_written: tracker.has_been_written,
};
key_tracker.insert(key.to_vec(), has_been_read); key_tracker.insert(key.to_vec(), has_been_read);
read_write_tracker.add_read(); read_write_tracker.add_read();
} else { } else {
@@ -426,7 +431,11 @@ impl<B: BlockT> StateBackend<HashFor<B>> for BenchmarkingState<B> {
self.wipe_tracker() self.wipe_tracker()
} }
fn set_whitelist(&self, new: Vec<Vec<u8>>) { fn get_whitelist(&self) -> Vec<TrackedStorageKey> {
self.whitelist.borrow().to_vec()
}
fn set_whitelist(&self, new: Vec<TrackedStorageKey>) {
*self.whitelist.borrow_mut() = new; *self.whitelist.borrow_mut() = new;
} }
+4 -4
View File
@@ -22,7 +22,7 @@
use super::*; use super::*;
use frame_system::RawOrigin; use frame_system::RawOrigin;
use frame_benchmarking::{benchmarks, account}; use frame_benchmarking::{benchmarks, account, whitelisted_caller};
use sp_runtime::traits::Bounded; use sp_runtime::traits::Bounded;
use crate::Module as Balances; use crate::Module as Balances;
@@ -40,7 +40,7 @@ benchmarks! {
// * Transfer will create the recipient account. // * Transfer will create the recipient account.
transfer { transfer {
let existential_deposit = T::ExistentialDeposit::get(); let existential_deposit = T::ExistentialDeposit::get();
let caller = account("caller", 0, SEED); let caller = whitelisted_caller();
// Give some multiple of the existential deposit + creation fee + transfer fee // Give some multiple of the existential deposit + creation fee + transfer fee
let balance = existential_deposit.saturating_mul(ED_MULTIPLIER.into()); let balance = existential_deposit.saturating_mul(ED_MULTIPLIER.into());
@@ -60,7 +60,7 @@ benchmarks! {
// * Both accounts exist and will continue to exist. // * Both accounts exist and will continue to exist.
#[extra] #[extra]
transfer_best_case { transfer_best_case {
let caller = account("caller", 0, SEED); let caller = whitelisted_caller();
let recipient: T::AccountId = account("recipient", 0, SEED); let recipient: T::AccountId = account("recipient", 0, SEED);
let recipient_lookup: <T::Lookup as StaticLookup>::Source = T::Lookup::unlookup(recipient.clone()); let recipient_lookup: <T::Lookup as StaticLookup>::Source = T::Lookup::unlookup(recipient.clone());
@@ -80,7 +80,7 @@ benchmarks! {
// Benchmark `transfer_keep_alive` with the worst possible condition: // Benchmark `transfer_keep_alive` with the worst possible condition:
// * The recipient account is created. // * The recipient account is created.
transfer_keep_alive { transfer_keep_alive {
let caller = account("caller", 0, SEED); let caller = whitelisted_caller();
let recipient: T::AccountId = account("recipient", 0, SEED); let recipient: T::AccountId = account("recipient", 0, SEED);
let recipient_lookup: <T::Lookup as StaticLookup>::Source = T::Lookup::unlookup(recipient.clone()); let recipient_lookup: <T::Lookup as StaticLookup>::Source = T::Lookup::unlookup(recipient.clone());
+4
View File
@@ -20,9 +20,13 @@ sp-runtime-interface = { version = "2.0.0-rc5", path = "../../primitives/runtime
sp-runtime = { version = "2.0.0-rc5", path = "../../primitives/runtime", default-features = false } sp-runtime = { version = "2.0.0-rc5", path = "../../primitives/runtime", default-features = false }
sp-std = { version = "2.0.0-rc5", path = "../../primitives/std", default-features = false } sp-std = { version = "2.0.0-rc5", path = "../../primitives/std", default-features = false }
sp-io = { version = "2.0.0-rc5", path = "../../primitives/io", default-features = false } sp-io = { version = "2.0.0-rc5", path = "../../primitives/io", default-features = false }
sp-storage = { version = "2.0.0-rc5", path = "../../primitives/storage", default-features = false }
frame-support = { version = "2.0.0-rc5", default-features = false, path = "../support" } frame-support = { version = "2.0.0-rc5", default-features = false, path = "../support" }
frame-system = { version = "2.0.0-rc5", default-features = false, path = "../system" } frame-system = { version = "2.0.0-rc5", default-features = false, path = "../system" }
[dev-dependencies]
hex-literal = "0.2.1"
[features] [features]
default = [ "std" ] default = [ "std" ]
std = [ std = [
+185 -108
View File
@@ -32,6 +32,7 @@ pub use sp_io::storage::root as storage_root;
pub use sp_runtime::traits::Zero; pub use sp_runtime::traits::Zero;
pub use frame_support; pub use frame_support;
pub use paste; pub use paste;
pub use sp_storage::TrackedStorageKey;
/// Construct pallet benchmarks for weighing dispatchables. /// Construct pallet benchmarks for weighing dispatchables.
/// ///
@@ -418,156 +419,220 @@ macro_rules! benchmarks_iter {
#[doc(hidden)] #[doc(hidden)]
macro_rules! benchmark_backend { macro_rules! benchmark_backend {
// parsing arms // parsing arms
( { $( $instance:ident )? } $name:ident { (
$( $where_clause:tt )* { $( $instance:ident )? }
} { $name:ident
$( $common:tt )* { $( $where_clause:tt )* }
} { { $( $common:tt )* }
$( PRE { $( $pre_parsed:tt )* } )* { $( PRE { $( $pre_parsed:tt )* } )* }
} { $eval:block } { { $eval:block }
{
let $pre_id:tt : $pre_ty:ty = $pre_ex:expr; let $pre_id:tt : $pre_ty:ty = $pre_ex:expr;
$( $rest:tt )* $( $rest:tt )*
} $postcode:block) => { }
$postcode:block
) => {
$crate::benchmark_backend! { $crate::benchmark_backend! {
{ $( $instance)? } $name { $( $where_clause )* } { $( $common )* } { { $( $instance)? }
$name
{ $( $where_clause )* }
{ $( $common )* }
{
$( PRE { $( $pre_parsed )* } )* $( PRE { $( $pre_parsed )* } )*
PRE { $pre_id , $pre_ty , $pre_ex } PRE { $pre_id , $pre_ty , $pre_ex }
} { $eval } { $( $rest )* } $postcode }
{ $eval }
{ $( $rest )* }
$postcode
} }
}; };
( { $( $instance:ident )? } $name:ident { (
$( $where_clause:tt )* { $( $instance:ident )? }
} { $name:ident
$( $common:tt )* { $( $where_clause:tt )* }
} { { $( $common:tt )* }
$( $parsed:tt )* { $( $parsed:tt )* }
} { $eval:block } { { $eval:block }
let $param:ident in ( $param_from:expr ) .. $param_to:expr => $param_instancer:expr; {
$( $rest:tt )* let $param:ident in ( $param_from:expr ) .. $param_to:expr => $param_instancer:expr;
} $postcode:block) => { $( $rest:tt )*
}
$postcode:block
) => {
$crate::benchmark_backend! { $crate::benchmark_backend! {
{ $( $instance)? } $name { $( $where_clause )* } { $( $common )* } { { $( $instance)? }
$name
{ $( $where_clause )* }
{ $( $common )* }
{
$( $parsed )* $( $parsed )*
PARAM { $param , $param_from , $param_to , $param_instancer } PARAM { $param , $param_from , $param_to , $param_instancer }
} { $eval } { $( $rest )* } $postcode }
{ $eval }
{ $( $rest )* }
$postcode
} }
}; };
// mutation arm to look after defaulting to a common param // mutation arm to look after defaulting to a common param
( { $( $instance:ident )? } $name:ident { (
$( $where_clause:tt )* { $( $instance:ident )? }
} { $name:ident
$( { $common:ident , $common_from:tt , $common_to:expr , $common_instancer:expr } )* { $( $where_clause:tt )* }
} { { $( { $common:ident , $common_from:tt , $common_to:expr , $common_instancer:expr } )* }
$( $parsed:tt )* { $( $parsed:tt )* }
} { $eval:block } { { $eval:block }
let $param:ident in ...; {
$( $rest:tt )* let $param:ident in ...;
} $postcode:block) => { $( $rest:tt )*
}
$postcode:block
) => {
$crate::benchmark_backend! { $crate::benchmark_backend! {
{ $( $instance)? } $name { $( $where_clause )* } { { $( $instance)? }
$( { $common , $common_from , $common_to , $common_instancer } )* $name
} { { $( $where_clause )* }
$( $parsed )* { $( { $common , $common_from , $common_to , $common_instancer } )* }
} { $eval } { { $( $parsed )* }
{ $eval }
{
let $param let $param
in ({ $( let $common = $common_from; )* $param }) in ({ $( let $common = $common_from; )* $param })
.. ({ $( let $common = $common_to; )* $param }) .. ({ $( let $common = $common_to; )* $param })
=> ({ $( let $common = || -> Result<(), &'static str> { $common_instancer ; Ok(()) }; )* $param()? }); => ({ $( let $common = || -> Result<(), &'static str> { $common_instancer ; Ok(()) }; )* $param()? });
$( $rest )* $( $rest )*
} $postcode }
$postcode
} }
}; };
// mutation arm to look after defaulting only the range to common param // mutation arm to look after defaulting only the range to common param
( { $( $instance:ident )? } $name:ident { (
$( $where_clause:tt )* { $( $instance:ident )? }
} { $name:ident
$( { $common:ident , $common_from:tt , $common_to:expr , $common_instancer:expr } )* { $( $where_clause:tt )* }
} { { $( { $common:ident , $common_from:tt , $common_to:expr , $common_instancer:expr } )* }
$( $parsed:tt )* { $( $parsed:tt )* }
} { $eval:block } { { $eval:block }
let $param:ident in _ .. _ => $param_instancer:expr ; {
$( $rest:tt )* let $param:ident in _ .. _ => $param_instancer:expr ;
} $postcode:block) => { $( $rest:tt )*
}
$postcode:block
) => {
$crate::benchmark_backend! { $crate::benchmark_backend! {
{ $( $instance)? } $name { $( $where_clause )* } { { $( $instance)? }
$( { $common , $common_from , $common_to , $common_instancer } )* $name
} { { $( $where_clause )* }
$( $parsed )* { $( { $common , $common_from , $common_to , $common_instancer } )* }
} { $eval } { { $( $parsed )* }
{ $eval }
{
let $param let $param
in ({ $( let $common = $common_from; )* $param }) in ({ $( let $common = $common_from; )* $param })
.. ({ $( let $common = $common_to; )* $param }) .. ({ $( let $common = $common_to; )* $param })
=> $param_instancer ; => $param_instancer ;
$( $rest )* $( $rest )*
} $postcode }
$postcode
} }
}; };
// mutation arm to look after a single tt for param_from. // mutation arm to look after a single tt for param_from.
( { $( $instance:ident )? } $name:ident { (
$( $where_clause:tt )* { $( $instance:ident )? }
} { $name:ident
$( $common:tt )* { $( $where_clause:tt )* }
} { { $( $common:tt )* }
$( $parsed:tt )* { $( $parsed:tt )* }
} { $eval:block } { { $eval:block }
let $param:ident in $param_from:tt .. $param_to:expr => $param_instancer:expr ; {
$( $rest:tt )* let $param:ident in $param_from:tt .. $param_to:expr => $param_instancer:expr ;
} $postcode:block) => { $( $rest:tt )*
}
$postcode:block
) => {
$crate::benchmark_backend! { $crate::benchmark_backend! {
{ $( $instance)? } { $( $instance)? }
$name { $( $where_clause )* } { $( $common )* } { $( $parsed )* } { $eval } { $name
{ $( $where_clause )* }
{ $( $common )* }
{ $( $parsed )* }
{ $eval }
{
let $param in ( $param_from ) .. $param_to => $param_instancer; let $param in ( $param_from ) .. $param_to => $param_instancer;
$( $rest )* $( $rest )*
} $postcode }
$postcode
} }
}; };
// mutation arm to look after the default tail of `=> ()` // mutation arm to look after the default tail of `=> ()`
( { $( $instance:ident )? } $name:ident { (
$( $where_clause:tt )* { $( $instance:ident )? }
} { $name:ident
$( $common:tt )* { $( $where_clause:tt )* }
} { { $( $common:tt )* }
$( $parsed:tt )* { $( $parsed:tt )* }
} { $eval:block } { { $eval:block }
let $param:ident in $param_from:tt .. $param_to:expr; {
$( $rest:tt )* let $param:ident in $param_from:tt .. $param_to:expr;
} $postcode:block) => { $( $rest:tt )*
}
$postcode:block
) => {
$crate::benchmark_backend! { $crate::benchmark_backend! {
{ $( $instance)? } { $( $instance)? }
$name { $( $where_clause )* } { $( $common )* } { $( $parsed )* } { $eval } { $name
{ $( $where_clause )* }
{ $( $common )* }
{ $( $parsed )* }
{ $eval }
{
let $param in $param_from .. $param_to => (); let $param in $param_from .. $param_to => ();
$( $rest )* $( $rest )*
} $postcode }
$postcode
} }
}; };
// mutation arm to look after `let _ =` // mutation arm to look after `let _ =`
( { $( $instance:ident )? } $name:ident { (
$( $where_clause:tt )* { $( $instance:ident )? }
} { $name:ident
$( $common:tt )* { $( $where_clause:tt )* }
} { { $( $common:tt )* }
$( $parsed:tt )* { $( $parsed:tt )* }
} { $eval:block } { { $eval:block }
let $pre_id:tt = $pre_ex:expr; {
$( $rest:tt )* let $pre_id:tt = $pre_ex:expr;
} $postcode:block) => { $( $rest:tt )*
}
$postcode:block
) => {
$crate::benchmark_backend! { $crate::benchmark_backend! {
{ $( $instance)? } { $( $instance)? }
$name { $( $where_clause )* } { $( $common )* } { $( $parsed )* } { $eval } { $name
{ $( $where_clause )* }
{ $( $common )* }
{ $( $parsed )* }
{ $eval }
{
let $pre_id : _ = $pre_ex; let $pre_id : _ = $pre_ex;
$( $rest )* $( $rest )*
} $postcode }
$postcode
} }
}; };
// actioning arm // actioning arm
( { $( $instance:ident )? } $name:ident { (
$( $where_clause:tt )* { $( $instance:ident )? }
} { $name:ident
$( { $common:ident , $common_from:tt , $common_to:expr , $common_instancer:expr } )* { $( $where_clause:tt )* }
} { { $( { $common:ident , $common_from:tt , $common_to:expr , $common_instancer:expr } )* }
$( PRE { $pre_id:tt , $pre_ty:ty , $pre_ex:expr } )* {
$( PARAM { $param:ident , $param_from:expr , $param_to:expr , $param_instancer:expr } )* $( PRE { $pre_id:tt , $pre_ty:ty , $pre_ex:expr } )*
} { $eval:block } { $( $post:tt )* } $postcode:block) => { $( PARAM { $param:ident , $param_from:expr , $param_to:expr , $param_instancer:expr } )*
}
{ $eval:block }
{ $( $post:tt )* }
$postcode:block
) => {
#[allow(non_camel_case_types)] #[allow(non_camel_case_types)]
struct $name; struct $name;
#[allow(unused_variables)] #[allow(unused_variables)]
@@ -726,7 +791,7 @@ macro_rules! impl_benchmark {
highest_range_values: &[u32], highest_range_values: &[u32],
steps: &[u32], steps: &[u32],
repeat: u32, repeat: u32,
whitelist: &[Vec<u8>] whitelist: &[$crate::TrackedStorageKey]
) -> Result<Vec<$crate::BenchmarkResults>, &'static str> { ) -> Result<Vec<$crate::BenchmarkResults>, &'static str> {
// Map the input to the selected benchmark. // Map the input to the selected benchmark.
let extrinsic = sp_std::str::from_utf8(extrinsic) let extrinsic = sp_std::str::from_utf8(extrinsic)
@@ -736,8 +801,14 @@ macro_rules! impl_benchmark {
_ => return Err("Could not find extrinsic."), _ => return Err("Could not find extrinsic."),
}; };
// Add whitelist to DB // Add whitelist to DB including whitelisted caller
$crate::benchmarking::set_whitelist(whitelist.to_vec()); let mut whitelist = whitelist.to_vec();
let whitelisted_caller_key =
<frame_system::Account::<T> as frame_support::storage::StorageMap<_,_>>::hashed_key_for(
$crate::whitelisted_caller::<T::AccountId>()
);
whitelist.push(whitelisted_caller_key.into());
$crate::benchmarking::set_whitelist(whitelist);
// Warm up the DB // Warm up the DB
$crate::benchmarking::commit_db(); $crate::benchmarking::commit_db();
@@ -947,19 +1018,25 @@ macro_rules! impl_benchmark_test {
/// let params = (&pallet, &benchmark, &lowest_range_values, &highest_range_values, &steps, repeat, &whitelist); /// let params = (&pallet, &benchmark, &lowest_range_values, &highest_range_values, &steps, repeat, &whitelist);
/// ``` /// ```
/// ///
/// The `whitelist` is a `Vec<Vec<u8>>` of storage keys that you would like to skip for DB tracking. For example: /// The `whitelist` is a parameter you pass to control the DB read/write tracking.
/// We use a vector of [TrackedStorageKey](./struct.TrackedStorageKey.html), which is a simple struct used to set
/// if a key has been read or written to.
/// ///
/// ```ignore /// For values that should be skipped entirely, we can just pass `key.into()`. For example:
/// let whitelist: Vec<Vec<u8>> = vec![ ///
/// ```
/// use frame_benchmarking::TrackedStorageKey;
/// let whitelist: Vec<TrackedStorageKey> = vec![
/// // Block Number /// // Block Number
/// hex_literal::hex!("26aa394eea5630e07c48ae0c9558cef702a5c1b19ab7a04f536c519aca4983ac").to_vec(), /// hex_literal::hex!("26aa394eea5630e07c48ae0c9558cef702a5c1b19ab7a04f536c519aca4983ac").to_vec().into(),
/// // Total Issuance /// // Total Issuance
/// hex_literal::hex!("c2261276cc9d1f8598ea4b6a74b15c2f57c875e4cff74148e4628f264b974c80").to_vec(), /// hex_literal::hex!("c2261276cc9d1f8598ea4b6a74b15c2f57c875e4cff74148e4628f264b974c80").to_vec().into(),
/// // Execution Phase /// // Execution Phase
/// hex_literal::hex!("26aa394eea5630e07c48ae0c9558cef7ff553b5a9862a516939d82b3d3d8661a").to_vec(), /// hex_literal::hex!("26aa394eea5630e07c48ae0c9558cef7ff553b5a9862a516939d82b3d3d8661a").to_vec().into(),
/// // Event Count /// // Event Count
/// hex_literal::hex!("26aa394eea5630e07c48ae0c9558cef70a98fdbe9ce6c55837576c60c7af3850").to_vec(), /// hex_literal::hex!("26aa394eea5630e07c48ae0c9558cef70a98fdbe9ce6c55837576c60c7af3850").to_vec().into(),
/// ]; /// ];
/// ```
/// ///
/// Then define a mutable local variable to hold your `BenchmarkBatch` object: /// Then define a mutable local variable to hold your `BenchmarkBatch` object:
/// ///
+3 -9
View File
@@ -20,7 +20,6 @@
#![cfg(test)] #![cfg(test)]
use super::*; use super::*;
use codec::Decode;
use sp_std::prelude::*; use sp_std::prelude::*;
use sp_runtime::{traits::{BlakeTwo256, IdentityLookup}, testing::{H256, Header}}; use sp_runtime::{traits::{BlakeTwo256, IdentityLookup}, testing::{H256, Header}};
use frame_support::{ use frame_support::{
@@ -64,12 +63,10 @@ pub trait OtherTrait {
type OtherEvent; type OtherEvent;
} }
pub trait Trait: OtherTrait where Self::OtherEvent: Into<Self::Event> { pub trait Trait: frame_system::Trait + OtherTrait
where Self::OtherEvent: Into<<Self as Trait>::Event>
{
type Event; type Event;
type BlockNumber;
type AccountId: 'static + Default + Decode;
type Origin: From<frame_system::RawOrigin<Self::AccountId>> +
Into<Result<RawOrigin<Self::AccountId>, Self::Origin>>;
} }
#[derive(Clone, Eq, PartialEq)] #[derive(Clone, Eq, PartialEq)]
@@ -105,9 +102,6 @@ impl frame_system::Trait for Test {
impl Trait for Test { impl Trait for Test {
type Event = (); type Event = ();
type BlockNumber = u32;
type Origin = Origin;
type AccountId = u64;
} }
impl OtherTrait for Test { impl OtherTrait for Test {
+43 -4
View File
@@ -21,6 +21,7 @@ use codec::{Encode, Decode};
use sp_std::{vec::Vec, prelude::Box}; use sp_std::{vec::Vec, prelude::Box};
use sp_io::hashing::blake2_256; use sp_io::hashing::blake2_256;
use sp_runtime::RuntimeString; use sp_runtime::RuntimeString;
use sp_storage::TrackedStorageKey;
/// An alphabet of possible parameters to use for benchmarking. /// An alphabet of possible parameters to use for benchmarking.
#[derive(Encode, Decode, Clone, Copy, PartialEq, Debug)] #[derive(Encode, Decode, Clone, Copy, PartialEq, Debug)]
@@ -101,19 +102,52 @@ pub trait Benchmarking {
self.commit() self.commit()
} }
/// Get the read/write count /// Get the read/write count.
fn read_write_count(&self) -> (u32, u32, u32, u32) { fn read_write_count(&self) -> (u32, u32, u32, u32) {
self.read_write_count() self.read_write_count()
} }
/// Reset the read/write count /// Reset the read/write count.
fn reset_read_write_count(&mut self) { fn reset_read_write_count(&mut self) {
self.reset_read_write_count() self.reset_read_write_count()
} }
fn set_whitelist(&mut self, new: Vec<Vec<u8>>) { /// Get the DB whitelist.
fn get_whitelist(&self) -> Vec<TrackedStorageKey> {
self.get_whitelist()
}
/// Set the DB whitelist.
fn set_whitelist(&mut self, new: Vec<TrackedStorageKey>) {
self.set_whitelist(new) self.set_whitelist(new)
} }
// Add a new item to the DB whitelist.
fn add_to_whitelist(&mut self, add: TrackedStorageKey) {
let mut whitelist = self.get_whitelist();
match whitelist.iter_mut().find(|x| x.key == add.key) {
// If we already have this key in the whitelist, update to be the most constrained value.
Some(item) => {
*item = TrackedStorageKey {
key: add.key,
has_been_read: item.has_been_read || add.has_been_read,
has_been_written: item.has_been_written || add.has_been_written,
}
},
// If the key does not exist, add it.
None => {
whitelist.push(add);
}
}
self.set_whitelist(whitelist);
}
// Remove an item from the DB whitelist.
fn remove_from_whitelist(&mut self, remove: Vec<u8>) {
let mut whitelist = self.get_whitelist();
whitelist.retain(|x| x.key != remove);
self.set_whitelist(whitelist);
}
} }
/// The pallet benchmarking trait. /// The pallet benchmarking trait.
@@ -141,7 +175,7 @@ pub trait Benchmarking<T> {
highest_range_values: &[u32], highest_range_values: &[u32],
steps: &[u32], steps: &[u32],
repeat: u32, repeat: u32,
whitelist: &[Vec<u8>] whitelist: &[TrackedStorageKey]
) -> Result<Vec<T>, &'static str>; ) -> Result<Vec<T>, &'static str>;
} }
@@ -165,3 +199,8 @@ pub fn account<AccountId: Decode + Default>(name: &'static str, index: u32, seed
let entropy = (name, index, seed).using_encoded(blake2_256); let entropy = (name, index, seed).using_encoded(blake2_256);
AccountId::decode(&mut &entropy[..]).unwrap_or_default() AccountId::decode(&mut &entropy[..]).unwrap_or_default()
} }
/// This caller account is automatically whitelisted for DB reads/writes by the benchmarking macro.
pub fn whitelisted_caller<AccountId: Decode + Default>() -> AccountId {
account::<AccountId>("whitelisted_caller", 0, 0)
}
@@ -21,7 +21,7 @@ use super::*;
use frame_system::RawOrigin as SystemOrigin; use frame_system::RawOrigin as SystemOrigin;
use frame_system::EventRecord; use frame_system::EventRecord;
use frame_benchmarking::{benchmarks_instance, account}; use frame_benchmarking::{benchmarks_instance, account, whitelisted_caller};
use sp_runtime::traits::Bounded; use sp_runtime::traits::Bounded;
use sp_std::mem::size_of; use sp_std::mem::size_of;
@@ -123,7 +123,7 @@ benchmarks_instance! {
members.push(member); members.push(member);
} }
let caller: T::AccountId = account("caller", 0, SEED); let caller: T::AccountId = whitelisted_caller();
members.push(caller.clone()); members.push(caller.clone());
Collective::<T, _>::set_members(SystemOrigin::Root.into(), members, None, MAX_MEMBERS)?; Collective::<T, _>::set_members(SystemOrigin::Root.into(), members, None, MAX_MEMBERS)?;
@@ -153,7 +153,7 @@ benchmarks_instance! {
members.push(member); members.push(member);
} }
let caller: T::AccountId = account("caller", 0, SEED); let caller: T::AccountId = whitelisted_caller();
members.push(caller.clone()); members.push(caller.clone());
Collective::<T, _>::set_members(SystemOrigin::Root.into(), members, None, MAX_MEMBERS)?; Collective::<T, _>::set_members(SystemOrigin::Root.into(), members, None, MAX_MEMBERS)?;
@@ -184,7 +184,7 @@ benchmarks_instance! {
let member = account("member", i, SEED); let member = account("member", i, SEED);
members.push(member); members.push(member);
} }
let caller: T::AccountId = account("caller", 0, SEED); let caller: T::AccountId = whitelisted_caller();
members.push(caller.clone()); members.push(caller.clone());
Collective::<T, _>::set_members(SystemOrigin::Root.into(), members, None, MAX_MEMBERS)?; Collective::<T, _>::set_members(SystemOrigin::Root.into(), members, None, MAX_MEMBERS)?;
@@ -377,7 +377,7 @@ benchmarks_instance! {
let member = account("member", i, SEED); let member = account("member", i, SEED);
members.push(member); members.push(member);
} }
let caller: T::AccountId = account("caller", 0, SEED); let caller: T::AccountId = whitelisted_caller();
members.push(caller.clone()); members.push(caller.clone());
Collective::<T, _>::set_members(SystemOrigin::Root.into(), members.clone(), None, MAX_MEMBERS)?; Collective::<T, _>::set_members(SystemOrigin::Root.into(), members.clone(), None, MAX_MEMBERS)?;
@@ -458,7 +458,7 @@ benchmarks_instance! {
let member = account("member", i, SEED); let member = account("member", i, SEED);
members.push(member); members.push(member);
} }
let caller: T::AccountId = account("caller", 0, SEED); let caller: T::AccountId = whitelisted_caller();
members.push(caller.clone()); members.push(caller.clone());
Collective::<T, _>::set_members( Collective::<T, _>::set_members(
SystemOrigin::Root.into(), SystemOrigin::Root.into(),
@@ -530,7 +530,7 @@ benchmarks_instance! {
let member = account("member", i, SEED); let member = account("member", i, SEED);
members.push(member); members.push(member);
} }
let caller: T::AccountId = account("caller", 0, SEED); let caller: T::AccountId = whitelisted_caller();
members.push(caller.clone()); members.push(caller.clone());
Collective::<T, _>::set_members( Collective::<T, _>::set_members(
SystemOrigin::Root.into(), SystemOrigin::Root.into(),
+5 -5
View File
@@ -21,7 +21,7 @@
use super::*; use super::*;
use frame_system::RawOrigin; use frame_system::RawOrigin;
use frame_benchmarking::{benchmarks, account}; use frame_benchmarking::{benchmarks, account, whitelisted_caller};
use sp_runtime::traits::Bounded; use sp_runtime::traits::Bounded;
use crate::Module as Indices; use crate::Module as Indices;
@@ -35,7 +35,7 @@ benchmarks! {
// Index being claimed // Index being claimed
let i in 0 .. 1000; let i in 0 .. 1000;
let account_index = T::AccountIndex::from(i); let account_index = T::AccountIndex::from(i);
let caller: T::AccountId = account("caller", 0, SEED); let caller: T::AccountId = whitelisted_caller();
T::Currency::make_free_balance_be(&caller, BalanceOf::<T>::max_value()); T::Currency::make_free_balance_be(&caller, BalanceOf::<T>::max_value());
}: _(RawOrigin::Signed(caller.clone()), account_index) }: _(RawOrigin::Signed(caller.clone()), account_index)
verify { verify {
@@ -47,7 +47,7 @@ benchmarks! {
let i in 0 .. 1000; let i in 0 .. 1000;
let account_index = T::AccountIndex::from(i); let account_index = T::AccountIndex::from(i);
// Setup accounts // Setup accounts
let caller: T::AccountId = account("caller", 0, SEED); let caller: T::AccountId = whitelisted_caller();
T::Currency::make_free_balance_be(&caller, BalanceOf::<T>::max_value()); T::Currency::make_free_balance_be(&caller, BalanceOf::<T>::max_value());
let recipient: T::AccountId = account("recipient", i, SEED); let recipient: T::AccountId = account("recipient", i, SEED);
T::Currency::make_free_balance_be(&recipient, BalanceOf::<T>::max_value()); T::Currency::make_free_balance_be(&recipient, BalanceOf::<T>::max_value());
@@ -63,7 +63,7 @@ benchmarks! {
let i in 0 .. 1000; let i in 0 .. 1000;
let account_index = T::AccountIndex::from(i); let account_index = T::AccountIndex::from(i);
// Setup accounts // Setup accounts
let caller: T::AccountId = account("caller", 0, SEED); let caller: T::AccountId = whitelisted_caller();
T::Currency::make_free_balance_be(&caller, BalanceOf::<T>::max_value()); T::Currency::make_free_balance_be(&caller, BalanceOf::<T>::max_value());
// Claim the index // Claim the index
Indices::<T>::claim(RawOrigin::Signed(caller.clone()).into(), account_index)?; Indices::<T>::claim(RawOrigin::Signed(caller.clone()).into(), account_index)?;
@@ -93,7 +93,7 @@ benchmarks! {
let i in 0 .. 1000; let i in 0 .. 1000;
let account_index = T::AccountIndex::from(i); let account_index = T::AccountIndex::from(i);
// Setup accounts // Setup accounts
let caller: T::AccountId = account("caller", 0, SEED); let caller: T::AccountId = whitelisted_caller();
T::Currency::make_free_balance_be(&caller, BalanceOf::<T>::max_value()); T::Currency::make_free_balance_be(&caller, BalanceOf::<T>::max_value());
// Claim the index // Claim the index
Indices::<T>::claim(RawOrigin::Signed(caller.clone()).into(), account_index)?; Indices::<T>::claim(RawOrigin::Signed(caller.clone()).into(), account_index)?;
+9 -9
View File
@@ -21,14 +21,14 @@
use super::*; use super::*;
use frame_system::RawOrigin; use frame_system::RawOrigin;
use frame_benchmarking::{benchmarks, account}; use frame_benchmarking::{benchmarks, account, whitelisted_caller};
use sp_runtime::traits::Bounded; use sp_runtime::traits::Bounded;
use crate::Module as Proxy; use crate::Module as Proxy;
const SEED: u32 = 0; const SEED: u32 = 0;
fn add_proxies<T: Trait>(n: u32, maybe_who: Option<T::AccountId>) -> Result<(), &'static str> { fn add_proxies<T: Trait>(n: u32, maybe_who: Option<T::AccountId>) -> Result<(), &'static str> {
let caller = maybe_who.unwrap_or_else(|| account("caller", 0, SEED)); let caller = maybe_who.unwrap_or_else(|| whitelisted_caller());
T::Currency::make_free_balance_be(&caller, BalanceOf::<T>::max_value()); T::Currency::make_free_balance_be(&caller, BalanceOf::<T>::max_value());
for i in 0..n { for i in 0..n {
Proxy::<T>::add_proxy( Proxy::<T>::add_proxy(
@@ -50,35 +50,35 @@ benchmarks! {
// In this case the caller is the "target" proxy // In this case the caller is the "target" proxy
let caller: T::AccountId = account("target", p - 1, SEED); let caller: T::AccountId = account("target", p - 1, SEED);
// ... and "real" is the traditional caller. This is not a typo. // ... and "real" is the traditional caller. This is not a typo.
let real: T::AccountId = account("caller", 0, SEED); let real: T::AccountId = whitelisted_caller();
let call: <T as Trait>::Call = frame_system::Call::<T>::remark(vec![]).into(); let call: <T as Trait>::Call = frame_system::Call::<T>::remark(vec![]).into();
}: _(RawOrigin::Signed(caller), real, Some(T::ProxyType::default()), Box::new(call)) }: _(RawOrigin::Signed(caller), real, Some(T::ProxyType::default()), Box::new(call))
add_proxy { add_proxy {
let p in ...; let p in ...;
let caller: T::AccountId = account("caller", 0, SEED); let caller: T::AccountId = whitelisted_caller();
}: _(RawOrigin::Signed(caller), account("target", T::MaxProxies::get().into(), SEED), T::ProxyType::default()) }: _(RawOrigin::Signed(caller), account("target", T::MaxProxies::get().into(), SEED), T::ProxyType::default())
remove_proxy { remove_proxy {
let p in ...; let p in ...;
let caller: T::AccountId = account("caller", 0, SEED); let caller: T::AccountId = whitelisted_caller();
}: _(RawOrigin::Signed(caller), account("target", 0, SEED), T::ProxyType::default()) }: _(RawOrigin::Signed(caller), account("target", 0, SEED), T::ProxyType::default())
remove_proxies { remove_proxies {
let p in ...; let p in ...;
let caller: T::AccountId = account("caller", 0, SEED); let caller: T::AccountId = whitelisted_caller();
}: _(RawOrigin::Signed(caller)) }: _(RawOrigin::Signed(caller))
anonymous { anonymous {
let p in ...; let p in ...;
}: _(RawOrigin::Signed(account("caller", 0, SEED)), T::ProxyType::default(), 0) }: _(RawOrigin::Signed(whitelisted_caller()), T::ProxyType::default(), 0)
kill_anonymous { kill_anonymous {
let p in 0 .. (T::MaxProxies::get() - 2).into(); let p in 0 .. (T::MaxProxies::get() - 2).into();
let caller: T::AccountId = account("caller", 0, SEED); let caller: T::AccountId = whitelisted_caller();
T::Currency::make_free_balance_be(&caller, BalanceOf::<T>::max_value()); T::Currency::make_free_balance_be(&caller, BalanceOf::<T>::max_value());
Module::<T>::anonymous(RawOrigin::Signed(account("caller", 0, SEED)).into(), T::ProxyType::default(), 0)?; Module::<T>::anonymous(RawOrigin::Signed(whitelisted_caller()).into(), T::ProxyType::default(), 0)?;
let height = system::Module::<T>::block_number(); let height = system::Module::<T>::block_number();
let ext_index = system::Module::<T>::extrinsic_index().unwrap_or(0); let ext_index = system::Module::<T>::extrinsic_index().unwrap_or(0);
let anon = Module::<T>::anonymous_account(&caller, &T::ProxyType::default(), 0, None); let anon = Module::<T>::anonymous_account(&caller, &T::ProxyType::default(), 0, None);
+16 -4
View File
@@ -23,7 +23,7 @@ use testing_utils::*;
use sp_runtime::traits::One; use sp_runtime::traits::One;
use frame_system::RawOrigin; use frame_system::RawOrigin;
pub use frame_benchmarking::{benchmarks, account}; pub use frame_benchmarking::{benchmarks, account, whitelisted_caller};
const SEED: u32 = 0; const SEED: u32 = 0;
const MAX_SPANS: u32 = 100; const MAX_SPANS: u32 = 100;
const MAX_VALIDATORS: u32 = 1000; const MAX_VALIDATORS: u32 = 1000;
@@ -280,7 +280,7 @@ benchmarks! {
let validator = create_validator_with_nominators::<T>(n, T::MaxNominatorRewardedPerValidator::get() as u32, true)?; let validator = create_validator_with_nominators::<T>(n, T::MaxNominatorRewardedPerValidator::get() as u32, true)?;
let current_era = CurrentEra::get().unwrap(); let current_era = CurrentEra::get().unwrap();
let caller = account("caller", 0, SEED); let caller = whitelisted_caller();
let balance_before = T::Currency::free_balance(&validator); let balance_before = T::Currency::free_balance(&validator);
}: _(RawOrigin::Signed(caller), validator.clone(), current_era) }: _(RawOrigin::Signed(caller), validator.clone(), current_era)
verify { verify {
@@ -294,7 +294,7 @@ benchmarks! {
let validator = create_validator_with_nominators::<T>(n, T::MaxNominatorRewardedPerValidator::get() as u32, false)?; let validator = create_validator_with_nominators::<T>(n, T::MaxNominatorRewardedPerValidator::get() as u32, false)?;
let current_era = CurrentEra::get().unwrap(); let current_era = CurrentEra::get().unwrap();
let caller = account("caller", 0, SEED); let caller = whitelisted_caller();
let balance_before = T::Currency::free_balance(&validator); let balance_before = T::Currency::free_balance(&validator);
}: payout_stakers(RawOrigin::Signed(caller), validator.clone(), current_era) }: payout_stakers(RawOrigin::Signed(caller), validator.clone(), current_era)
verify { verify {
@@ -419,7 +419,7 @@ benchmarks! {
let total_payout = T::Currency::minimum_balance() * 1000.into(); let total_payout = T::Currency::minimum_balance() * 1000.into();
<ErasValidatorReward<T>>::insert(current_era, total_payout); <ErasValidatorReward<T>>::insert(current_era, total_payout);
let caller: T::AccountId = account("caller", 0, SEED); let caller: T::AccountId = whitelisted_caller();
}: { }: {
for arg in payout_calls_arg { for arg in payout_calls_arg {
<Staking<T>>::payout_stakers(RawOrigin::Signed(caller.clone()).into(), arg.0, arg.1)?; <Staking<T>>::payout_stakers(RawOrigin::Signed(caller.clone()).into(), arg.0, arg.1)?;
@@ -471,6 +471,10 @@ benchmarks! {
let era = <Staking<T>>::current_era().unwrap_or(0); let era = <Staking<T>>::current_era().unwrap_or(0);
let caller: T::AccountId = account("caller", n, SEED); let caller: T::AccountId = account("caller", n, SEED);
// Whitelist caller account from further DB operations.
let caller_key = frame_system::Account::<T>::hashed_key_for(&caller);
frame_benchmarking::benchmarking::add_to_whitelist(caller_key.into());
}: { }: {
let result = <Staking<T>>::submit_election_solution( let result = <Staking<T>>::submit_election_solution(
RawOrigin::Signed(caller.clone()).into(), RawOrigin::Signed(caller.clone()).into(),
@@ -532,6 +536,10 @@ benchmarks! {
let era = <Staking<T>>::current_era().unwrap_or(0); let era = <Staking<T>>::current_era().unwrap_or(0);
let caller: T::AccountId = account("caller", n, SEED); let caller: T::AccountId = account("caller", n, SEED);
// Whitelist caller account from further DB operations.
let caller_key = frame_system::Account::<T>::hashed_key_for(&caller);
frame_benchmarking::benchmarking::add_to_whitelist(caller_key.into());
// submit a very bad solution on-chain // submit a very bad solution on-chain
{ {
// this is needed to fool the chain to accept this solution. // this is needed to fool the chain to accept this solution.
@@ -584,6 +592,10 @@ benchmarks! {
let caller: T::AccountId = account("caller", n, SEED); let caller: T::AccountId = account("caller", n, SEED);
let era = <Staking<T>>::current_era().unwrap_or(0); let era = <Staking<T>>::current_era().unwrap_or(0);
// Whitelist caller account from further DB operations.
let caller_key = frame_system::Account::<T>::hashed_key_for(&caller);
frame_benchmarking::benchmarking::add_to_whitelist(caller_key.into());
// submit a seq-phragmen with all the good stuff on chain. // submit a seq-phragmen with all the good stuff on chain.
{ {
let (winners, compact, score, size) = get_seq_phragmen_solution::<T>(true); let (winners, compact, score, size) = get_seq_phragmen_solution::<T>(true);
@@ -24,15 +24,13 @@ use sp_std::vec;
use sp_std::prelude::*; use sp_std::prelude::*;
use sp_core::{ChangesTrieConfiguration, storage::well_known_keys}; use sp_core::{ChangesTrieConfiguration, storage::well_known_keys};
use sp_runtime::traits::Hash; use sp_runtime::traits::Hash;
use frame_benchmarking::{benchmarks, account}; use frame_benchmarking::{benchmarks, whitelisted_caller};
use frame_support::traits::Get; use frame_support::traits::Get;
use frame_support::storage::{self, StorageMap}; use frame_support::storage::{self, StorageMap};
use frame_system::{Module as System, Call, RawOrigin, DigestItemOf, AccountInfo}; use frame_system::{Module as System, Call, RawOrigin, DigestItemOf, AccountInfo};
mod mock; mod mock;
const SEED: u32 = 0;
pub struct Module<T: Trait>(System<T>); pub struct Module<T: Trait>(System<T>);
pub trait Trait: frame_system::Trait {} pub trait Trait: frame_system::Trait {}
@@ -42,7 +40,7 @@ benchmarks! {
remark { remark {
let b in 0 .. T::MaximumBlockLength::get(); let b in 0 .. T::MaximumBlockLength::get();
let remark_message = vec![1; b as usize]; let remark_message = vec![1; b as usize];
let caller = account("caller", 0, SEED); let caller = whitelisted_caller();
}: _(RawOrigin::Signed(caller), remark_message) }: _(RawOrigin::Signed(caller), remark_message)
set_heap_pages { set_heap_pages {
@@ -139,7 +137,7 @@ benchmarks! {
} }
suicide { suicide {
let caller: T::AccountId = account("caller", 0, SEED); let caller: T::AccountId = whitelisted_caller();
let account_info = AccountInfo::<T::Index, T::AccountData> { let account_info = AccountInfo::<T::Index, T::AccountData> {
nonce: 1337.into(), nonce: 1337.into(),
refcount: 0, refcount: 0,
+11 -3
View File
@@ -23,7 +23,7 @@ use super::*;
use sp_std::prelude::*; use sp_std::prelude::*;
use frame_system::RawOrigin; use frame_system::RawOrigin;
use frame_support::{ensure, traits::OnFinalize}; use frame_support::{ensure, traits::OnFinalize};
use frame_benchmarking::benchmarks; use frame_benchmarking::{benchmarks, TrackedStorageKey};
use crate::Module as Timestamp; use crate::Module as Timestamp;
@@ -34,8 +34,14 @@ benchmarks! {
set { set {
let t in 1 .. MAX_TIME; let t in 1 .. MAX_TIME;
// Ignore write to `DidUpdate` since it transient.
let did_update_key = crate::DidUpdate::hashed_key().to_vec();
frame_benchmarking::benchmarking::add_to_whitelist(TrackedStorageKey {
key: did_update_key,
has_been_read: false,
has_been_written: true,
});
}: _(RawOrigin::None, t.into()) }: _(RawOrigin::None, t.into())
verify { verify {
ensure!(Timestamp::<T>::now() == t.into(), "Time was not set."); ensure!(Timestamp::<T>::now() == t.into(), "Time was not set.");
} }
@@ -44,8 +50,10 @@ benchmarks! {
let t in 1 .. MAX_TIME; let t in 1 .. MAX_TIME;
Timestamp::<T>::set(RawOrigin::None.into(), t.into())?; Timestamp::<T>::set(RawOrigin::None.into(), t.into())?;
ensure!(DidUpdate::exists(), "Time was not set."); ensure!(DidUpdate::exists(), "Time was not set.");
// Ignore read/write to `DidUpdate` since it is transient.
let did_update_key = crate::DidUpdate::hashed_key().to_vec();
frame_benchmarking::benchmarking::add_to_whitelist(did_update_key.into());
}: { Timestamp::<T>::on_finalize(t.into()); } }: { Timestamp::<T>::on_finalize(t.into()); }
verify { verify {
ensure!(!DidUpdate::exists(), "Time was not removed."); ensure!(!DidUpdate::exists(), "Time was not removed.");
} }
+20 -2
View File
@@ -22,7 +22,7 @@
use super::*; use super::*;
use frame_system::RawOrigin; use frame_system::RawOrigin;
use frame_benchmarking::{benchmarks, account}; use frame_benchmarking::{benchmarks, account, whitelisted_caller};
use frame_support::traits::OnInitialize; use frame_support::traits::OnInitialize;
use crate::Module as Treasury; use crate::Module as Treasury;
@@ -45,7 +45,7 @@ fn setup_proposal<T: Trait>(u: u32) -> (
// Create the pre-requisite information needed to create a `report_awesome`. // Create the pre-requisite information needed to create a `report_awesome`.
fn setup_awesome<T: Trait>(length: u32) -> (T::AccountId, Vec<u8>, T::AccountId) { fn setup_awesome<T: Trait>(length: u32) -> (T::AccountId, Vec<u8>, T::AccountId) {
let caller = account("caller", 0, SEED); let caller = whitelisted_caller();
let value = T::TipReportDepositBase::get() let value = T::TipReportDepositBase::get()
+ T::TipReportDepositPerByte::get() * length.into() + T::TipReportDepositPerByte::get() * length.into()
+ T::Currency::minimum_balance(); + T::Currency::minimum_balance();
@@ -116,6 +116,9 @@ benchmarks! {
propose_spend { propose_spend {
let u in 0 .. 1000; let u in 0 .. 1000;
let (caller, value, beneficiary_lookup) = setup_proposal::<T>(u); let (caller, value, beneficiary_lookup) = setup_proposal::<T>(u);
// Whitelist caller account from further DB operations.
let caller_key = frame_system::Account::<T>::hashed_key_for(&caller);
frame_benchmarking::benchmarking::add_to_whitelist(caller_key.into());
}: _(RawOrigin::Signed(caller), value, beneficiary_lookup) }: _(RawOrigin::Signed(caller), value, beneficiary_lookup)
reject_proposal { reject_proposal {
@@ -143,6 +146,9 @@ benchmarks! {
report_awesome { report_awesome {
let r in 0 .. MAX_BYTES; let r in 0 .. MAX_BYTES;
let (caller, reason, awesome_person) = setup_awesome::<T>(r); let (caller, reason, awesome_person) = setup_awesome::<T>(r);
// Whitelist caller account from further DB operations.
let caller_key = frame_system::Account::<T>::hashed_key_for(&caller);
frame_benchmarking::benchmarking::add_to_whitelist(caller_key.into());
}: _(RawOrigin::Signed(caller), reason, awesome_person) }: _(RawOrigin::Signed(caller), reason, awesome_person)
retract_tip { retract_tip {
@@ -155,6 +161,9 @@ benchmarks! {
)?; )?;
let reason_hash = T::Hashing::hash(&reason[..]); let reason_hash = T::Hashing::hash(&reason[..]);
let hash = T::Hashing::hash_of(&(&reason_hash, &awesome_person)); let hash = T::Hashing::hash_of(&(&reason_hash, &awesome_person));
// Whitelist caller account from further DB operations.
let caller_key = frame_system::Account::<T>::hashed_key_for(&caller);
frame_benchmarking::benchmarking::add_to_whitelist(caller_key.into());
}: _(RawOrigin::Signed(caller), hash) }: _(RawOrigin::Signed(caller), hash)
tip_new { tip_new {
@@ -162,6 +171,9 @@ benchmarks! {
let t in 1 .. MAX_TIPPERS; let t in 1 .. MAX_TIPPERS;
let (caller, reason, beneficiary, value) = setup_tip::<T>(r, t)?; let (caller, reason, beneficiary, value) = setup_tip::<T>(r, t)?;
// Whitelist caller account from further DB operations.
let caller_key = frame_system::Account::<T>::hashed_key_for(&caller);
frame_benchmarking::benchmarking::add_to_whitelist(caller_key.into());
}: _(RawOrigin::Signed(caller), reason, beneficiary, value) }: _(RawOrigin::Signed(caller), reason, beneficiary, value)
tip { tip {
@@ -179,6 +191,9 @@ benchmarks! {
ensure!(Tips::<T>::contains_key(hash), "tip does not exist"); ensure!(Tips::<T>::contains_key(hash), "tip does not exist");
create_tips::<T>(t - 1, hash.clone(), value)?; create_tips::<T>(t - 1, hash.clone(), value)?;
let caller = account("member", t - 1, SEED); let caller = account("member", t - 1, SEED);
// Whitelist caller account from further DB operations.
let caller_key = frame_system::Account::<T>::hashed_key_for(&caller);
frame_benchmarking::benchmarking::add_to_whitelist(caller_key.into());
}: _(RawOrigin::Signed(caller), hash, value) }: _(RawOrigin::Signed(caller), hash, value)
close_tip { close_tip {
@@ -206,6 +221,9 @@ benchmarks! {
create_tips::<T>(t, hash.clone(), value)?; create_tips::<T>(t, hash.clone(), value)?;
let caller = account("caller", t, SEED); let caller = account("caller", t, SEED);
// Whitelist caller account from further DB operations.
let caller_key = frame_system::Account::<T>::hashed_key_for(&caller);
frame_benchmarking::benchmarking::add_to_whitelist(caller_key.into());
}: _(RawOrigin::Signed(caller), hash) }: _(RawOrigin::Signed(caller), hash)
on_initialize { on_initialize {
+5 -2
View File
@@ -21,7 +21,7 @@
use super::*; use super::*;
use frame_system::{RawOrigin, EventRecord}; use frame_system::{RawOrigin, EventRecord};
use frame_benchmarking::{benchmarks, account}; use frame_benchmarking::{benchmarks, account, whitelisted_caller};
const SEED: u32 = 0; const SEED: u32 = 0;
@@ -43,7 +43,7 @@ benchmarks! {
let call = frame_system::Call::remark(vec![]).into(); let call = frame_system::Call::remark(vec![]).into();
calls.push(call); calls.push(call);
} }
let caller = account("caller", 0, SEED); let caller = whitelisted_caller();
}: _(RawOrigin::Signed(caller), calls) }: _(RawOrigin::Signed(caller), calls)
verify { verify {
assert_last_event::<T>(Event::BatchCompleted.into()) assert_last_event::<T>(Event::BatchCompleted.into())
@@ -53,6 +53,9 @@ benchmarks! {
let u in 0 .. 1000; let u in 0 .. 1000;
let caller = account("caller", u, SEED); let caller = account("caller", u, SEED);
let call = Box::new(frame_system::Call::remark(vec![]).into()); let call = Box::new(frame_system::Call::remark(vec![]).into());
// Whitelist caller account from further DB operations.
let caller_key = frame_system::Account::<T>::hashed_key_for(&caller);
frame_benchmarking::benchmarking::add_to_whitelist(caller_key.into());
}: _(RawOrigin::Signed(caller), u as u16, call) }: _(RawOrigin::Signed(caller), u as u16, call)
} }
+6 -6
View File
@@ -22,7 +22,7 @@
use super::*; use super::*;
use frame_system::{RawOrigin, Module as System}; use frame_system::{RawOrigin, Module as System};
use frame_benchmarking::{benchmarks, account}; use frame_benchmarking::{benchmarks, account, whitelisted_caller};
use sp_runtime::traits::Bounded; use sp_runtime::traits::Bounded;
use crate::Module as Vesting; use crate::Module as Vesting;
@@ -64,7 +64,7 @@ benchmarks! {
vest_locked { vest_locked {
let l in 0 .. MAX_LOCKS; let l in 0 .. MAX_LOCKS;
let caller = account("caller", 0, SEED); let caller = whitelisted_caller();
T::Currency::make_free_balance_be(&caller, BalanceOf::<T>::max_value()); T::Currency::make_free_balance_be(&caller, BalanceOf::<T>::max_value());
add_locks::<T>(&caller, l as u8); add_locks::<T>(&caller, l as u8);
add_vesting_schedule::<T>(&caller)?; add_vesting_schedule::<T>(&caller)?;
@@ -88,7 +88,7 @@ benchmarks! {
vest_unlocked { vest_unlocked {
let l in 0 .. MAX_LOCKS; let l in 0 .. MAX_LOCKS;
let caller = account("caller", 0, SEED); let caller = whitelisted_caller();
T::Currency::make_free_balance_be(&caller, BalanceOf::<T>::max_value()); T::Currency::make_free_balance_be(&caller, BalanceOf::<T>::max_value());
add_locks::<T>(&caller, l as u8); add_locks::<T>(&caller, l as u8);
add_vesting_schedule::<T>(&caller)?; add_vesting_schedule::<T>(&caller)?;
@@ -125,7 +125,7 @@ benchmarks! {
"Vesting schedule not added", "Vesting schedule not added",
); );
let caller: T::AccountId = account("caller", 0, SEED); let caller: T::AccountId = whitelisted_caller();
}: vest_other(RawOrigin::Signed(caller.clone()), other_lookup) }: vest_other(RawOrigin::Signed(caller.clone()), other_lookup)
verify { verify {
// Nothing happened since everything is still vested. // Nothing happened since everything is still vested.
@@ -152,7 +152,7 @@ benchmarks! {
"Vesting schedule still active", "Vesting schedule still active",
); );
let caller: T::AccountId = account("caller", 0, SEED); let caller: T::AccountId = whitelisted_caller();
}: vest_other(RawOrigin::Signed(caller.clone()), other_lookup) }: vest_other(RawOrigin::Signed(caller.clone()), other_lookup)
verify { verify {
// Vesting schedule is removed! // Vesting schedule is removed!
@@ -166,7 +166,7 @@ benchmarks! {
vested_transfer { vested_transfer {
let l in 0 .. MAX_LOCKS; let l in 0 .. MAX_LOCKS;
let caller: T::AccountId = account("caller", 0, SEED); let caller: T::AccountId = whitelisted_caller();
T::Currency::make_free_balance_be(&caller, BalanceOf::<T>::max_value()); T::Currency::make_free_balance_be(&caller, BalanceOf::<T>::max_value());
let target: T::AccountId = account("target", 0, SEED); let target: T::AccountId = account("target", 0, SEED);
let target_lookup: <T::Lookup as StaticLookup>::Source = T::Lookup::unlookup(target.clone()); let target_lookup: <T::Lookup as StaticLookup>::Source = T::Lookup::unlookup(target.clone());
@@ -25,7 +25,7 @@
use std::any::{Any, TypeId}; use std::any::{Any, TypeId};
use sp_storage::ChildInfo; use sp_storage::{ChildInfo, TrackedStorageKey};
pub use scope_limited::{set_and_run_with_externalities, with_externalities}; pub use scope_limited::{set_and_run_with_externalities, with_externalities};
pub use extensions::{Extension, Extensions, ExtensionStore}; pub use extensions::{Extension, Extensions, ExtensionStore};
@@ -248,12 +248,19 @@ pub trait Externalities: ExtensionStore {
/// Resets read/write count for the benchmarking process. /// Resets read/write count for the benchmarking process.
fn reset_read_write_count(&mut self); fn reset_read_write_count(&mut self);
/// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
/// Benchmarking related functionality and shouldn't be used anywhere else!
/// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
///
/// Gets the current DB tracking whitelist.
fn get_whitelist(&self) -> Vec<TrackedStorageKey>;
/// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! /// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
/// Benchmarking related functionality and shouldn't be used anywhere else! /// Benchmarking related functionality and shouldn't be used anywhere else!
/// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! /// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
/// ///
/// Adds new storage keys to the DB tracking whitelist. /// Adds new storage keys to the DB tracking whitelist.
fn set_whitelist(&mut self, new: Vec<Vec<u8>>); fn set_whitelist(&mut self, new: Vec<TrackedStorageKey>);
} }
/// Extension for the [`Externalities`] trait. /// Extension for the [`Externalities`] trait.
@@ -21,6 +21,7 @@ sp-externalities = { version = "0.8.0-rc5", optional = true, path = "../external
codec = { package = "parity-scale-codec", version = "1.3.1", default-features = false } codec = { package = "parity-scale-codec", version = "1.3.1", default-features = false }
static_assertions = "1.0.0" static_assertions = "1.0.0"
primitive-types = { version = "0.7.0", default-features = false } primitive-types = { version = "0.7.0", default-features = false }
sp-storage = { version = "2.0.0-rc5", default-features = false, path = "../storage" }
[dev-dependencies] [dev-dependencies]
sp-runtime-interface-test-wasm = { version = "2.0.0-rc5", path = "test-wasm" } sp-runtime-interface-test-wasm = { version = "2.0.0-rc5", path = "test-wasm" }
@@ -537,3 +537,7 @@ impl PassBy for sp_wasm_interface::ValueType {
impl PassBy for sp_wasm_interface::Value { impl PassBy for sp_wasm_interface::Value {
type PassBy = Codec<sp_wasm_interface::Value>; type PassBy = Codec<sp_wasm_interface::Value>;
} }
impl PassBy for sp_storage::TrackedStorageKey {
type PassBy = Codec<Self>;
}
@@ -19,7 +19,10 @@
use hash_db::Hasher; use hash_db::Hasher;
use codec::{Decode, Encode}; use codec::{Decode, Encode};
use sp_core::{traits::RuntimeCode, storage::{ChildInfo, well_known_keys}}; use sp_core::{
traits::RuntimeCode,
storage::{ChildInfo, well_known_keys, TrackedStorageKey}
};
use crate::{ use crate::{
trie_backend::TrieBackend, trie_backend::TrieBackend,
trie_backend_essence::TrieBackendStorage, trie_backend_essence::TrieBackendStorage,
@@ -226,10 +229,13 @@ pub trait Backend<H: Hasher>: std::fmt::Debug {
unimplemented!() unimplemented!()
} }
/// Update the whitelist for tracking db reads/writes /// Get the whitelist for tracking db reads/writes
fn set_whitelist(&self, _: Vec<Vec<u8>>) { fn get_whitelist(&self) -> Vec<TrackedStorageKey> {
unimplemented!() Default::default()
} }
/// Update the whitelist for tracking db reads/writes
fn set_whitelist(&self, _: Vec<TrackedStorageKey>) {}
} }
impl<'a, T: Backend<H>, H: Hasher> Backend<H> for &'a T { impl<'a, T: Backend<H>, H: Hasher> Backend<H> for &'a T {
@@ -27,7 +27,7 @@ use sp_trie::trie_types::Layout;
use sp_core::{ use sp_core::{
storage::{ storage::{
well_known_keys::is_child_storage_key, Storage, well_known_keys::is_child_storage_key, Storage,
ChildInfo, StorageChild, ChildInfo, StorageChild, TrackedStorageKey,
}, },
traits::Externalities, Blake2Hasher, traits::Externalities, Blake2Hasher,
}; };
@@ -325,7 +325,11 @@ impl Externalities for BasicExternalities {
unimplemented!("reset_read_write_count is not supported in Basic") unimplemented!("reset_read_write_count is not supported in Basic")
} }
fn set_whitelist(&mut self, _: Vec<Vec<u8>>) { fn get_whitelist(&self) -> Vec<TrackedStorageKey> {
unimplemented!("get_whitelist is not supported in Basic")
}
fn set_whitelist(&mut self, _: Vec<TrackedStorageKey>) {
unimplemented!("set_whitelist is not supported in Basic") unimplemented!("set_whitelist is not supported in Basic")
} }
} }
@@ -26,7 +26,7 @@ use crate::{
use hash_db::Hasher; use hash_db::Hasher;
use sp_core::{ use sp_core::{
offchain::storage::OffchainOverlayedChanges, offchain::storage::OffchainOverlayedChanges,
storage::{well_known_keys::is_child_storage_key, ChildInfo}, storage::{well_known_keys::is_child_storage_key, ChildInfo, TrackedStorageKey},
traits::Externalities, hexdisplay::HexDisplay, traits::Externalities, hexdisplay::HexDisplay,
}; };
use sp_trie::{trie_types::Layout, empty_child_trie_root}; use sp_trie::{trie_types::Layout, empty_child_trie_root};
@@ -609,7 +609,11 @@ where
self.backend.reset_read_write_count() self.backend.reset_read_write_count()
} }
fn set_whitelist(&mut self, new: Vec<Vec<u8>>) { fn get_whitelist(&self) -> Vec<TrackedStorageKey> {
self.backend.get_whitelist()
}
fn set_whitelist(&mut self, new: Vec<TrackedStorageKey>) {
self.backend.set_whitelist(new) self.backend.set_whitelist(new)
} }
} }
@@ -24,7 +24,7 @@ use std::{
use crate::{Backend, StorageKey, StorageValue}; use crate::{Backend, StorageKey, StorageValue};
use hash_db::Hasher; use hash_db::Hasher;
use sp_core::{ use sp_core::{
storage::ChildInfo, storage::{ChildInfo, TrackedStorageKey},
traits::Externalities, Blake2Hasher, traits::Externalities, Blake2Hasher,
}; };
use codec::Encode; use codec::Encode;
@@ -194,7 +194,11 @@ impl<'a, H: Hasher, B: 'a + Backend<H>> Externalities for ReadOnlyExternalities<
unimplemented!("reset_read_write_count is not supported in ReadOnlyExternalities") unimplemented!("reset_read_write_count is not supported in ReadOnlyExternalities")
} }
fn set_whitelist(&mut self, _: Vec<Vec<u8>>) { fn get_whitelist(&self) -> Vec<TrackedStorageKey> {
unimplemented!("get_whitelist is not supported in ReadOnlyExternalities")
}
fn set_whitelist(&mut self, _: Vec<TrackedStorageKey>) {
unimplemented!("set_whitelist is not supported in ReadOnlyExternalities") unimplemented!("set_whitelist is not supported in ReadOnlyExternalities")
} }
} }
+2 -1
View File
@@ -18,7 +18,8 @@ serde = { version = "1.0.101", optional = true, features = ["derive"] }
impl-serde = { version = "0.2.3", optional = true } impl-serde = { version = "0.2.3", optional = true }
ref-cast = "1.0.0" ref-cast = "1.0.0"
sp-debug-derive = { version = "2.0.0-rc5", path = "../debug-derive" } sp-debug-derive = { version = "2.0.0-rc5", path = "../debug-derive" }
codec = { package = "parity-scale-codec", version = "1.3.1", default-features = false, features = ["derive"] }
[features] [features]
default = [ "std" ] default = [ "std" ]
std = [ "sp-std/std", "serde", "impl-serde" ] std = [ "sp-std/std", "serde", "impl-serde", "codec/std" ]
+21
View File
@@ -25,6 +25,7 @@ use sp_debug_derive::RuntimeDebug;
use sp_std::{vec::Vec, ops::{Deref, DerefMut}}; use sp_std::{vec::Vec, ops::{Deref, DerefMut}};
use ref_cast::RefCast; use ref_cast::RefCast;
use codec::{Encode, Decode};
/// Storage key. /// Storage key.
#[derive(PartialEq, Eq, RuntimeDebug)] #[derive(PartialEq, Eq, RuntimeDebug)]
@@ -34,6 +35,26 @@ pub struct StorageKey(
pub Vec<u8>, pub Vec<u8>,
); );
/// Storage key with read/write tracking information.
#[derive(PartialEq, Eq, RuntimeDebug, Clone, Encode, Decode)]
#[cfg_attr(feature = "std", derive(Hash, PartialOrd, Ord))]
pub struct TrackedStorageKey {
pub key: Vec<u8>,
pub has_been_read: bool,
pub has_been_written: bool,
}
// Easily convert a key to a `TrackedStorageKey` that has been read and written to.
impl From<Vec<u8>> for TrackedStorageKey {
fn from(key: Vec<u8>) -> Self {
Self {
key: key,
has_been_read: true,
has_been_written: true,
}
}
}
/// Storage key of a child trie, it contains the prefix to the key. /// Storage key of a child trie, it contains the prefix to the key.
#[derive(PartialEq, Eq, RuntimeDebug)] #[derive(PartialEq, Eq, RuntimeDebug)]
#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Hash, PartialOrd, Ord, Clone))] #[cfg_attr(feature = "std", derive(Serialize, Deserialize, Hash, PartialOrd, Ord, Clone))]