mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-05-09 23:28:00 +00:00
Benchmark macro (#4962)
* MAcro benchamrks * Iterative macro * Tidying it up. * Macro improvements * Bits.. * Last benchmaks. * Repo benchmark macro * Add the possibility of evaluating arbitrary expressions in a benchmaark * Better syntax and docs * Update `BenchmarkParameter` * Add `ignore` to sudo-code in docs * First try of timestamp implementation. * Fix macro docs, remove warnings. * Use macro in balances pallet. * Make some space in frame benchmarking. * Remove _benchmarks_seed variable. * Bump impl_version. Co-authored-by: Shawn Tabrizi <shawntabrizi@gmail.com> Co-authored-by: Marcio Diaz <marcio@parity.io>
This commit is contained in:
Generated
+4416
-4417
File diff suppressed because it is too large
Load Diff
@@ -82,7 +82,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion {
|
||||
// implementation changes and behavior does not, then leave spec_version as
|
||||
// is and increment impl_version.
|
||||
spec_version: 224,
|
||||
impl_version: 0,
|
||||
impl_version: 1,
|
||||
apis: RUNTIME_API_VERSIONS,
|
||||
};
|
||||
|
||||
|
||||
@@ -19,305 +19,101 @@
|
||||
use super::*;
|
||||
|
||||
use frame_system::RawOrigin;
|
||||
use sp_io::hashing::blake2_256;
|
||||
use frame_benchmarking::{
|
||||
BenchmarkResults, BenchmarkParameter, Benchmarking, BenchmarkingSetup, benchmarking,
|
||||
};
|
||||
use frame_benchmarking::{benchmarks, account};
|
||||
use sp_runtime::traits::{Bounded, Dispatchable};
|
||||
|
||||
use crate::Module as Balances;
|
||||
|
||||
// Support Functions
|
||||
fn account<T: Trait>(name: &'static str, index: u32) -> T::AccountId {
|
||||
let entropy = (name, index).using_encoded(blake2_256);
|
||||
T::AccountId::decode(&mut &entropy[..]).unwrap_or_default()
|
||||
}
|
||||
const SEED: u32 = 0;
|
||||
const MAX_EXISTENTIAL_DEPOSIT: u32 = 1000;
|
||||
const MAX_USER_INDEX: u32 = 1000;
|
||||
|
||||
// Benchmark `transfer` extrinsic with the worst possible conditions:
|
||||
// * Transfer will kill the sender account.
|
||||
// * Transfer will create the recipient account.
|
||||
struct Transfer;
|
||||
impl<T: Trait> BenchmarkingSetup<T, crate::Call<T>, RawOrigin<T::AccountId>> for Transfer {
|
||||
fn components(&self) -> Vec<(BenchmarkParameter, u32, u32)> {
|
||||
vec![
|
||||
// Existential Deposit Multiplier
|
||||
(BenchmarkParameter::E, 2, 1000),
|
||||
// User Seed
|
||||
(BenchmarkParameter::U, 1, 1000),
|
||||
]
|
||||
benchmarks! {
|
||||
_ {
|
||||
let e in 2 .. MAX_EXISTENTIAL_DEPOSIT => ();
|
||||
let u in 1 .. MAX_USER_INDEX => ();
|
||||
}
|
||||
|
||||
fn instance(&self, components: &[(BenchmarkParameter, u32)])
|
||||
-> Result<(crate::Call<T>, RawOrigin<T::AccountId>), &'static str>
|
||||
{
|
||||
// Constants
|
||||
let ed = T::ExistentialDeposit::get();
|
||||
// Benchmark `transfer` extrinsic with the worst possible conditions:
|
||||
// * Transfer will kill the sender account.
|
||||
// * Transfer will create the recipient account.
|
||||
transfer {
|
||||
let u in ...;
|
||||
let e in ...;
|
||||
|
||||
// Select an account
|
||||
let u = components.iter().find(|&c| c.0 == BenchmarkParameter::U).unwrap().1;
|
||||
let user = account::<T>("user", u);
|
||||
let user_origin = RawOrigin::Signed(user.clone());
|
||||
let existential_deposit = T::ExistentialDeposit::get();
|
||||
let caller = account("caller", u, SEED);
|
||||
|
||||
// Give some multiple of the existential deposit + creation fee + transfer fee
|
||||
let e = components.iter().find(|&c| c.0 == BenchmarkParameter::E).unwrap().1;
|
||||
let balance = ed.saturating_mul(e.into());
|
||||
let _ = <Balances<T> as Currency<_>>::make_free_balance_be(&user, balance);
|
||||
let balance = existential_deposit.saturating_mul(e.into());
|
||||
let _ = <Balances<T> as Currency<_>>::make_free_balance_be(&caller, balance);
|
||||
|
||||
// Transfer `e - 1` existential deposits + 1 unit, which guarantees to create one account, and reap this user.
|
||||
let recipient = account::<T>("recipient", u);
|
||||
let recipient = account("recipient", u, SEED);
|
||||
let recipient_lookup: <T::Lookup as StaticLookup>::Source = T::Lookup::unlookup(recipient);
|
||||
let transfer_amt = ed.saturating_mul((e - 1).into()) + 1.into();
|
||||
let transfer_amount = existential_deposit.saturating_mul((e - 1).into()) + 1.into();
|
||||
}: _(RawOrigin::Signed(caller), recipient_lookup, transfer_amount)
|
||||
|
||||
// Return the `transfer` call
|
||||
Ok((crate::Call::<T>::transfer(recipient_lookup, transfer_amt), user_origin))
|
||||
}
|
||||
}
|
||||
// Benchmark `transfer` with the best possible condition:
|
||||
// * Both accounts exist and will continue to exist.
|
||||
transfer_best_case {
|
||||
let u in ...;
|
||||
let e in ...;
|
||||
|
||||
// Benchmark `transfer` with the best possible condition:
|
||||
// * Both accounts exist and will continue to exist.
|
||||
struct TransferBestCase;
|
||||
impl<T: Trait> BenchmarkingSetup<T, crate::Call<T>, RawOrigin<T::AccountId>> for TransferBestCase {
|
||||
fn components(&self) -> Vec<(BenchmarkParameter, u32, u32)> {
|
||||
vec![
|
||||
// Existential Deposit Multiplier
|
||||
(BenchmarkParameter::E, 2, 1000),
|
||||
// User Seed
|
||||
(BenchmarkParameter::U, 1, 1000),
|
||||
]
|
||||
}
|
||||
|
||||
fn instance(&self, components: &[(BenchmarkParameter, u32)])
|
||||
-> Result<(crate::Call<T>, RawOrigin<T::AccountId>), &'static str>
|
||||
{
|
||||
// Constants
|
||||
let ed = T::ExistentialDeposit::get();
|
||||
|
||||
// Select a sender
|
||||
let u = components.iter().find(|&c| c.0 == BenchmarkParameter::U).unwrap().1;
|
||||
let user = account::<T>("user", u);
|
||||
let user_origin = RawOrigin::Signed(user.clone());
|
||||
|
||||
// Select a recipient
|
||||
let recipient = account::<T>("recipient", u);
|
||||
let caller = account("caller", u, SEED);
|
||||
let recipient: T::AccountId = account("recipient", u, SEED);
|
||||
let recipient_lookup: <T::Lookup as StaticLookup>::Source = T::Lookup::unlookup(recipient.clone());
|
||||
|
||||
// Get the existential deposit multiplier
|
||||
let e = components.iter().find(|&c| c.0 == BenchmarkParameter::E).unwrap().1;
|
||||
|
||||
// Give the sender account max funds for transfer (their account will never reasonably be killed).
|
||||
let _ = <Balances<T> as Currency<_>>::make_free_balance_be(&user, T::Balance::max_value());
|
||||
let _ = <Balances<T> as Currency<_>>::make_free_balance_be(&caller, T::Balance::max_value());
|
||||
|
||||
// Give the recipient account existential deposit (thus their account already exists).
|
||||
let _ = <Balances<T> as Currency<_>>::make_free_balance_be(&recipient, ed);
|
||||
let existential_deposit = T::ExistentialDeposit::get();
|
||||
let _ = <Balances<T> as Currency<_>>::make_free_balance_be(&recipient, existential_deposit);
|
||||
let transfer_amount = existential_deposit.saturating_mul(e.into());
|
||||
}: transfer(RawOrigin::Signed(caller), recipient_lookup, transfer_amount)
|
||||
|
||||
// Transfer e * existential deposit.
|
||||
let transfer_amt = ed.saturating_mul(e.into());
|
||||
// Benchmark `transfer_keep_alive` with the worst possible condition:
|
||||
// * The recipient account is created.
|
||||
transfer_keep_alive {
|
||||
let u in ...;
|
||||
let e in ...;
|
||||
|
||||
// Return the `transfer` call
|
||||
Ok((crate::Call::<T>::transfer(recipient_lookup, transfer_amt), user_origin))
|
||||
}
|
||||
}
|
||||
|
||||
// Benchmark `transfer_keep_alive` with the worst possible condition:
|
||||
// * The recipient account is created.
|
||||
struct TransferKeepAlive;
|
||||
impl<T: Trait> BenchmarkingSetup<T, crate::Call<T>, RawOrigin<T::AccountId>> for TransferKeepAlive {
|
||||
fn components(&self) -> Vec<(BenchmarkParameter, u32, u32)> {
|
||||
vec![
|
||||
// Existential Deposit Multiplier
|
||||
(BenchmarkParameter::E, 2, 1000),
|
||||
// User Seed
|
||||
(BenchmarkParameter::U, 1, 1000),
|
||||
]
|
||||
}
|
||||
|
||||
fn instance(&self, components: &[(BenchmarkParameter, u32)])
|
||||
-> Result<(crate::Call<T>, RawOrigin<T::AccountId>), &'static str>
|
||||
{
|
||||
// Constants
|
||||
let ed = T::ExistentialDeposit::get();
|
||||
|
||||
// Select a sender
|
||||
let u = components.iter().find(|&c| c.0 == BenchmarkParameter::U).unwrap().1;
|
||||
let user = account::<T>("user", u);
|
||||
let user_origin = RawOrigin::Signed(user.clone());
|
||||
|
||||
// Select a recipient
|
||||
let recipient = account::<T>("recipient", u);
|
||||
let recipient_lookup: <T::Lookup as StaticLookup>::Source = T::Lookup::unlookup(recipient.clone());
|
||||
|
||||
// Get the existential deposit multiplier
|
||||
let e = components.iter().find(|&c| c.0 == BenchmarkParameter::E).unwrap().1;
|
||||
let caller = account("caller", u, SEED);
|
||||
let recipient = account("recipient", u, SEED);
|
||||
let recipient_lookup: <T::Lookup as StaticLookup>::Source = T::Lookup::unlookup(recipient);
|
||||
|
||||
// Give the sender account max funds, thus a transfer will not kill account.
|
||||
let _ = <Balances<T> as Currency<_>>::make_free_balance_be(&user, T::Balance::max_value());
|
||||
let _ = <Balances<T> as Currency<_>>::make_free_balance_be(&caller, T::Balance::max_value());
|
||||
let existential_deposit = T::ExistentialDeposit::get();
|
||||
let transfer_amount = existential_deposit.saturating_mul(e.into());
|
||||
}: _(RawOrigin::Signed(caller), recipient_lookup, transfer_amount)
|
||||
|
||||
// Transfer e * existential deposit.
|
||||
let transfer_amt = ed.saturating_mul(e.into());
|
||||
// Benchmark `set_balance` coming from ROOT account. This always creates an account.
|
||||
set_balance {
|
||||
let u in ...;
|
||||
let e in ...;
|
||||
|
||||
// Return the `transfer_keep_alive` call
|
||||
Ok((crate::Call::<T>::transfer_keep_alive(recipient_lookup, transfer_amt), user_origin))
|
||||
}
|
||||
}
|
||||
|
||||
// Benchmark `set_balance` coming from ROOT account. This always creates an account.
|
||||
struct SetBalance;
|
||||
impl<T: Trait> BenchmarkingSetup<T, crate::Call<T>, RawOrigin<T::AccountId>> for SetBalance {
|
||||
fn components(&self) -> Vec<(BenchmarkParameter, u32, u32)> {
|
||||
vec![
|
||||
// Existential Deposit Multiplier
|
||||
(BenchmarkParameter::E, 2, 1000),
|
||||
// User Seed
|
||||
(BenchmarkParameter::U, 1, 1000),
|
||||
]
|
||||
}
|
||||
|
||||
fn instance(&self, components: &[(BenchmarkParameter, u32)])
|
||||
-> Result<(crate::Call<T>, RawOrigin<T::AccountId>), &'static str>
|
||||
{
|
||||
// Constants
|
||||
let ed = T::ExistentialDeposit::get();
|
||||
|
||||
// Select a sender
|
||||
let u = components.iter().find(|&c| c.0 == BenchmarkParameter::U).unwrap().1;
|
||||
let user = account::<T>("user", u);
|
||||
let user: T::AccountId = account("user", u, SEED);
|
||||
let user_lookup: <T::Lookup as StaticLookup>::Source = T::Lookup::unlookup(user.clone());
|
||||
|
||||
// Get the existential deposit multiplier for free and reserved
|
||||
let e = components.iter().find(|&c| c.0 == BenchmarkParameter::E).unwrap().1;
|
||||
let balance_amt = ed.saturating_mul(e.into());
|
||||
// Give the user some initial balance.
|
||||
let existential_deposit = T::ExistentialDeposit::get();
|
||||
let balance_amount = existential_deposit.saturating_mul(e.into());
|
||||
let _ = <Balances<T> as Currency<_>>::make_free_balance_be(&user, balance_amount);
|
||||
}: _(RawOrigin::Root, user_lookup, balance_amount, balance_amount)
|
||||
|
||||
// Return the `set_balance` call
|
||||
Ok((crate::Call::<T>::set_balance(user_lookup, balance_amt, balance_amt), RawOrigin::Root))
|
||||
}
|
||||
}
|
||||
// Benchmark `set_balance` coming from ROOT account. This always kills an account.
|
||||
set_balance_killing {
|
||||
let u in ...;
|
||||
let e in ...;
|
||||
|
||||
// Benchmark `set_balance` coming from ROOT account. This always kills an account.
|
||||
struct SetBalanceKilling;
|
||||
impl<T: Trait> BenchmarkingSetup<T, crate::Call<T>, RawOrigin<T::AccountId>> for SetBalanceKilling {
|
||||
fn components(&self) -> Vec<(BenchmarkParameter, u32, u32)> {
|
||||
vec![
|
||||
// Existential Deposit Multiplier
|
||||
(BenchmarkParameter::E, 2, 1000),
|
||||
// User Seed
|
||||
(BenchmarkParameter::U, 1, 1000),
|
||||
]
|
||||
}
|
||||
|
||||
fn instance(&self, components: &[(BenchmarkParameter, u32)])
|
||||
-> Result<(crate::Call<T>, RawOrigin<T::AccountId>), &'static str>
|
||||
{
|
||||
// Constants
|
||||
let ed = T::ExistentialDeposit::get();
|
||||
|
||||
// Select a sender
|
||||
let u = components.iter().find(|&c| c.0 == BenchmarkParameter::U).unwrap().1;
|
||||
let user = account::<T>("user", u);
|
||||
let user: T::AccountId = account("user", u, SEED);
|
||||
let user_lookup: <T::Lookup as StaticLookup>::Source = T::Lookup::unlookup(user.clone());
|
||||
|
||||
// Get the existential deposit multiplier for free and reserved
|
||||
let e = components.iter().find(|&c| c.0 == BenchmarkParameter::E).unwrap().1;
|
||||
// Give the user some initial balance
|
||||
let balance_amt = ed.saturating_mul(e.into());
|
||||
let _ = <Balances<T> as Currency<_>>::make_free_balance_be(&user, balance_amt);
|
||||
|
||||
// Return the `set_balance` call that will kill the account
|
||||
Ok((crate::Call::<T>::set_balance(user_lookup, 0.into(), 0.into()), RawOrigin::Root))
|
||||
}
|
||||
}
|
||||
|
||||
// The list of available benchmarks for this pallet.
|
||||
enum SelectedBenchmark {
|
||||
Transfer,
|
||||
TransferBestCase,
|
||||
TransferKeepAlive,
|
||||
SetBalance,
|
||||
SetBalanceKilling,
|
||||
}
|
||||
|
||||
// Allow us to select a benchmark from the list of available benchmarks.
|
||||
impl<T: Trait> BenchmarkingSetup<T, crate::Call<T>, RawOrigin<T::AccountId>> for SelectedBenchmark {
|
||||
fn components(&self) -> Vec<(BenchmarkParameter, u32, u32)> {
|
||||
match self {
|
||||
Self::Transfer => <Transfer as BenchmarkingSetup<T, crate::Call<T>, RawOrigin<T::AccountId>>>::components(&Transfer),
|
||||
Self::TransferBestCase => <TransferBestCase as BenchmarkingSetup<T, crate::Call<T>, RawOrigin<T::AccountId>>>::components(&TransferBestCase),
|
||||
Self::TransferKeepAlive => <TransferKeepAlive as BenchmarkingSetup<T, crate::Call<T>, RawOrigin<T::AccountId>>>::components(&TransferKeepAlive),
|
||||
Self::SetBalance => <SetBalance as BenchmarkingSetup<T, crate::Call<T>, RawOrigin<T::AccountId>>>::components(&SetBalance),
|
||||
Self::SetBalanceKilling => <SetBalanceKilling as BenchmarkingSetup<T, crate::Call<T>, RawOrigin<T::AccountId>>>::components(&SetBalanceKilling),
|
||||
}
|
||||
}
|
||||
|
||||
fn instance(&self, components: &[(BenchmarkParameter, u32)])
|
||||
-> Result<(crate::Call<T>, RawOrigin<T::AccountId>), &'static str>
|
||||
{
|
||||
match self {
|
||||
Self::Transfer => <Transfer as BenchmarkingSetup<T, crate::Call<T>, RawOrigin<T::AccountId>>>::instance(&Transfer, components),
|
||||
Self::TransferBestCase => <TransferBestCase as BenchmarkingSetup<T, crate::Call<T>, RawOrigin<T::AccountId>>>::instance(&TransferBestCase, components),
|
||||
Self::TransferKeepAlive => <TransferKeepAlive as BenchmarkingSetup<T, crate::Call<T>, RawOrigin<T::AccountId>>>::instance(&TransferKeepAlive, components),
|
||||
Self::SetBalance => <SetBalance as BenchmarkingSetup<T, crate::Call<T>, RawOrigin<T::AccountId>>>::instance(&SetBalance, components),
|
||||
Self::SetBalanceKilling => <SetBalanceKilling as BenchmarkingSetup<T, crate::Call<T>, RawOrigin<T::AccountId>>>::instance(&SetBalanceKilling, components),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Trait> Benchmarking<BenchmarkResults> for Module<T> {
|
||||
fn run_benchmark(extrinsic: Vec<u8>, steps: u32, repeat: u32) -> Result<Vec<BenchmarkResults>, &'static str> {
|
||||
// Map the input to the selected benchmark.
|
||||
let selected_benchmark = match extrinsic.as_slice() {
|
||||
b"transfer" => SelectedBenchmark::Transfer,
|
||||
b"transfer_best_case" => SelectedBenchmark::TransferBestCase,
|
||||
b"transfer_keep_alive" => SelectedBenchmark::TransferKeepAlive,
|
||||
b"set_balance" => SelectedBenchmark::SetBalance,
|
||||
b"set_balance_killing" => SelectedBenchmark::SetBalanceKilling,
|
||||
_ => return Err("Could not find extrinsic."),
|
||||
};
|
||||
|
||||
// Warm up the DB
|
||||
benchmarking::commit_db();
|
||||
benchmarking::wipe_db();
|
||||
|
||||
let components = <SelectedBenchmark as BenchmarkingSetup<T, crate::Call<T>, RawOrigin<T::AccountId>>>::components(&selected_benchmark);
|
||||
// results go here
|
||||
let mut results: Vec<BenchmarkResults> = Vec::new();
|
||||
// Select the component we will be benchmarking. Each component will be benchmarked.
|
||||
for (name, low, high) in components.iter() {
|
||||
// Create up to `STEPS` steps for that component between high and low.
|
||||
let step_size = ((high - low) / steps).max(1);
|
||||
let num_of_steps = (high - low) / step_size;
|
||||
for s in 0..num_of_steps {
|
||||
// This is the value we will be testing for component `name`
|
||||
let component_value = low + step_size * s;
|
||||
|
||||
// Select the mid value for all the other components.
|
||||
let c: Vec<(BenchmarkParameter, u32)> = components.iter()
|
||||
.map(|(n, l, h)|
|
||||
(*n, if n == name { component_value } else { (h - l) / 2 + l })
|
||||
).collect();
|
||||
|
||||
// Run the benchmark `repeat` times.
|
||||
for _r in 0..repeat {
|
||||
// Set up the externalities environment for the setup we want to benchmark.
|
||||
let (call, caller) = <SelectedBenchmark as BenchmarkingSetup<T, crate::Call<T>, RawOrigin<T::AccountId>>>::instance(&selected_benchmark, &c)?;
|
||||
// Commit the externalities to the database, flushing the DB cache.
|
||||
// This will enable worst case scenario for reading from the database.
|
||||
benchmarking::commit_db();
|
||||
// Run the benchmark.
|
||||
let start = benchmarking::current_time();
|
||||
call.dispatch(caller.clone().into())?;
|
||||
let finish = benchmarking::current_time();
|
||||
let elapsed = finish - start;
|
||||
sp_std::if_std!{
|
||||
if let RawOrigin::Signed(who) = caller.clone() {
|
||||
let balance = Account::<T>::get(&who).free;
|
||||
println!("Free Balance {:?}", balance);
|
||||
}
|
||||
}
|
||||
results.push((c.clone(), elapsed));
|
||||
// Wipe the DB back to the genesis state.
|
||||
benchmarking::wipe_db();
|
||||
}
|
||||
}
|
||||
}
|
||||
return Ok(results);
|
||||
}
|
||||
}
|
||||
// Give the user some initial balance.
|
||||
let existential_deposit = T::ExistentialDeposit::get();
|
||||
let balance_amount = existential_deposit.saturating_mul(e.into());
|
||||
let _ = <Balances<T> as Currency<_>>::make_free_balance_be(&user, balance_amount);
|
||||
}: set_balance(RawOrigin::Root, user_lookup, 0.into(), 0.into())
|
||||
}
|
||||
@@ -10,6 +10,7 @@ codec = { package = "parity-scale-codec", version = "1.1.2", default-features =
|
||||
sp-api = { version = "2.0.0", path = "../../primitives/api", default-features = false }
|
||||
sp-runtime-interface = { version = "2.0.0", path = "../../primitives/runtime-interface", default-features = false }
|
||||
sp-std = { version = "2.0.0", path = "../../primitives/std", default-features = false }
|
||||
sp-io ={ path = "../../primitives/io", default-features = false }
|
||||
|
||||
[features]
|
||||
default = [ "std" ]
|
||||
|
||||
@@ -14,79 +14,396 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Interfaces and types for benchmarking a FRAME runtime.
|
||||
//! Macro for benchmarking a FRAME runtime.
|
||||
|
||||
#![cfg_attr(not(feature = "std"), no_std)]
|
||||
|
||||
use sp_std::vec::Vec;
|
||||
mod utils;
|
||||
pub use utils::*;
|
||||
|
||||
/// An alphabet of possible parameters to use for benchmarking.
|
||||
#[derive(codec::Encode, codec::Decode, Clone, Copy, PartialEq, Debug)]
|
||||
/// Construct pallet benchmarks for weighing dispatchables.
|
||||
///
|
||||
/// Works around the idea of complexity parameters, named by a single letter (which is usually
|
||||
/// upper cased in complexity notation but is lower-cased for use in this macro).
|
||||
///
|
||||
/// Complexity parameters ("parameters") have a range which is a `u32` pair. Every time a benchmark
|
||||
/// is prepared and run, this parameter takes a concrete value within the range. There is an
|
||||
/// associated instancing block, which is a single expression that is evaluated during
|
||||
/// preparation. It may use `?` (`i.e. `return Err(...)`) to bail with a string error. Here's a
|
||||
/// few examples:
|
||||
///
|
||||
/// ```ignore
|
||||
/// // These two are equivalent:
|
||||
/// let x in 0 .. 10;
|
||||
/// let x in 0 .. 10 => ();
|
||||
/// // This one calls a setup function and might return an error (which would be terminal).
|
||||
/// let y in 0 .. 10 => setup(y)?;
|
||||
/// // This one uses a code block to do lots of stuff:
|
||||
/// let z in 0 .. 10 => {
|
||||
/// let a = z * z / 5;
|
||||
/// let b = do_something(a)?;
|
||||
/// combine_into(z, b);
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// Note that due to parsing restrictions, if the `from` expression is not a single token (i.e. a
|
||||
/// literal or constant), then it must be parenthesised.
|
||||
///
|
||||
/// The macro allows for a number of "arms", each representing an individual benchmark. Using the
|
||||
/// simple syntax, the associated dispatchable function maps 1:1 with the benchmark and the name of
|
||||
/// the benchmark is the same as that of the associated function. However, extended syntax allows
|
||||
/// for arbitrary expresions to be evaluated in a benchmark (including for example,
|
||||
/// `on_initialize`).
|
||||
///
|
||||
/// The macro allows for common parameters whose ranges and instancing expressions may be drawn upon
|
||||
/// (or not) by each arm. Syntax is available to allow for only the range to be drawn upon if
|
||||
/// desired, allowing an alternative instancing expression to be given.
|
||||
///
|
||||
/// Each arm may also have a block of code which is run prior to any instancing and a block of code
|
||||
/// which is run afterwards. All code blocks may draw upon the specific value of each parameter
|
||||
/// at any time. Local variables are shared between the two pre- and post- code blocks, but do not
|
||||
/// leak from the interior of any instancing expressions.
|
||||
///
|
||||
/// Any common parameters that are unused in an arm do not have their instancing expressions
|
||||
/// evaluated.
|
||||
///
|
||||
/// Example:
|
||||
/// ```ignore
|
||||
/// benchmarks! {
|
||||
/// // common parameter; just one for this example.
|
||||
/// _ {
|
||||
/// let l in 1 .. MAX_LENGTH => initialize_l(l);
|
||||
/// }
|
||||
///
|
||||
/// // first dispatchable: foo; this is a user dispatchable and operates on a `u8` vector of
|
||||
/// // size `l`, which we allow to be initialised as usual.
|
||||
/// foo {
|
||||
/// let caller = account::<T>(b"caller", 0, benchmarks_seed);
|
||||
/// let l = ...;
|
||||
/// } _(Origin::Signed(caller), vec![0u8; l])
|
||||
///
|
||||
/// // second dispatchable: bar; this is a root dispatchable and accepts a `u8` vector of size
|
||||
/// // `l`. We don't want it preininitialised like before so we override using the `=> ()`
|
||||
/// // notation.
|
||||
/// // In this case, we explicitly name the call using `bar` instead of `_`.
|
||||
/// bar {
|
||||
/// let l = _ .. _ => ();
|
||||
/// } bar(Origin::Root, vec![0u8; l])
|
||||
///
|
||||
/// // third dispatchable: baz; this is a user dispatchable. It isn't dependent on length like the
|
||||
/// // other two but has its own complexity `c` that needs setting up. It uses `caller` (in the
|
||||
/// // pre-instancing block) within the code block. This is only allowed in the param instancers
|
||||
/// // of arms. Instancers of common params cannot optimistically draw upon hypothetical variables
|
||||
/// // that the arm's pre-instancing code block might have declared.
|
||||
/// baz1 {
|
||||
/// let caller = account::<T>(b"caller", 0, benchmarks_seed);
|
||||
/// let c = 0 .. 10 => setup_c(&caller, c);
|
||||
/// } baz(Origin::Signed(caller))
|
||||
///
|
||||
/// // this is a second benchmark of the baz dispatchable with a different setup.
|
||||
/// baz2 {
|
||||
/// let caller = account::<T>(b"caller", 0, benchmarks_seed);
|
||||
/// let c = 0 .. 10 => setup_c_in_some_other_way(&caller, c);
|
||||
/// } baz(Origin::Signed(caller))
|
||||
///
|
||||
/// // this is benchmarking some code that is not a dispatchable.
|
||||
/// populate_a_set {
|
||||
/// let x in 0 .. 10_000;
|
||||
/// let mut m = Vec::<u32>::new();
|
||||
/// for i in 0..x {
|
||||
/// m.insert(i);
|
||||
/// }
|
||||
/// } { m.into_iter().collect::<BTreeSet>() }
|
||||
/// }
|
||||
/// ```
|
||||
#[macro_export]
|
||||
macro_rules! benchmarks {
|
||||
(
|
||||
_ {
|
||||
$(
|
||||
let $common:ident in $common_from:tt .. $common_to:expr => $common_instancer:expr;
|
||||
)*
|
||||
}
|
||||
$( $rest:tt )*
|
||||
) => {
|
||||
$crate::benchmarks_iter!({
|
||||
$( { $common , $common_from , $common_to , $common_instancer } )*
|
||||
} ( ) $( $rest )* );
|
||||
}
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! impl_benchmark {
|
||||
(
|
||||
$( $name:ident ),*
|
||||
) => {
|
||||
impl<T: Trait> $crate::Benchmarking<$crate::BenchmarkResults> for Module<T> {
|
||||
fn run_benchmark(extrinsic: Vec<u8>, steps: u32, repeat: u32) -> Result<Vec<$crate::BenchmarkResults>, &'static str> {
|
||||
// Map the input to the selected benchmark.
|
||||
let extrinsic = sp_std::str::from_utf8(extrinsic.as_slice())
|
||||
.map_err(|_| "Could not find extrinsic")?;
|
||||
let selected_benchmark = match extrinsic {
|
||||
$( stringify!($name) => SelectedBenchmark::$name, )*
|
||||
_ => return Err("Could not find extrinsic."),
|
||||
};
|
||||
|
||||
// Warm up the DB
|
||||
$crate::benchmarking::commit_db();
|
||||
$crate::benchmarking::wipe_db();
|
||||
|
||||
// first one is set_identity.
|
||||
let components = <SelectedBenchmark as $crate::BenchmarkingSetup<T, crate::Call<T>, RawOrigin<T::AccountId>>>::components(&selected_benchmark);
|
||||
// results go here
|
||||
let mut results: Vec<$crate::BenchmarkResults> = Vec::new();
|
||||
// Select the component we will be benchmarking. Each component will be benchmarked.
|
||||
for (name, low, high) in components.iter() {
|
||||
// Create up to `STEPS` steps for that component between high and low.
|
||||
let step_size = ((high - low) / steps).max(1);
|
||||
let num_of_steps = (high - low) / step_size;
|
||||
for s in 0..num_of_steps {
|
||||
// This is the value we will be testing for component `name`
|
||||
let component_value = low + step_size * s;
|
||||
|
||||
// Select the mid value for all the other components.
|
||||
let c: Vec<($crate::BenchmarkParameter, u32)> = components.iter()
|
||||
.map(|(n, l, h)|
|
||||
(*n, if n == name { component_value } else { (h - l) / 2 + l })
|
||||
).collect();
|
||||
|
||||
// Run the benchmark `repeat` times.
|
||||
for _ in 0..repeat {
|
||||
// Set up the externalities environment for the setup we want to benchmark.
|
||||
let (call, caller) = <SelectedBenchmark as $crate::BenchmarkingSetup<T, crate::Call<T>, RawOrigin<T::AccountId>>>::instance(&selected_benchmark, &c)?;
|
||||
// Commit the externalities to the database, flushing the DB cache.
|
||||
// This will enable worst case scenario for reading from the database.
|
||||
$crate::benchmarking::commit_db();
|
||||
// Run the benchmark.
|
||||
let start = $crate::benchmarking::current_time();
|
||||
call.dispatch(caller.into())?;
|
||||
let finish = $crate::benchmarking::current_time();
|
||||
let elapsed = finish - start;
|
||||
results.push((c.clone(), elapsed));
|
||||
// Wipe the DB back to the genesis state.
|
||||
$crate::benchmarking::wipe_db();
|
||||
}
|
||||
}
|
||||
}
|
||||
return Ok(results);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
#[allow(missing_docs)]
|
||||
pub enum BenchmarkParameter {
|
||||
A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z,
|
||||
}
|
||||
|
||||
/// Results from running benchmarks on a FRAME pallet.
|
||||
/// Contains duration of the function call in nanoseconds along with the benchmark parameters
|
||||
/// used for that benchmark result.
|
||||
pub type BenchmarkResults = (Vec<(BenchmarkParameter, u32)>, u128);
|
||||
|
||||
sp_api::decl_runtime_apis! {
|
||||
/// Runtime api for benchmarking a FRAME runtime.
|
||||
pub trait Benchmark {
|
||||
/// Dispatch the given benchmark.
|
||||
fn dispatch_benchmark(
|
||||
module: Vec<u8>,
|
||||
extrinsic: Vec<u8>,
|
||||
steps: u32,
|
||||
repeat: u32,
|
||||
) -> Option<Vec<BenchmarkResults>>;
|
||||
macro_rules! benchmarks_iter {
|
||||
// mutation arm:
|
||||
(
|
||||
{ $( $common:tt )* }
|
||||
( $( $names:ident )* )
|
||||
$name:ident { $( $code:tt )* }: _ ( $origin:expr $( , $arg:expr )* )
|
||||
$( $rest:tt )*
|
||||
) => {
|
||||
$crate::benchmarks_iter! {
|
||||
{ $( $common )* } ( $( $names )* ) $name { $( $code )* }: $name ( $origin $( , $arg )* ) $( $rest )*
|
||||
}
|
||||
};
|
||||
// mutation arm:
|
||||
(
|
||||
{ $( $common:tt )* }
|
||||
( $( $names:ident )* )
|
||||
$name:ident { $( $code:tt )* }: $dispatch:ident ( $origin:expr $( , $arg:expr )* )
|
||||
$( $rest:tt )*
|
||||
) => {
|
||||
$crate::benchmarks_iter! {
|
||||
{ $( $common )* } ( $( $names )* ) $name { $( $code )* }: { Ok((crate::Call::<T>::$dispatch($($arg),*), $origin)) } $( $rest )*
|
||||
}
|
||||
};
|
||||
// iteration arm:
|
||||
(
|
||||
{ $( $common:tt )* }
|
||||
( $( $names:ident )* )
|
||||
$name:ident { $( $code:tt )* }: { $eval:expr }
|
||||
$( $rest:tt )*
|
||||
) => {
|
||||
$crate::benchmark_backend! {
|
||||
$name { $( $common )* } { } { $eval } { $( $code )* }
|
||||
}
|
||||
$crate::benchmarks_iter!( { $( $common )* } ( $( $names )* $name ) $( $rest )* );
|
||||
};
|
||||
// iteration-exit arm
|
||||
( { $( $common:tt )* } ( $( $names:ident )* ) ) => {
|
||||
$crate::selected_benchmark!( $( $names ),* );
|
||||
$crate::impl_benchmark!( $( $names ),* );
|
||||
}
|
||||
}
|
||||
|
||||
/// Interface that provides functions for benchmarking the runtime.
|
||||
#[sp_runtime_interface::runtime_interface]
|
||||
pub trait Benchmarking {
|
||||
/// Get the number of nanoseconds passed since the UNIX epoch
|
||||
///
|
||||
/// WARNING! This is a non-deterministic call. Do not use this within
|
||||
/// consensus critical logic.
|
||||
fn current_time() -> u128 {
|
||||
std::time::SystemTime::now().duration_since(std::time::SystemTime::UNIX_EPOCH)
|
||||
.expect("Unix time doesn't go backwards; qed")
|
||||
.as_nanos()
|
||||
#[macro_export]
|
||||
#[allow(missing_docs)]
|
||||
macro_rules! benchmark_backend {
|
||||
// parsing arms
|
||||
($name:ident {
|
||||
$( $common:tt )*
|
||||
} {
|
||||
$( PRE { $( $pre_parsed:tt )* } )*
|
||||
} { $eval:expr } {
|
||||
let $pre_id:tt : $pre_ty:ty = $pre_ex:expr;
|
||||
$( $rest:tt )*
|
||||
} ) => {
|
||||
$crate::benchmark_backend! {
|
||||
$name { $( $common )* } {
|
||||
$( PRE { $( $pre_parsed )* } )*
|
||||
PRE { $pre_id , $pre_ty , $pre_ex }
|
||||
} { $eval } { $( $rest )* }
|
||||
}
|
||||
};
|
||||
($name:ident {
|
||||
$( $common:tt )*
|
||||
} {
|
||||
$( $parsed:tt )*
|
||||
} { $eval:expr } {
|
||||
let $param:ident in ( $param_from:expr ) .. $param_to:expr => $param_instancer:expr;
|
||||
$( $rest:tt )*
|
||||
}) => {
|
||||
$crate::benchmark_backend! {
|
||||
$name { $( $common )* } {
|
||||
$( $parsed )*
|
||||
PARAM { $param , $param_from , $param_to , $param_instancer }
|
||||
} { $eval } { $( $rest )* }
|
||||
}
|
||||
};
|
||||
// mutation arm to look after defaulting to a common param
|
||||
($name:ident {
|
||||
$( { $common:ident , $common_from:tt , $common_to:expr , $common_instancer:expr } )*
|
||||
} {
|
||||
$( $parsed:tt )*
|
||||
} { $eval:expr } {
|
||||
let $param:ident in ...;
|
||||
$( $rest:tt )*
|
||||
}) => {
|
||||
$crate::benchmark_backend! {
|
||||
$name {
|
||||
$( { $common , $common_from , $common_to , $common_instancer } )*
|
||||
} {
|
||||
$( $parsed )*
|
||||
} { $eval } {
|
||||
let $param
|
||||
in ({ $( let $common = $common_from; )* $param })
|
||||
.. ({ $( let $common = $common_to; )* $param })
|
||||
=> ({ $( let $common = || -> Result<(), &'static str> { $common_instancer ; Ok(()) }; )* $param()? });
|
||||
$( $rest )*
|
||||
}
|
||||
}
|
||||
};
|
||||
// mutation arm to look after defaulting only the range to common param
|
||||
($name:ident {
|
||||
$( { $common:ident , $common_from:tt , $common_to:expr , $common_instancer:expr } )*
|
||||
} {
|
||||
$( $parsed:tt )*
|
||||
} { $eval:expr } {
|
||||
let $param:ident in _ .. _ => $param_instancer:expr ;
|
||||
$( $rest:tt )*
|
||||
}) => {
|
||||
$crate::benchmark_backend! {
|
||||
$name {
|
||||
$( { $common , $common_from , $common_to , $common_instancer } )*
|
||||
} {
|
||||
$( $parsed )*
|
||||
} { $eval } {
|
||||
let $param
|
||||
in ({ $( let $common = $common_from; )* $param })
|
||||
.. ({ $( let $common = $common_to; )* $param })
|
||||
=> $param_instancer ;
|
||||
$( $rest )*
|
||||
}
|
||||
}
|
||||
};
|
||||
// mutation arm to look after a single tt for param_from.
|
||||
($name:ident {
|
||||
$( $common:tt )*
|
||||
} {
|
||||
$( $parsed:tt )*
|
||||
} { $eval:expr } {
|
||||
let $param:ident in $param_from:tt .. $param_to:expr => $param_instancer:expr ;
|
||||
$( $rest:tt )*
|
||||
}) => {
|
||||
$crate::benchmark_backend! {
|
||||
$name { $( $common )* } { $( $parsed )* } { $eval } {
|
||||
let $param in ( $param_from ) .. $param_to => $param_instancer;
|
||||
$( $rest )*
|
||||
}
|
||||
}
|
||||
};
|
||||
// mutation arm to look after the default tail of `=> ()`
|
||||
($name:ident {
|
||||
$( $common:tt )*
|
||||
} {
|
||||
$( $parsed:tt )*
|
||||
} { $eval:expr } {
|
||||
let $param:ident in $param_from:tt .. $param_to:expr;
|
||||
$( $rest:tt )*
|
||||
}) => {
|
||||
$crate::benchmark_backend! {
|
||||
$name { $( $common )* } { $( $parsed )* } { $eval } {
|
||||
let $param in $param_from .. $param_to => ();
|
||||
$( $rest )*
|
||||
}
|
||||
}
|
||||
};
|
||||
// mutation arm to look after `let _ =`
|
||||
($name:ident {
|
||||
$( $common:tt )*
|
||||
} {
|
||||
$( $parsed:tt )*
|
||||
} { $eval:expr } {
|
||||
let $pre_id:tt = $pre_ex:expr;
|
||||
$( $rest:tt )*
|
||||
}) => {
|
||||
$crate::benchmark_backend! {
|
||||
$name { $( $common )* } { $( $parsed )* } { $eval } {
|
||||
let $pre_id : _ = $pre_ex;
|
||||
$( $rest )*
|
||||
}
|
||||
}
|
||||
};
|
||||
// actioning arm
|
||||
($name:ident {
|
||||
$( { $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 } )*
|
||||
} { $eval:expr } { $( $post:tt )* } ) => {
|
||||
#[allow(non_camel_case_types)]
|
||||
struct $name;
|
||||
#[allow(unused_variables)]
|
||||
impl<T: Trait> $crate::BenchmarkingSetup<T, crate::Call<T>, RawOrigin<T::AccountId>> for $name {
|
||||
fn components(&self) -> Vec<($crate::BenchmarkParameter, u32, u32)> {
|
||||
vec! [
|
||||
$(
|
||||
($crate::BenchmarkParameter::$param, $param_from, $param_to)
|
||||
),*
|
||||
]
|
||||
}
|
||||
|
||||
fn instance(&self, components: &[($crate::BenchmarkParameter, u32)])
|
||||
-> Result<(crate::Call<T>, RawOrigin<T::AccountId>), &'static str>
|
||||
{
|
||||
$(
|
||||
let $common = $common_from;
|
||||
)*
|
||||
$(
|
||||
// Prepare instance
|
||||
let $param = components.iter().find(|&c| c.0 == $crate::BenchmarkParameter::$param).unwrap().1;
|
||||
)*
|
||||
$(
|
||||
let $pre_id : $pre_ty = $pre_ex;
|
||||
)*
|
||||
$( $param_instancer ; )*
|
||||
$( $post )*
|
||||
$eval
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Reset the trie database to the genesis state.
|
||||
fn wipe_db(&mut self) {
|
||||
self.wipe()
|
||||
}
|
||||
|
||||
/// Commit pending storage changes to the trie database and clear the database cache.
|
||||
fn commit_db(&mut self) {
|
||||
self.commit()
|
||||
}
|
||||
}
|
||||
|
||||
/// The pallet benchmarking trait.
|
||||
pub trait Benchmarking<T> {
|
||||
/// Run the benchmarks for this pallet.
|
||||
///
|
||||
/// Parameters
|
||||
/// - `extrinsic`: The name of extrinsic function you want to benchmark encoded as bytes.
|
||||
/// - `steps`: The number of sample points you want to take across the range of parameters.
|
||||
/// - `repeat`: The number of times you want to repeat a benchmark.
|
||||
fn run_benchmark(extrinsic: Vec<u8>, steps: u32, repeat: u32) -> Result<Vec<T>, &'static str>;
|
||||
}
|
||||
|
||||
/// The required setup for creating a benchmark.
|
||||
pub trait BenchmarkingSetup<T, Call, RawOrigin> {
|
||||
/// Return the components and their ranges which should be tested in this benchmark.
|
||||
fn components(&self) -> Vec<(BenchmarkParameter, u32, u32)>;
|
||||
|
||||
/// Set up the storage, and prepare a call and caller to test in a single run of the benchmark.
|
||||
fn instance(&self, components: &[(BenchmarkParameter, u32)]) -> Result<(Call, RawOrigin), &'static str>;
|
||||
}
|
||||
|
||||
/// Creates a `SelectedBenchmark` enum implementing `BenchmarkingSetup`.
|
||||
@@ -109,6 +426,7 @@ macro_rules! selected_benchmark {
|
||||
$( $bench:ident ),*
|
||||
) => {
|
||||
// The list of available benchmarks for this pallet.
|
||||
#[allow(non_camel_case_types)]
|
||||
enum SelectedBenchmark {
|
||||
$( $bench, )*
|
||||
}
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
// 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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Interfaces, types and utils for benchmarking a FRAME runtime.
|
||||
|
||||
use codec::{Encode, Decode};
|
||||
use sp_std::vec::Vec;
|
||||
use sp_io::hashing::blake2_256;
|
||||
|
||||
/// An alphabet of possible parameters to use for benchmarking.
|
||||
#[derive(codec::Encode, codec::Decode, Clone, Copy, PartialEq, Debug)]
|
||||
#[allow(missing_docs)]
|
||||
#[allow(non_camel_case_types)]
|
||||
pub enum BenchmarkParameter {
|
||||
a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z,
|
||||
}
|
||||
|
||||
/// Results from running benchmarks on a FRAME pallet.
|
||||
/// Contains duration of the function call in nanoseconds along with the benchmark parameters
|
||||
/// used for that benchmark result.
|
||||
pub type BenchmarkResults = (Vec<(BenchmarkParameter, u32)>, u128);
|
||||
|
||||
sp_api::decl_runtime_apis! {
|
||||
/// Runtime api for benchmarking a FRAME runtime.
|
||||
pub trait Benchmark {
|
||||
/// Dispatch the given benchmark.
|
||||
fn dispatch_benchmark(
|
||||
module: Vec<u8>,
|
||||
extrinsic: Vec<u8>,
|
||||
steps: u32,
|
||||
repeat: u32,
|
||||
) -> Option<Vec<BenchmarkResults>>;
|
||||
}
|
||||
}
|
||||
|
||||
/// Interface that provides functions for benchmarking the runtime.
|
||||
#[sp_runtime_interface::runtime_interface]
|
||||
pub trait Benchmarking {
|
||||
/// Get the number of nanoseconds passed since the UNIX epoch
|
||||
///
|
||||
/// WARNING! This is a non-deterministic call. Do not use this within
|
||||
/// consensus critical logic.
|
||||
fn current_time() -> u128 {
|
||||
std::time::SystemTime::now().duration_since(std::time::SystemTime::UNIX_EPOCH)
|
||||
.expect("Unix time doesn't go backwards; qed")
|
||||
.as_nanos()
|
||||
}
|
||||
|
||||
/// Reset the trie database to the genesis state.
|
||||
fn wipe_db(&mut self) {
|
||||
self.wipe()
|
||||
}
|
||||
|
||||
/// Commit pending storage changes to the trie database and clear the database cache.
|
||||
fn commit_db(&mut self) {
|
||||
self.commit()
|
||||
}
|
||||
}
|
||||
|
||||
/// The pallet benchmarking trait.
|
||||
pub trait Benchmarking<T> {
|
||||
/// Run the benchmarks for this pallet.
|
||||
///
|
||||
/// Parameters
|
||||
/// - `extrinsic`: The name of extrinsic function you want to benchmark encoded as bytes.
|
||||
/// - `steps`: The number of sample points you want to take across the range of parameters.
|
||||
/// - `repeat`: The number of times you want to repeat a benchmark.
|
||||
fn run_benchmark(extrinsic: Vec<u8>, steps: u32, repeat: u32) -> Result<Vec<T>, &'static str>;
|
||||
}
|
||||
|
||||
/// The required setup for creating a benchmark.
|
||||
pub trait BenchmarkingSetup<T, Call, RawOrigin> {
|
||||
/// Return the components and their ranges which should be tested in this benchmark.
|
||||
fn components(&self) -> Vec<(BenchmarkParameter, u32, u32)>;
|
||||
|
||||
/// Set up the storage, and prepare a call and caller to test in a single run of the benchmark.
|
||||
fn instance(&self, components: &[(BenchmarkParameter, u32)]) -> Result<(Call, RawOrigin), &'static str>;
|
||||
}
|
||||
|
||||
/// Grab an account, seeded by a name and index.
|
||||
pub fn account<AccountId: Decode + Default>(name: &'static str, index: u32, seed: u32) -> AccountId {
|
||||
let entropy = (name, index, seed).using_encoded(blake2_256);
|
||||
AccountId::decode(&mut &entropy[..]).unwrap_or_default()
|
||||
}
|
||||
@@ -20,10 +20,7 @@ use super::*;
|
||||
|
||||
use frame_system::RawOrigin;
|
||||
use sp_io::hashing::blake2_256;
|
||||
use frame_benchmarking::{
|
||||
BenchmarkResults, BenchmarkParameter, selected_benchmark, benchmarking, Benchmarking,
|
||||
BenchmarkingSetup,
|
||||
};
|
||||
use frame_benchmarking::benchmarks;
|
||||
use sp_runtime::traits::{Bounded, Dispatchable};
|
||||
|
||||
use crate::Module as Identity;
|
||||
@@ -90,150 +87,89 @@ fn create_identity_info<T: Trait>(num_fields: u32) -> IdentityInfo {
|
||||
return info
|
||||
}
|
||||
|
||||
// Benchmark `add_registrar` extrinsic.
|
||||
struct AddRegistrar;
|
||||
impl<T: Trait> BenchmarkingSetup<T, crate::Call<T>, RawOrigin<T::AccountId>> for AddRegistrar {
|
||||
fn components(&self) -> Vec<(BenchmarkParameter, u32, u32)> {
|
||||
vec![
|
||||
// Registrar Count
|
||||
(BenchmarkParameter::R, 1, MAX_REGISTRARS),
|
||||
]
|
||||
benchmarks! {
|
||||
// These are the common parameters along with their instancing.
|
||||
_ {
|
||||
let r in 1 .. MAX_REGISTRARS => add_registrars::<T>(r)?;
|
||||
let s in 1 .. T::MaxSubAccounts::get() => {
|
||||
// Give them s many sub accounts
|
||||
let caller = account::<T>("caller", 0);
|
||||
let _ = add_sub_accounts::<T>(caller, s)?;
|
||||
};
|
||||
let x in 1 .. T::MaxAdditionalFields::get() => {
|
||||
// Create their main identity with x additional fields
|
||||
let info = create_identity_info::<T>(x);
|
||||
let caller = account::<T>("caller", 0);
|
||||
let caller_origin = <T as frame_system::Trait>::Origin::from(RawOrigin::Signed(caller));
|
||||
Identity::<T>::set_identity(caller_origin, info)?;
|
||||
};
|
||||
}
|
||||
|
||||
fn instance(&self, components: &[(BenchmarkParameter, u32)])
|
||||
-> Result<(crate::Call<T>, RawOrigin<T::AccountId>), &'static str>
|
||||
{
|
||||
// Add r registrars
|
||||
let r = components.iter().find(|&c| c.0 == BenchmarkParameter::R).unwrap().1;
|
||||
add_registrars::<T>(r)?;
|
||||
add_registrar {
|
||||
let r in ...;
|
||||
}: _(RawOrigin::Root, account::<T>("registrar", r + 1))
|
||||
|
||||
// Return the `add_registrar` r + 1 call
|
||||
Ok((crate::Call::<T>::add_registrar(account::<T>("registrar", r + 1)), RawOrigin::Root))
|
||||
}
|
||||
}
|
||||
set_identity {
|
||||
let r in ...;
|
||||
// This X doesn't affect the caller ID up front like with the others, so we don't use the
|
||||
// standard preparation.
|
||||
let x in _ .. _ => ();
|
||||
let caller = {
|
||||
// The target user
|
||||
let caller = account::<T>("caller", 0);
|
||||
let caller_lookup: <T::Lookup as StaticLookup>::Source = T::Lookup::unlookup(caller.clone());
|
||||
let caller_origin: <T as frame_system::Trait>::Origin = RawOrigin::Signed(caller.clone()).into();
|
||||
let _ = T::Currency::make_free_balance_be(&caller, BalanceOf::<T>::max_value());
|
||||
|
||||
// Benchmark `set_identity` extrinsic.
|
||||
struct SetIdentity;
|
||||
impl<T: Trait> BenchmarkingSetup<T, crate::Call<T>, RawOrigin<T::AccountId>> for SetIdentity {
|
||||
fn components(&self) -> Vec<(BenchmarkParameter, u32, u32)> {
|
||||
vec![
|
||||
// Registrar Count
|
||||
(BenchmarkParameter::R, 1, MAX_REGISTRARS),
|
||||
// Additional Field Count
|
||||
(BenchmarkParameter::X, 1, T::MaxAdditionalFields::get())
|
||||
]
|
||||
}
|
||||
// Add an initial identity
|
||||
let initial_info = create_identity_info::<T>(1);
|
||||
Identity::<T>::set_identity(caller_origin.clone(), initial_info)?;
|
||||
|
||||
fn instance(&self, components: &[(BenchmarkParameter, u32)])
|
||||
-> Result<(crate::Call<T>, RawOrigin<T::AccountId>), &'static str>
|
||||
{
|
||||
// Add r registrars
|
||||
let r = components.iter().find(|&c| c.0 == BenchmarkParameter::R).unwrap().1;
|
||||
add_registrars::<T>(r)?;
|
||||
// User requests judgement from all the registrars, and they approve
|
||||
for i in 0..r {
|
||||
Identity::<T>::request_judgement(caller_origin.clone(), i, 10.into())?;
|
||||
Identity::<T>::provide_judgement(
|
||||
RawOrigin::Signed(account::<T>("registrar", i)).into(),
|
||||
i,
|
||||
caller_lookup.clone(),
|
||||
Judgement::Reasonable
|
||||
)?;
|
||||
}
|
||||
caller
|
||||
};
|
||||
}: _(
|
||||
RawOrigin::Signed(caller),
|
||||
create_identity_info::<T>(x)
|
||||
)
|
||||
|
||||
// The target user
|
||||
let caller = account::<T>("caller", r);
|
||||
let caller_lookup: <T::Lookup as StaticLookup>::Source = T::Lookup::unlookup(caller.clone());
|
||||
let caller_origin: <T as frame_system::Trait>::Origin = RawOrigin::Signed(caller.clone()).into();
|
||||
let _ = T::Currency::make_free_balance_be(&caller, BalanceOf::<T>::max_value());
|
||||
set_subs {
|
||||
let s in ...;
|
||||
|
||||
// Add an initial identity
|
||||
let initial_info = create_identity_info::<T>(1);
|
||||
Identity::<T>::set_identity(caller_origin.clone(), initial_info)?;
|
||||
|
||||
// User requests judgement from all the registrars, and they approve
|
||||
for i in 0..r {
|
||||
Identity::<T>::request_judgement(caller_origin.clone(), i, 10.into())?;
|
||||
Identity::<T>::provide_judgement(
|
||||
RawOrigin::Signed(account::<T>("registrar", i)).into(),
|
||||
i,
|
||||
caller_lookup.clone(),
|
||||
Judgement::Reasonable
|
||||
)?;
|
||||
}
|
||||
|
||||
// Create identity info with x additional fields
|
||||
let x = components.iter().find(|&c| c.0 == BenchmarkParameter::X).unwrap().1;
|
||||
// 32 byte data that we reuse below
|
||||
let info = create_identity_info::<T>(x);
|
||||
|
||||
// Return the `set_identity` call
|
||||
Ok((crate::Call::<T>::set_identity(info), RawOrigin::Signed(caller)))
|
||||
}
|
||||
}
|
||||
|
||||
// Benchmark `set_subs` extrinsic.
|
||||
struct SetSubs;
|
||||
impl<T: Trait> BenchmarkingSetup<T, crate::Call<T>, RawOrigin<T::AccountId>> for SetSubs {
|
||||
fn components(&self) -> Vec<(BenchmarkParameter, u32, u32)> {
|
||||
vec![
|
||||
// Subs Count
|
||||
(BenchmarkParameter::S, 1, T::MaxSubAccounts::get()),
|
||||
]
|
||||
}
|
||||
|
||||
fn instance(&self, components: &[(BenchmarkParameter, u32)])
|
||||
-> Result<(crate::Call<T>, RawOrigin<T::AccountId>), &'static str>
|
||||
{
|
||||
// Generic data to be used.
|
||||
let data = Data::Raw(vec![0; 32]);
|
||||
|
||||
// The target user
|
||||
let caller = account::<T>("caller", 0);
|
||||
let caller_origin: <T as frame_system::Trait>::Origin = RawOrigin::Signed(caller.clone()).into();
|
||||
let _ = T::Currency::make_free_balance_be(&caller, BalanceOf::<T>::max_value());
|
||||
|
||||
// Create their main identity
|
||||
let info = create_identity_info::<T>(1);
|
||||
Identity::<T>::set_identity(caller_origin.clone(), info)?;
|
||||
|
||||
// Give them s many sub accounts
|
||||
let s = components.iter().find(|&c| c.0 == BenchmarkParameter::S).unwrap().1;
|
||||
let mut subs = add_sub_accounts::<T>(caller.clone(), s)?;
|
||||
|
||||
Identity::<T>::set_identity(caller_origin, info)?;
|
||||
}: _(RawOrigin::Signed(caller), {
|
||||
let mut subs = Module::<T>::subs(&caller);
|
||||
// Generic data to be used.
|
||||
let data = Data::Raw(vec![0; 32]);
|
||||
// Create an s+1 sub account to add
|
||||
subs.push((account::<T>("sub", s+1), data));
|
||||
subs.push((account::<T>("sub", s + 1), data));
|
||||
subs
|
||||
})
|
||||
|
||||
// Return the `set_subs` call
|
||||
Ok((crate::Call::<T>::set_subs(subs), RawOrigin::Signed(caller)))
|
||||
}
|
||||
}
|
||||
|
||||
// Benchmark `clear_identity` extrinsic.
|
||||
struct ClearIdentity;
|
||||
impl<T: Trait> BenchmarkingSetup<T, crate::Call<T>, RawOrigin<T::AccountId>> for ClearIdentity {
|
||||
fn components(&self) -> Vec<(BenchmarkParameter, u32, u32)> {
|
||||
vec![
|
||||
// Registrar Count
|
||||
(BenchmarkParameter::R, 1, MAX_REGISTRARS),
|
||||
// Subs Count
|
||||
(BenchmarkParameter::S, 1, T::MaxSubAccounts::get()),
|
||||
// Additional Field Count
|
||||
(BenchmarkParameter::X, 1, T::MaxAdditionalFields::get()),
|
||||
]
|
||||
}
|
||||
|
||||
fn instance(&self, components: &[(BenchmarkParameter, u32)])
|
||||
-> Result<(crate::Call<T>, RawOrigin<T::AccountId>), &'static str>
|
||||
{
|
||||
// The target user
|
||||
clear_identity {
|
||||
let caller = account::<T>("caller", 0);
|
||||
let caller_origin: <T as frame_system::Trait>::Origin = RawOrigin::Signed(caller.clone()).into();
|
||||
let caller_lookup: <T::Lookup as StaticLookup>::Source = T::Lookup::unlookup(caller.clone());
|
||||
let caller_origin = <T as frame_system::Trait>::Origin::from(RawOrigin::Signed(caller.clone()));
|
||||
let caller_lookup = <T::Lookup as StaticLookup>::unlookup(caller.clone());
|
||||
let _ = T::Currency::make_free_balance_be(&caller, BalanceOf::<T>::max_value());
|
||||
|
||||
// Register r registrars
|
||||
let r = components.iter().find(|&c| c.0 == BenchmarkParameter::R).unwrap().1;
|
||||
add_registrars::<T>(r)?;
|
||||
|
||||
// Create their main identity with x additional fields
|
||||
let x = components.iter().find(|&c| c.0 == BenchmarkParameter::X).unwrap().1;
|
||||
let info = create_identity_info::<T>(x);
|
||||
Identity::<T>::set_identity(caller_origin.clone(), info)?;
|
||||
|
||||
// Give them s many sub accounts
|
||||
let s = components.iter().find(|&c| c.0 == BenchmarkParameter::S).unwrap().1;
|
||||
let _ = add_sub_accounts::<T>(caller.clone(), s)?;
|
||||
let r in ...;
|
||||
let s in ...;
|
||||
let x in ...;
|
||||
|
||||
// User requests judgement from all the registrars, and they approve
|
||||
for i in 0..r {
|
||||
@@ -245,260 +181,87 @@ impl<T: Trait> BenchmarkingSetup<T, crate::Call<T>, RawOrigin<T::AccountId>> for
|
||||
Judgement::Reasonable
|
||||
)?;
|
||||
}
|
||||
}: _(RawOrigin::Signed(caller))
|
||||
|
||||
// Return the `clear_identity` call
|
||||
Ok((crate::Call::<T>::clear_identity(), RawOrigin::Signed(caller)))
|
||||
}
|
||||
}
|
||||
|
||||
// Benchmark `request_judgement` extrinsic.
|
||||
struct RequestJudgement;
|
||||
impl<T: Trait> BenchmarkingSetup<T, crate::Call<T>, RawOrigin<T::AccountId>> for RequestJudgement {
|
||||
fn components(&self) -> Vec<(BenchmarkParameter, u32, u32)> {
|
||||
vec![
|
||||
// Registrar Count
|
||||
(BenchmarkParameter::R, 1, MAX_REGISTRARS),
|
||||
// Additional Field Count
|
||||
(BenchmarkParameter::X, 1, T::MaxAdditionalFields::get()),
|
||||
]
|
||||
}
|
||||
|
||||
fn instance(&self, components: &[(BenchmarkParameter, u32)])
|
||||
-> Result<(crate::Call<T>, RawOrigin<T::AccountId>), &'static str>
|
||||
{
|
||||
// The target user
|
||||
let caller = account::<T>("caller", 0);
|
||||
let caller_origin: <T as frame_system::Trait>::Origin = RawOrigin::Signed(caller.clone()).into();
|
||||
let _ = T::Currency::make_free_balance_be(&caller, BalanceOf::<T>::max_value());
|
||||
|
||||
// Register r registrars
|
||||
let r = components.iter().find(|&c| c.0 == BenchmarkParameter::R).unwrap().1;
|
||||
add_registrars::<T>(r)?;
|
||||
|
||||
// Create their main identity with x additional fields
|
||||
let x = components.iter().find(|&c| c.0 == BenchmarkParameter::X).unwrap().1;
|
||||
let info = create_identity_info::<T>(x);
|
||||
Identity::<T>::set_identity(caller_origin.clone(), info)?;
|
||||
|
||||
// Return the `request_judgement` call
|
||||
Ok((crate::Call::<T>::request_judgement(r-1, 10.into()), RawOrigin::Signed(caller)))
|
||||
}
|
||||
}
|
||||
|
||||
// Benchmark `cancel_request` extrinsic.
|
||||
struct CancelRequest;
|
||||
impl<T: Trait> BenchmarkingSetup<T, crate::Call<T>, RawOrigin<T::AccountId>> for CancelRequest {
|
||||
fn components(&self) -> Vec<(BenchmarkParameter, u32, u32)> {
|
||||
vec![
|
||||
// Registrar Count
|
||||
(BenchmarkParameter::R, 1, MAX_REGISTRARS),
|
||||
// Additional Field Count
|
||||
(BenchmarkParameter::X, 1, T::MaxAdditionalFields::get()),
|
||||
]
|
||||
}
|
||||
|
||||
fn instance(&self, components: &[(BenchmarkParameter, u32)])
|
||||
-> Result<(crate::Call<T>, RawOrigin<T::AccountId>), &'static str>
|
||||
{
|
||||
// The target user
|
||||
let caller = account::<T>("caller", 0);
|
||||
let caller_origin: <T as frame_system::Trait>::Origin = RawOrigin::Signed(caller.clone()).into();
|
||||
let _ = T::Currency::make_free_balance_be(&caller, BalanceOf::<T>::max_value());
|
||||
|
||||
// Register r registrars
|
||||
let r = components.iter().find(|&c| c.0 == BenchmarkParameter::R).unwrap().1;
|
||||
add_registrars::<T>(r)?;
|
||||
|
||||
// Create their main identity with x additional fields
|
||||
let x = components.iter().find(|&c| c.0 == BenchmarkParameter::X).unwrap().1;
|
||||
let info = create_identity_info::<T>(x);
|
||||
Identity::<T>::set_identity(caller_origin.clone(), info)?;
|
||||
|
||||
// Request judgement
|
||||
Identity::<T>::request_judgement(caller_origin.clone(), r-1, 10.into())?;
|
||||
|
||||
Ok((crate::Call::<T>::cancel_request(r-1), RawOrigin::Signed(caller)))
|
||||
}
|
||||
}
|
||||
|
||||
// Benchmark `set_fee` extrinsic.
|
||||
struct SetFee;
|
||||
impl<T: Trait> BenchmarkingSetup<T, crate::Call<T>, RawOrigin<T::AccountId>> for SetFee {
|
||||
fn components(&self) -> Vec<(BenchmarkParameter, u32, u32)> {
|
||||
vec![
|
||||
// Registrar Count
|
||||
(BenchmarkParameter::R, 1, MAX_REGISTRARS),
|
||||
]
|
||||
}
|
||||
|
||||
fn instance(&self, components: &[(BenchmarkParameter, u32)])
|
||||
-> Result<(crate::Call<T>, RawOrigin<T::AccountId>), &'static str>
|
||||
{
|
||||
// The target user
|
||||
request_judgement {
|
||||
let caller = account::<T>("caller", 0);
|
||||
let _ = T::Currency::make_free_balance_be(&caller, BalanceOf::<T>::max_value());
|
||||
|
||||
// Register r registrars
|
||||
let r = components.iter().find(|&c| c.0 == BenchmarkParameter::R).unwrap().1;
|
||||
add_registrars::<T>(r)?;
|
||||
let r in ...;
|
||||
let x in ...;
|
||||
}: _(RawOrigin::Signed(caller), r - 1, 10.into())
|
||||
|
||||
cancel_request {
|
||||
let caller = account::<T>("caller", 0);
|
||||
let caller_origin = <T as frame_system::Trait>::Origin::from(RawOrigin::Signed(caller.clone()));
|
||||
let _ = T::Currency::make_free_balance_be(&caller, BalanceOf::<T>::max_value());
|
||||
|
||||
let r in ...;
|
||||
let x in ...;
|
||||
|
||||
Identity::<T>::request_judgement(caller_origin, r - 1, 10.into())?;
|
||||
}: _(RawOrigin::Signed(caller), r - 1)
|
||||
|
||||
set_fee {
|
||||
let caller = account::<T>("caller", 0);
|
||||
|
||||
let r in ...;
|
||||
|
||||
// Add caller as registrar
|
||||
Identity::<T>::add_registrar(RawOrigin::Root.into(), caller.clone())?;
|
||||
}: _(RawOrigin::Signed(caller), r, 10.into())
|
||||
|
||||
// Return `set_fee` call
|
||||
Ok((crate::Call::<T>::set_fee(r, 10.into()), RawOrigin::Signed(caller)))
|
||||
}
|
||||
}
|
||||
|
||||
// Benchmark `set_account_id` extrinsic.
|
||||
struct SetAccountId;
|
||||
impl<T: Trait> BenchmarkingSetup<T, crate::Call<T>, RawOrigin<T::AccountId>> for SetAccountId {
|
||||
fn components(&self) -> Vec<(BenchmarkParameter, u32, u32)> {
|
||||
vec![
|
||||
// Registrar Count
|
||||
(BenchmarkParameter::R, 1, MAX_REGISTRARS),
|
||||
]
|
||||
}
|
||||
|
||||
fn instance(&self, components: &[(BenchmarkParameter, u32)])
|
||||
-> Result<(crate::Call<T>, RawOrigin<T::AccountId>), &'static str>
|
||||
{
|
||||
// The target user
|
||||
set_account_id {
|
||||
let caller = account::<T>("caller", 0);
|
||||
let _ = T::Currency::make_free_balance_be(&caller, BalanceOf::<T>::max_value());
|
||||
|
||||
// Register r registrars
|
||||
let r = components.iter().find(|&c| c.0 == BenchmarkParameter::R).unwrap().1;
|
||||
add_registrars::<T>(r)?;
|
||||
let r in ...;
|
||||
|
||||
// Add caller as registrar
|
||||
Identity::<T>::add_registrar(RawOrigin::Root.into(), caller.clone())?;
|
||||
}: _(RawOrigin::Signed(caller), r, account::<T>("new", 0))
|
||||
|
||||
// Return `set_account_id` call
|
||||
Ok((crate::Call::<T>::set_account_id(r, account::<T>("new", 0)), RawOrigin::Signed(caller)))
|
||||
}
|
||||
}
|
||||
|
||||
// Benchmark `set_fields` extrinsic.
|
||||
struct SetFields;
|
||||
impl<T: Trait> BenchmarkingSetup<T, crate::Call<T>, RawOrigin<T::AccountId>> for SetFields {
|
||||
fn components(&self) -> Vec<(BenchmarkParameter, u32, u32)> {
|
||||
vec![
|
||||
// Registrar Count
|
||||
(BenchmarkParameter::R, 1, MAX_REGISTRARS),
|
||||
]
|
||||
}
|
||||
|
||||
fn instance(&self, components: &[(BenchmarkParameter, u32)])
|
||||
-> Result<(crate::Call<T>, RawOrigin<T::AccountId>), &'static str>
|
||||
{
|
||||
// The target user
|
||||
set_fields {
|
||||
let caller = account::<T>("caller", 0);
|
||||
let _ = T::Currency::make_free_balance_be(&caller, BalanceOf::<T>::max_value());
|
||||
|
||||
// Register r registrars
|
||||
let r = components.iter().find(|&c| c.0 == BenchmarkParameter::R).unwrap().1;
|
||||
add_registrars::<T>(r)?;
|
||||
let r in ...;
|
||||
|
||||
// Add caller as registrar
|
||||
Identity::<T>::add_registrar(RawOrigin::Root.into(), caller.clone())?;
|
||||
|
||||
let fields = IdentityFields(
|
||||
IdentityField::Display | IdentityField::Legal | IdentityField::Web | IdentityField::Riot
|
||||
| IdentityField::Email | IdentityField::PgpFingerprint | IdentityField::Image | IdentityField::Twitter
|
||||
);
|
||||
}: _(RawOrigin::Signed(caller), r, fields)
|
||||
|
||||
// Return `set_account_id` call
|
||||
Ok((crate::Call::<T>::set_fields(r, fields), RawOrigin::Signed(caller)))
|
||||
}
|
||||
}
|
||||
|
||||
// Benchmark `provide_judgement` extrinsic.g
|
||||
struct ProvideJudgement;
|
||||
impl<T: Trait> BenchmarkingSetup<T, crate::Call<T>, RawOrigin<T::AccountId>> for ProvideJudgement {
|
||||
|
||||
fn components(&self) -> Vec<(BenchmarkParameter, u32, u32)> {
|
||||
vec![
|
||||
// Registrar Count
|
||||
(BenchmarkParameter::R, 1, MAX_REGISTRARS),
|
||||
// Additional Field Count
|
||||
(BenchmarkParameter::X, 1, T::MaxAdditionalFields::get()),
|
||||
]
|
||||
}
|
||||
|
||||
fn instance(&self, components: &[(BenchmarkParameter, u32)])
|
||||
-> Result<(crate::Call<T>, RawOrigin<T::AccountId>), &'static str>
|
||||
{
|
||||
// Add r registrars
|
||||
let r = components.iter().find(|&c| c.0 == BenchmarkParameter::R).unwrap().1;
|
||||
add_registrars::<T>(r)?;
|
||||
|
||||
provide_judgement {
|
||||
// The user
|
||||
let user = account::<T>("user", r);
|
||||
let user_origin: <T as frame_system::Trait>::Origin = RawOrigin::Signed(user.clone()).into();
|
||||
let user_lookup: <T::Lookup as StaticLookup>::Source = T::Lookup::unlookup(user.clone());
|
||||
let user_origin = <T as frame_system::Trait>::Origin::from(RawOrigin::Signed(user.clone()));
|
||||
let user_lookup = <T::Lookup as StaticLookup>::unlookup(user.clone());
|
||||
let _ = T::Currency::make_free_balance_be(&user, BalanceOf::<T>::max_value());
|
||||
|
||||
// Create their main identity with x additional fields
|
||||
let x = components.iter().find(|&c| c.0 == BenchmarkParameter::X).unwrap().1;
|
||||
let info = create_identity_info::<T>(x);
|
||||
Identity::<T>::set_identity(user_origin.clone(), info)?;
|
||||
|
||||
// The caller registrar
|
||||
let caller = account::<T>("caller", r);
|
||||
let caller = account::<T>("caller", 0);
|
||||
let _ = T::Currency::make_free_balance_be(&caller, BalanceOf::<T>::max_value());
|
||||
|
||||
// Add caller as registrar
|
||||
let r in ...;
|
||||
// For this x, it's the user identity that gts the fields, not the caller.
|
||||
let x in _ .. _ => {
|
||||
let info = create_identity_info::<T>(x);
|
||||
Identity::<T>::set_identity(user_origin.clone(), info)?;
|
||||
};
|
||||
|
||||
Identity::<T>::add_registrar(RawOrigin::Root.into(), caller.clone())?;
|
||||
|
||||
// User requests judgement from caller registrar
|
||||
Identity::<T>::request_judgement(user_origin.clone(), r, 10.into())?;
|
||||
}: _(RawOrigin::Signed(caller), r, user_lookup, Judgement::Reasonable)
|
||||
|
||||
// Return `provide_judgement` call
|
||||
Ok((crate::Call::<T>::provide_judgement(
|
||||
r,
|
||||
user_lookup.clone(),
|
||||
Judgement::Reasonable
|
||||
), RawOrigin::Signed(caller)))
|
||||
}
|
||||
}
|
||||
|
||||
// Benchmark `kill_identity` extrinsic.
|
||||
struct KillIdentity;
|
||||
impl<T: Trait> BenchmarkingSetup<T, crate::Call<T>, RawOrigin<T::AccountId>> for KillIdentity {
|
||||
|
||||
fn components(&self) -> Vec<(BenchmarkParameter, u32, u32)> {
|
||||
vec![
|
||||
// Registrar Count
|
||||
(BenchmarkParameter::R, 1, MAX_REGISTRARS),
|
||||
// Subs Count
|
||||
(BenchmarkParameter::S, 1, T::MaxSubAccounts::get()),
|
||||
// Additional Field Count
|
||||
(BenchmarkParameter::X, 1, T::MaxAdditionalFields::get()),
|
||||
]
|
||||
}
|
||||
|
||||
fn instance(&self, components: &[(BenchmarkParameter, u32)])
|
||||
-> Result<(crate::Call<T>, RawOrigin<T::AccountId>), &'static str>
|
||||
{
|
||||
// The target user
|
||||
kill_identity {
|
||||
let caller = account::<T>("caller", 0);
|
||||
let caller_origin: <T as frame_system::Trait>::Origin = RawOrigin::Signed(caller.clone()).into();
|
||||
let caller_lookup: <T::Lookup as StaticLookup>::Source = T::Lookup::unlookup(caller.clone());
|
||||
let _ = T::Currency::make_free_balance_be(&caller, BalanceOf::<T>::max_value());
|
||||
|
||||
// Register r registrars
|
||||
let r = components.iter().find(|&c| c.0 == BenchmarkParameter::R).unwrap().1;
|
||||
add_registrars::<T>(r)?;
|
||||
|
||||
// Create their main identity with x additional fields
|
||||
let x = components.iter().find(|&c| c.0 == BenchmarkParameter::X).unwrap().1;
|
||||
let info = create_identity_info::<T>(x);
|
||||
Identity::<T>::set_identity(caller_origin.clone(), info)?;
|
||||
|
||||
// Give them s many sub accounts
|
||||
let s = components.iter().find(|&c| c.0 == BenchmarkParameter::S).unwrap().1;
|
||||
let _ = add_sub_accounts::<T>(caller.clone(), s)?;
|
||||
let r in ...;
|
||||
let s in ...;
|
||||
let x in ...;
|
||||
|
||||
// User requests judgement from all the registrars, and they approve
|
||||
for i in 0..r {
|
||||
@@ -510,86 +273,5 @@ impl<T: Trait> BenchmarkingSetup<T, crate::Call<T>, RawOrigin<T::AccountId>> for
|
||||
Judgement::Reasonable
|
||||
)?;
|
||||
}
|
||||
|
||||
// Return the `kill_identity` call
|
||||
Ok((crate::Call::<T>::kill_identity(caller_lookup), RawOrigin::Root))
|
||||
}
|
||||
}
|
||||
|
||||
// The list of available benchmarks for this pallet.
|
||||
selected_benchmark!(
|
||||
AddRegistrar,
|
||||
SetIdentity,
|
||||
SetSubs,
|
||||
ClearIdentity,
|
||||
RequestJudgement,
|
||||
CancelRequest,
|
||||
SetFee,
|
||||
SetAccountId,
|
||||
SetFields,
|
||||
ProvideJudgement,
|
||||
KillIdentity
|
||||
);
|
||||
|
||||
impl<T: Trait> Benchmarking<BenchmarkResults> for Module<T> {
|
||||
fn run_benchmark(extrinsic: Vec<u8>, steps: u32, repeat: u32) -> Result<Vec<BenchmarkResults>, &'static str> {
|
||||
// Map the input to the selected benchmark.
|
||||
let selected_benchmark = match extrinsic.as_slice() {
|
||||
b"add_registrar" => SelectedBenchmark::AddRegistrar,
|
||||
b"set_identity" => SelectedBenchmark::SetIdentity,
|
||||
b"set_subs" => SelectedBenchmark::SetSubs,
|
||||
b"clear_identity" => SelectedBenchmark::ClearIdentity,
|
||||
b"request_judgement" => SelectedBenchmark::RequestJudgement,
|
||||
b"cancel_request" => SelectedBenchmark::CancelRequest,
|
||||
b"set_fee" => SelectedBenchmark::SetFee,
|
||||
b"set_account_id" => SelectedBenchmark::SetAccountId,
|
||||
b"set_fields" => SelectedBenchmark::SetFields,
|
||||
b"provide_judgement" => SelectedBenchmark::ProvideJudgement,
|
||||
b"kill_identity" => SelectedBenchmark::KillIdentity,
|
||||
_ => return Err("Could not find extrinsic."),
|
||||
};
|
||||
|
||||
// Warm up the DB
|
||||
benchmarking::commit_db();
|
||||
benchmarking::wipe_db();
|
||||
|
||||
// first one is set_identity.
|
||||
let components = <SelectedBenchmark as BenchmarkingSetup<T, crate::Call<T>, RawOrigin<T::AccountId>>>::components(&selected_benchmark);
|
||||
// results go here
|
||||
let mut results: Vec<BenchmarkResults> = Vec::new();
|
||||
// Select the component we will be benchmarking. Each component will be benchmarked.
|
||||
for (name, low, high) in components.iter() {
|
||||
// Create up to `STEPS` steps for that component between high and low.
|
||||
let step_size = ((high - low) / steps).max(1);
|
||||
let num_of_steps = (high - low) / step_size;
|
||||
for s in 0..num_of_steps {
|
||||
// This is the value we will be testing for component `name`
|
||||
let component_value = low + step_size * s;
|
||||
|
||||
// Select the mid value for all the other components.
|
||||
let c: Vec<(BenchmarkParameter, u32)> = components.iter()
|
||||
.map(|(n, l, h)|
|
||||
(*n, if n == name { component_value } else { (h - l) / 2 + l })
|
||||
).collect();
|
||||
|
||||
// Run the benchmark `repeat` times.
|
||||
for _ in 0..repeat {
|
||||
// Set up the externalities environment for the setup we want to benchmark.
|
||||
let (call, caller) = <SelectedBenchmark as BenchmarkingSetup<T, crate::Call<T>, RawOrigin<T::AccountId>>>::instance(&selected_benchmark, &c)?;
|
||||
// Commit the externalities to the database, flushing the DB cache.
|
||||
// This will enable worst case scenario for reading from the database.
|
||||
benchmarking::commit_db();
|
||||
// Run the benchmark.
|
||||
let start = benchmarking::current_time();
|
||||
call.dispatch(caller.into())?;
|
||||
let finish = benchmarking::current_time();
|
||||
let elapsed = finish - start;
|
||||
results.push((c.clone(), elapsed));
|
||||
// Wipe the DB back to the genesis state.
|
||||
benchmarking::wipe_db();
|
||||
}
|
||||
}
|
||||
}
|
||||
return Ok(results);
|
||||
}
|
||||
}: _(RawOrigin::Root, caller_lookup)
|
||||
}
|
||||
|
||||
@@ -394,7 +394,7 @@ decl_storage! {
|
||||
/// Alternative "sub" identities of this account.
|
||||
///
|
||||
/// The first item is the deposit, the second is a vector of the accounts.
|
||||
pub SubsOf get(fn subs):
|
||||
pub SubsOf get(fn subs_of):
|
||||
map hasher(blake2_256) T::AccountId => (BalanceOf<T>, Vec<T::AccountId>);
|
||||
|
||||
/// The set of registrars. Not expected to get very big as can only be added through a
|
||||
@@ -875,6 +875,16 @@ decl_module! {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Trait> Module<T> {
|
||||
/// Get the subs of an account.
|
||||
pub fn subs(who: &T::AccountId) -> Vec<(T::AccountId, Data)> {
|
||||
SubsOf::<T>::get(who).1
|
||||
.into_iter()
|
||||
.filter_map(|a| SuperOf::<T>::get(&a).map(|x| (a, x.1)))
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
@@ -1097,14 +1107,14 @@ mod tests {
|
||||
assert_ok!(Identity::set_identity(Origin::signed(10), ten()));
|
||||
assert_ok!(Identity::set_subs(Origin::signed(10), subs.clone()));
|
||||
assert_eq!(Balances::free_balance(10), 80);
|
||||
assert_eq!(Identity::subs(10), (10, vec![20]));
|
||||
assert_eq!(Identity::subs_of(10), (10, vec![20]));
|
||||
assert_eq!(Identity::super_of(20), Some((10, Data::Raw(vec![40; 1]))));
|
||||
|
||||
// push another item and re-set it.
|
||||
subs.push((30, Data::Raw(vec![50; 1])));
|
||||
assert_ok!(Identity::set_subs(Origin::signed(10), subs.clone()));
|
||||
assert_eq!(Balances::free_balance(10), 70);
|
||||
assert_eq!(Identity::subs(10), (20, vec![20, 30]));
|
||||
assert_eq!(Identity::subs_of(10), (20, vec![20, 30]));
|
||||
assert_eq!(Identity::super_of(20), Some((10, Data::Raw(vec![40; 1]))));
|
||||
assert_eq!(Identity::super_of(30), Some((10, Data::Raw(vec![50; 1]))));
|
||||
|
||||
@@ -1112,7 +1122,7 @@ mod tests {
|
||||
subs[0] = (40, Data::Raw(vec![60; 1]));
|
||||
assert_ok!(Identity::set_subs(Origin::signed(10), subs.clone()));
|
||||
assert_eq!(Balances::free_balance(10), 70); // no change in the balance
|
||||
assert_eq!(Identity::subs(10), (20, vec![40, 30]));
|
||||
assert_eq!(Identity::subs_of(10), (20, vec![40, 30]));
|
||||
assert_eq!(Identity::super_of(20), None);
|
||||
assert_eq!(Identity::super_of(30), Some((10, Data::Raw(vec![50; 1]))));
|
||||
assert_eq!(Identity::super_of(40), Some((10, Data::Raw(vec![60; 1]))));
|
||||
@@ -1120,7 +1130,7 @@ mod tests {
|
||||
// clear
|
||||
assert_ok!(Identity::set_subs(Origin::signed(10), vec![]));
|
||||
assert_eq!(Balances::free_balance(10), 90);
|
||||
assert_eq!(Identity::subs(10), (0, vec![]));
|
||||
assert_eq!(Identity::subs_of(10), (0, vec![]));
|
||||
assert_eq!(Identity::super_of(30), None);
|
||||
assert_eq!(Identity::super_of(40), None);
|
||||
|
||||
|
||||
@@ -21,88 +21,17 @@ use super::*;
|
||||
use sp_std::prelude::*;
|
||||
|
||||
use frame_system::RawOrigin;
|
||||
use frame_benchmarking::{
|
||||
BenchmarkResults, BenchmarkParameter, selected_benchmark, benchmarking,
|
||||
Benchmarking, BenchmarkingSetup,
|
||||
};
|
||||
use frame_benchmarking::benchmarks;
|
||||
use sp_runtime::traits::Dispatchable;
|
||||
|
||||
/// Benchmark `set` extrinsic.
|
||||
struct Set;
|
||||
impl<T: Trait> BenchmarkingSetup<T, Call<T>, RawOrigin<T::AccountId>> for Set {
|
||||
fn components(&self) -> Vec<(BenchmarkParameter, u32, u32)> {
|
||||
vec![
|
||||
// Current time ("Now")
|
||||
(BenchmarkParameter::N, 1, 100),
|
||||
]
|
||||
const MAX_TIME: u32 = 100;
|
||||
|
||||
benchmarks! {
|
||||
_ {
|
||||
let n in 1 .. MAX_TIME => ();
|
||||
}
|
||||
|
||||
fn instance(&self, components: &[(BenchmarkParameter, u32)])
|
||||
-> Result<(Call<T>, RawOrigin<T::AccountId>), &'static str>
|
||||
{
|
||||
let user_origin = RawOrigin::None;
|
||||
let now = components.iter().find(|&c| c.0 == BenchmarkParameter::N).unwrap().1;
|
||||
|
||||
// Return the `set` call
|
||||
Ok((Call::<T>::set(now.into()), user_origin))
|
||||
}
|
||||
}
|
||||
|
||||
selected_benchmark!(Set);
|
||||
|
||||
impl<T: Trait> Benchmarking<BenchmarkResults> for Module<T> {
|
||||
fn run_benchmark(extrinsic: Vec<u8>, steps: u32, repeat: u32) -> Result<Vec<BenchmarkResults>, &'static str> {
|
||||
// Map the input to the selected benchmark.
|
||||
let selected_benchmark = match extrinsic.as_slice() {
|
||||
b"set" => SelectedBenchmark::Set,
|
||||
_ => return Err("Could not find extrinsic."),
|
||||
};
|
||||
|
||||
// Warm up the DB
|
||||
benchmarking::commit_db();
|
||||
benchmarking::wipe_db();
|
||||
|
||||
let components = <SelectedBenchmark as BenchmarkingSetup<T, crate::Call<T>, RawOrigin<T::AccountId>>>::components(&selected_benchmark);
|
||||
let mut results: Vec<BenchmarkResults> = Vec::new();
|
||||
|
||||
// Select the component we will be benchmarking. Each component will be benchmarked.
|
||||
for (name, low, high) in components.iter() {
|
||||
// Create up to `STEPS` steps for that component between high and low.
|
||||
let step_size = ((high - low) / steps).max(1);
|
||||
let num_of_steps = (high - low) / step_size;
|
||||
for s in 0..num_of_steps {
|
||||
// This is the value we will be testing for component `name`
|
||||
let component_value = low + step_size * s;
|
||||
|
||||
// Select the mid value for all the other components.
|
||||
let c: Vec<(BenchmarkParameter, u32)> = components.iter()
|
||||
.map(|(n, l, h)|
|
||||
(*n, if n == name { component_value } else { (h - l) / 2 + l })
|
||||
).collect();
|
||||
|
||||
// Run the benchmark `repeat` times.
|
||||
for _ in 0..repeat {
|
||||
// Set up the externalities environment for the setup we want to benchmark.
|
||||
let (call, caller) = <SelectedBenchmark as BenchmarkingSetup<
|
||||
T,
|
||||
Call<T>,
|
||||
RawOrigin<T::AccountId>,
|
||||
>>::instance(&selected_benchmark, &c)?;
|
||||
// Commit the externalities to the database, flushing the DB cache.
|
||||
// This will enable worst case scenario for reading from the database.
|
||||
benchmarking::commit_db();
|
||||
// Run the benchmark.
|
||||
let start = benchmarking::current_time();
|
||||
call.dispatch(caller.into())?;
|
||||
let finish = benchmarking::current_time();
|
||||
let elapsed = finish - start;
|
||||
results.push((c.clone(), elapsed));
|
||||
// Wipe the DB back to the genesis state.
|
||||
benchmarking::wipe_db();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Ok(results);
|
||||
}
|
||||
set {
|
||||
let n in ...;
|
||||
}: _(RawOrigin::None, n.into())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user