Update System Weights (#5888)

* Update system weights

* Use maximum block weight for scheduler

* Update offences to use full block

* Move weight inside if statement

* Add one read to offences `on_initialize`

* Delete factory test

* Revert "Delete factory test"

This reverts commit 8f95aacd63a028ef1b415185b45367b4140d86fd.

* Revert "Add one read to offences `on_initialize`"

This reverts commit 7df7ebc73625ed79b14086f13c247d4058ee87d6.

* Revert "Move weight inside if statement"

This reverts commit 87277d07913a7d1868eeee85ef4673f51ee4013b.

* Revert "Update offences to use full block"

This reverts commit 0bbe0ce18e9419b032157f7d37dea6481078cdc0.

* Use scheduler in Sudo

* Apply suggestions from code review

Co-authored-by: Alexander Popiak <alexander.popiak@parity.io>

* Revert "Use scheduler in Sudo"

This reverts commit 95bd2768dfea100bdf682cf4fe6c0f46e8e1f66e.

* remove max extrinsic weight (it does nothing useful)

* fix tests

* introduce `sudo_unchecked_weight`

* bump spec version

* scheduler 80 percent of maximum

* Update `set_changes_trie_config` weight

* Update bin/node/runtime/src/lib.rs

* Update frame/democracy/src/tests.rs

* Update tests.rs

* update based on feedback

Co-authored-by: Alexander Popiak <alexander.popiak@parity.io>
This commit is contained in:
Shawn Tabrizi
2020-05-07 14:33:33 +02:00
committed by GitHub
parent 99a80da757
commit b0d17b02ea
7 changed files with 118 additions and 103 deletions
+2 -2
View File
@@ -175,14 +175,14 @@ impl pallet_utility::Trait for Runtime {
}
parameter_types! {
pub const MaximumWeight: Weight = 2_000_000;
pub const MaximumSchedulerWeight: Weight = Perbill::from_percent(80) * MaximumBlockWeight::get();
}
impl pallet_scheduler::Trait for Runtime {
type Event = Event;
type Origin = Origin;
type Call = Call;
type MaximumWeight = MaximumWeight;
type MaximumWeight = MaximumSchedulerWeight;
}
parameter_types! {
+1 -1
View File
@@ -1252,7 +1252,7 @@ decl_module! {
}
/// Enact a proposal from a referendum. For now we just make the weight be the maximum.
#[weight = frame_system::Module::<T>::max_extrinsic_weight(DispatchClass::Normal)]
#[weight = T::MaximumBlockWeight::get()]
fn enact_proposal(origin, proposal_hash: T::Hash, index: ReferendumIndex) -> DispatchResult {
ensure_root(origin)?;
Self::do_enact_proposal(proposal_hash, index)
+6 -4
View File
@@ -77,7 +77,7 @@ impl_outer_event! {
pub struct Test;
parameter_types! {
pub const BlockHashCount: u64 = 250;
pub const MaximumBlockWeight: Weight = 1024;
pub const MaximumBlockWeight: Weight = 1_000_000;
pub const MaximumBlockLength: u32 = 2 * 1024;
pub const AvailableBlockRatio: Perbill = Perbill::one();
}
@@ -106,14 +106,16 @@ impl frame_system::Trait for Test {
type OnKilledAccount = ();
}
parameter_types! {
pub const ExistentialDeposit: u64 = 1;
pub const MaximumWeight: u32 = 1000000;
pub const MaximumSchedulerWeight: Weight = Perbill::from_percent(80) * MaximumBlockWeight::get();
}
impl pallet_scheduler::Trait for Test {
type Event = Event;
type Origin = Origin;
type Call = Call;
type MaximumWeight = MaximumWeight;
type MaximumWeight = MaximumSchedulerWeight;
}
parameter_types! {
pub const ExistentialDeposit: u64 = 1;
}
impl pallet_balances::Trait for Test {
type Balance = u64;
+20 -17
View File
@@ -513,11 +513,14 @@ mod tests {
impl logger::Trait for Test {
type Event = ();
}
parameter_types! {
pub const MaximumSchedulerWeight: Weight = Perbill::from_percent(80) * MaximumBlockWeight::get();
}
impl Trait for Test {
type Event = ();
type Origin = Origin;
type Call = Call;
type MaximumWeight = MaximumBlockWeight;
type MaximumWeight = MaximumSchedulerWeight;
}
type System = system::Module<Test>;
type Logger = logger::Module<Test>;
@@ -611,8 +614,8 @@ mod tests {
#[test]
fn scheduler_respects_weight_limits() {
new_test_ext().execute_with(|| {
Scheduler::do_schedule(4, None, 127, Call::Logger(logger::Call::log(42, MaximumBlockWeight::get() / 2)));
Scheduler::do_schedule(4, None, 127, Call::Logger(logger::Call::log(69, MaximumBlockWeight::get() / 2)));
Scheduler::do_schedule(4, None, 127, Call::Logger(logger::Call::log(42, MaximumSchedulerWeight::get() / 2)));
Scheduler::do_schedule(4, None, 127, Call::Logger(logger::Call::log(69, MaximumSchedulerWeight::get() / 2)));
// 69 and 42 do not fit together
run_to_block(4);
assert_eq!(logger::log(), vec![42u32]);
@@ -624,8 +627,8 @@ mod tests {
#[test]
fn scheduler_respects_hard_deadlines_more() {
new_test_ext().execute_with(|| {
Scheduler::do_schedule(4, None, 0, Call::Logger(logger::Call::log(42, MaximumBlockWeight::get() / 2)));
Scheduler::do_schedule(4, None, 0, Call::Logger(logger::Call::log(69, MaximumBlockWeight::get() / 2)));
Scheduler::do_schedule(4, None, 0, Call::Logger(logger::Call::log(42, MaximumSchedulerWeight::get() / 2)));
Scheduler::do_schedule(4, None, 0, Call::Logger(logger::Call::log(69, MaximumSchedulerWeight::get() / 2)));
// With base weights, 69 and 42 should not fit together, but do because of hard deadlines
run_to_block(4);
assert_eq!(logger::log(), vec![42u32, 69u32]);
@@ -635,8 +638,8 @@ mod tests {
#[test]
fn scheduler_respects_priority_ordering() {
new_test_ext().execute_with(|| {
Scheduler::do_schedule(4, None, 1, Call::Logger(logger::Call::log(42, MaximumBlockWeight::get() / 2)));
Scheduler::do_schedule(4, None, 0, Call::Logger(logger::Call::log(69, MaximumBlockWeight::get() / 2)));
Scheduler::do_schedule(4, None, 1, Call::Logger(logger::Call::log(42, MaximumSchedulerWeight::get() / 2)));
Scheduler::do_schedule(4, None, 0, Call::Logger(logger::Call::log(69, MaximumSchedulerWeight::get() / 2)));
run_to_block(4);
assert_eq!(logger::log(), vec![69u32, 42u32]);
});
@@ -645,9 +648,9 @@ mod tests {
#[test]
fn scheduler_respects_priority_ordering_with_soft_deadlines() {
new_test_ext().execute_with(|| {
Scheduler::do_schedule(4, None, 255, Call::Logger(logger::Call::log(42, MaximumBlockWeight::get() / 3)));
Scheduler::do_schedule(4, None, 127, Call::Logger(logger::Call::log(69, MaximumBlockWeight::get() / 2)));
Scheduler::do_schedule(4, None, 126, Call::Logger(logger::Call::log(2600, MaximumBlockWeight::get() / 2)));
Scheduler::do_schedule(4, None, 255, Call::Logger(logger::Call::log(42, MaximumSchedulerWeight::get() / 3)));
Scheduler::do_schedule(4, None, 127, Call::Logger(logger::Call::log(69, MaximumSchedulerWeight::get() / 2)));
Scheduler::do_schedule(4, None, 126, Call::Logger(logger::Call::log(2600, MaximumSchedulerWeight::get() / 2)));
// 2600 does not fit with 69 or 42, but has higher priority, so will go through
run_to_block(4);
@@ -667,29 +670,29 @@ mod tests {
let periodic_multiplier = <Test as frame_system::Trait>::DbWeight::get().reads_writes(1, 1);
// Named
assert_ok!(Scheduler::do_schedule_named(1u32.encode(), 1, None, 255, Call::Logger(logger::Call::log(3, MaximumBlockWeight::get() / 3))));
assert_ok!(Scheduler::do_schedule_named(1u32.encode(), 1, None, 255, Call::Logger(logger::Call::log(3, MaximumSchedulerWeight::get() / 3))));
// Anon Periodic
Scheduler::do_schedule(1, Some((1000, 3)), 128, Call::Logger(logger::Call::log(42, MaximumBlockWeight::get() / 3)));
Scheduler::do_schedule(1, Some((1000, 3)), 128, Call::Logger(logger::Call::log(42, MaximumSchedulerWeight::get() / 3)));
// Anon
Scheduler::do_schedule(1, None, 127, Call::Logger(logger::Call::log(69, MaximumBlockWeight::get() / 2)));
Scheduler::do_schedule(1, None, 127, Call::Logger(logger::Call::log(69, MaximumSchedulerWeight::get() / 2)));
// Named Periodic
assert_ok!(Scheduler::do_schedule_named(2u32.encode(), 1, Some((1000, 3)), 126, Call::Logger(logger::Call::log(2600, MaximumBlockWeight::get() / 2))));
assert_ok!(Scheduler::do_schedule_named(2u32.encode(), 1, Some((1000, 3)), 126, Call::Logger(logger::Call::log(2600, MaximumSchedulerWeight::get() / 2))));
// Will include the named periodic only
let actual_weight = Scheduler::on_initialize(1);
let call_weight = MaximumBlockWeight::get() / 2;
let call_weight = MaximumSchedulerWeight::get() / 2;
assert_eq!(actual_weight, call_weight + base_weight + base_multiplier + named_multiplier + periodic_multiplier);
assert_eq!(logger::log(), vec![2600u32]);
// Will include anon and anon periodic
let actual_weight = Scheduler::on_initialize(2);
let call_weight = MaximumBlockWeight::get() / 2 + MaximumBlockWeight::get() / 3;
let call_weight = MaximumSchedulerWeight::get() / 2 + MaximumSchedulerWeight::get() / 3;
assert_eq!(actual_weight, call_weight + base_weight + base_multiplier * 2 + periodic_multiplier);
assert_eq!(logger::log(), vec![2600u32, 69u32, 42u32]);
// Will include named only
let actual_weight = Scheduler::on_initialize(3);
let call_weight = MaximumBlockWeight::get() / 3;
let call_weight = MaximumSchedulerWeight::get() / 3;
assert_eq!(actual_weight, call_weight + base_weight + base_multiplier + named_multiplier);
assert_eq!(logger::log(), vec![2600u32, 69u32, 42u32, 3u32]);
+25 -1
View File
@@ -92,7 +92,7 @@ use sp_runtime::{DispatchResult, traits::{StaticLookup, Dispatchable}};
use frame_support::{
Parameter, decl_module, decl_event, decl_storage, decl_error, ensure,
};
use frame_support::weights::{GetDispatchInfo, FunctionOf, Pays};
use frame_support::weights::{Weight, GetDispatchInfo, FunctionOf, Pays};
use frame_system::{self as system, ensure_signed};
pub trait Trait: frame_system::Trait {
@@ -134,6 +134,30 @@ decl_module! {
Self::deposit_event(RawEvent::Sudid(res.map(|_| ()).map_err(|e| e.error)));
}
/// Authenticates the sudo key and dispatches a function call with `Root` origin.
/// This function does not check the weight of the call, and instead allows the
/// Sudo user to specify the weight of the call.
///
/// The dispatch origin for this call must be _Signed_.
///
/// # <weight>
/// - O(1).
/// - The weight of this call is defined by the caller.
/// # </weight>
#[weight = FunctionOf(
|(_, &weight): (&Box<<T as Trait>::Call>,&Weight,)| weight,
|(call, _): (&Box<<T as Trait>::Call>,&Weight,)| call.get_dispatch_info().class,
Pays::Yes,
)]
fn sudo_unchecked_weight(origin, call: Box<<T as Trait>::Call>, _weight: Weight) {
// This is a public call, so we ensure that the origin is some signed account.
let sender = ensure_signed(origin)?;
ensure!(sender == Self::key(), Error::<T>::RequireSudo);
let res = call.dispatch(frame_system::RawOrigin::Root.into());
Self::deposit_event(RawEvent::Sudid(res.map(|_| ()).map_err(|e| e.error)));
}
/// Authenticates the current sudo key and sets the given AccountId (`new`) as the new sudo key.
///
/// The dispatch origin for this call must be _Signed_.
@@ -134,7 +134,7 @@ benchmarks! {
let value = storage::unhashed::get_raw(&last_key).ok_or("No value stored")?;
assert_eq!(value, last_key);
}: _(RawOrigin::Root, prefix)
}: _(RawOrigin::Root, prefix, p)
verify {
assert_eq!(storage::unhashed::get_raw(&last_key), None);
}
+63 -77
View File
@@ -512,8 +512,10 @@ decl_module! {
///
/// # <weight>
/// - `O(1)`
/// - Base Weight: 0.665 µs, independent of remark length.
/// - No DB operations.
/// # </weight>
#[weight = 0]
#[weight = 700_000]
fn remark(origin, _remark: Vec<u8>) {
ensure_signed(origin)?;
}
@@ -523,8 +525,10 @@ decl_module! {
/// # <weight>
/// - `O(1)`
/// - 1 storage write.
/// - Base Weight: 1.405 µs
/// - 1 write to HEAP_PAGES
/// # </weight>
#[weight = (0, DispatchClass::Operational)]
#[weight = (T::DbWeight::get().writes(1) + 1_500_000, DispatchClass::Operational)]
fn set_heap_pages(origin, pages: u64) {
ensure_root(origin)?;
storage::unhashed::put_raw(well_known_keys::HEAP_PAGES, &pages.encode());
@@ -537,8 +541,10 @@ decl_module! {
/// - 1 storage write (codec `O(C)`).
/// - 1 call to `can_set_code`: `O(S)` (calls `sp_io::misc::runtime_version` which is expensive).
/// - 1 event.
/// The weight of this function is dependent on the runtime, but generally this is very expensive.
/// We will treat this as a full block.
/// # </weight>
#[weight = (200_000_000, DispatchClass::Operational)]
#[weight = (T::MaximumBlockWeight::get(), DispatchClass::Operational)]
pub fn set_code(origin, code: Vec<u8>) {
Self::can_set_code(origin, &code)?;
@@ -552,8 +558,9 @@ decl_module! {
/// - `O(C)` where `C` length of `code`
/// - 1 storage write (codec `O(C)`).
/// - 1 event.
/// The weight of this function is dependent on the runtime. We will treat this as a full block.
/// # </weight>
#[weight = (200_000_000, DispatchClass::Operational)]
#[weight = (T::MaximumBlockWeight::get(), DispatchClass::Operational)]
pub fn set_code_without_checks(origin, code: Vec<u8>) {
ensure_root(origin)?;
storage::unhashed::put_raw(well_known_keys::CODE, &code);
@@ -563,11 +570,14 @@ decl_module! {
/// Set the new changes trie configuration.
///
/// # <weight>
/// - `O(D)` where `D` length of `Digest`
/// - `O(1)`
/// - 1 storage write or delete (codec `O(1)`).
/// - 1 call to `deposit_log`: `O(D)` (which depends on the length of `Digest`)
/// - 1 call to `deposit_log`: Uses `append` API, so O(1)
/// - Base Weight: 7.218 µs
/// - DB Weight:
/// - Writes: Changes Trie, System Digest
/// # </weight>
#[weight = (20_000_000, DispatchClass::Operational)]
#[weight = (T::DbWeight::get().writes(2) + 10_000_000, DispatchClass::Operational)]
pub fn set_changes_trie_config(origin, changes_trie_config: Option<ChangesTrieConfiguration>) {
ensure_root(origin)?;
match changes_trie_config.clone() {
@@ -589,8 +599,17 @@ decl_module! {
/// # <weight>
/// - `O(I)` where `I` length of `items`
/// - `I` storage writes (`O(1)`).
/// - Base Weight: 0.568 * i µs
/// - Writes: Number of items
/// # </weight>
#[weight = (0, DispatchClass::Operational)]
#[weight = FunctionOf(
|(items,): (&Vec<KeyValue>,)| {
T::DbWeight::get().writes(items.len() as Weight)
.saturating_add((items.len() as Weight).saturating_mul(600_000))
},
DispatchClass::Operational,
Pays::Yes,
)]
fn set_storage(origin, items: Vec<KeyValue>) {
ensure_root(origin)?;
for i in &items {
@@ -601,10 +620,19 @@ decl_module! {
/// Kill some items from storage.
///
/// # <weight>
/// - `O(VK)` where `V` length of `keys` and `K` length of one key
/// - `V` storage deletions.
/// - `O(IK)` where `I` length of `keys` and `K` length of one key
/// - `I` storage deletions.
/// - Base Weight: .378 * i µs
/// - Writes: Number of items
/// # </weight>
#[weight = (0, DispatchClass::Operational)]
#[weight = FunctionOf(
|(keys,): (&Vec<Key>,)| {
T::DbWeight::get().writes(keys.len() as Weight)
.saturating_add((keys.len() as Weight).saturating_mul(400_000))
},
DispatchClass::Operational,
Pays::Yes,
)]
fn kill_storage(origin, keys: Vec<Key>) {
ensure_root(origin)?;
for key in &keys {
@@ -614,12 +642,24 @@ decl_module! {
/// Kill all storage items with a key that starts with the given prefix.
///
/// **NOTE:** We rely on the Root origin to provide us the number of subkeys under
/// the prefix we are removing to accurately calculate the weight of this function.
///
/// # <weight>
/// - `O(P)` where `P` amount of keys with prefix `prefix`
/// - `P` storage deletions.
/// - Base Weight: 0.834 * P µs
/// - Writes: Number of subkeys + 1
/// # </weight>
#[weight = (0, DispatchClass::Operational)]
fn kill_prefix(origin, prefix: Key) {
#[weight = FunctionOf(
|(_, &subkeys): (&Key, &u32)| {
T::DbWeight::get().writes(Weight::from(subkeys) + 1)
.saturating_add((Weight::from(subkeys) + 1).saturating_mul(850_000))
},
DispatchClass::Operational,
Pays::Yes,
)]
fn kill_prefix(origin, prefix: Key, _subkeys: u32) {
ensure_root(origin)?;
storage::unhashed::kill_prefix(&prefix);
}
@@ -630,8 +670,11 @@ decl_module! {
/// # <weight>
/// - `O(1)`
/// - 1 storage read and deletion.
/// --------------------
/// Base Weight: 8.626 µs
/// No DB Read or Write operations because caller is already in overlay
/// # </weight>
#[weight = (25_000_000, DispatchClass::Operational)]
#[weight = (10_000_000, DispatchClass::Operational)]
fn suicide(origin) {
let who = ensure_signed(origin)?;
let account = Account::<T>::get(&who);
@@ -874,23 +917,6 @@ impl<T: Trait> Module<T> {
AllExtrinsicsWeight::get().unwrap_or_default()
}
/// Get the quota ratio of each dispatch class type. This indicates that all operational and mandatory
/// dispatches can use the full capacity of any resource, while user-triggered ones can consume
/// a portion.
pub fn get_dispatch_limit_ratio(class: DispatchClass) -> Perbill {
match class {
DispatchClass::Operational | DispatchClass::Mandatory
=> <Perbill as sp_runtime::PerThing>::one(),
DispatchClass::Normal => T::AvailableBlockRatio::get(),
}
}
/// The maximum weight of an allowable extrinsic. Only one of these could exist in a block.
pub fn max_extrinsic_weight(class: DispatchClass) -> Weight {
let limit = Self::get_dispatch_limit_ratio(class) * T::MaximumBlockWeight::get();
limit - (T::BlockExecutionWeight::get() + T::ExtrinsicBaseWeight::get())
}
pub fn all_extrinsics_len() -> u32 {
AllExtrinsicsLen::get().unwrap_or_default()
}
@@ -1257,7 +1283,11 @@ impl<T: Trait + Send + Sync> CheckWeight<T> where
/// dispatches can use the full capacity of any resource, while user-triggered ones can consume
/// a portion.
fn get_dispatch_limit_ratio(class: DispatchClass) -> Perbill {
Module::<T>::get_dispatch_limit_ratio(class)
match class {
DispatchClass::Operational | DispatchClass::Mandatory
=> <Perbill as sp_runtime::PerThing>::one(),
DispatchClass::Normal => T::AvailableBlockRatio::get(),
}
}
/// Checks if the current extrinsic can fit into the block with respect to block weight limits.
@@ -1680,7 +1710,7 @@ pub(crate) mod tests {
use sp_std::cell::RefCell;
use sp_core::H256;
use sp_runtime::{traits::{BlakeTwo256, IdentityLookup, SignedExtension}, testing::Header, DispatchError};
use frame_support::{impl_outer_origin, parameter_types, assert_ok, assert_err};
use frame_support::{impl_outer_origin, parameter_types, assert_ok};
impl_outer_origin! {
pub enum Origin for Test where system = super {}
@@ -2082,47 +2112,6 @@ pub(crate) mod tests {
})
}
#[test]
fn max_extrinsic_weight_is_allowed_but_nothing_more() {
// Dispatch Class Normal
new_test_ext().execute_with(|| {
let one = DispatchInfo { weight: 1, ..Default::default() };
let max = DispatchInfo { weight: System::max_extrinsic_weight(DispatchClass::Normal), ..Default::default() };
let len = 0_usize;
assert_ok!(CheckWeight::<Test>::do_pre_dispatch(&max, len));
assert_err!(
CheckWeight::<Test>::do_pre_dispatch(&one, len),
InvalidTransaction::ExhaustsResources,
);
// Weight should be 75% of 1024 (max block weight)
assert_eq!(System::all_extrinsics_weight(), 768);
});
// Dispatch Class Operational
new_test_ext().execute_with(|| {
let one = DispatchInfo {
weight: 1,
class: DispatchClass::Operational,
..Default::default()
};
let max = DispatchInfo {
weight: System::max_extrinsic_weight(DispatchClass::Operational),
class: DispatchClass::Operational,
..Default::default()
};
let len = 0_usize;
assert_ok!(CheckWeight::<Test>::do_pre_dispatch(&max, len));
assert_err!(
CheckWeight::<Test>::do_pre_dispatch(&one, len),
InvalidTransaction::ExhaustsResources,
);
// Weight should be 100% of max block weight
assert_eq!(System::all_extrinsics_weight(), <Test as Trait>::MaximumBlockWeight::get());
});
}
#[test]
fn mandatory_extrinsic_doesnt_care_about_limits() {
new_test_ext().execute_with(|| {
@@ -2156,9 +2145,6 @@ pub(crate) mod tests {
// 10 is taken for block execution weight
// So normal extrinsic can be 758 weight (-5 for base extrinsic weight)
// And Operational can be 256 to produce a full block (-5 for base)
assert_eq!(System::max_extrinsic_weight(DispatchClass::Normal), 753);
let max_normal = DispatchInfo { weight: 753, ..Default::default() };
let rest_operational = DispatchInfo { weight: 251, class: DispatchClass::Operational, ..Default::default() };