mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-13 17:31:05 +00:00
Weight annotation. (#3157)
* Make extrinsics extensible. Also Remove old extrinsic types. * Rest of mockup. Add tips. * Fix some build issues * Runtiem builds :) * Substrate builds. * Fix a doc test * Compact encoding * Extract out the era logic into an extension * Weight Check signed extension. (#3115) * Weight signed extension. * Revert a bit + test for check era. * Update Cargo.toml * Update node/cli/src/factory_impl.rs * Update node/executor/src/lib.rs * Update node/executor/src/lib.rs * Don't use len for weight - use data. * Operational Transaction; second attempt (#3138) * working poc added. * some fixes. * Update doc. * Fix all tests + final logic. * more refactoring. * nits. * System block limit in bytes. * Silent the storage macro warnings. * More logic more tests. * Fix import. * Refactor names. * Fix build. * Update srml/balances/src/lib.rs * Final refactor. * Bump transaction version * Fix weight mult test. * Fix more tests and improve doc. * Bump. * Make some tests work again. * Fix subkey. * Remove todos + bump. * First draft of annotating weights. * Refactor weight to u64. * More refactoring and tests. * New convert for weight to fee * more tests. * remove merge redundancy. * Fix system test. * Bring back subkey stuff. * a few stress tests. * fix some of the grumbles. * Final nits. * Update srml/system/src/lib.rs Co-Authored-By: DemiMarie-parity <48690212+DemiMarie-parity@users.noreply.github.com> * Scale weights by 1000. * Bump. * Fix decl_storage test.
This commit is contained in:
committed by
Bastian Köcher
parent
80472956f8
commit
002acb9373
@@ -78,7 +78,8 @@ use rstd::prelude::*;
|
||||
use rstd::map;
|
||||
use rstd::marker::PhantomData;
|
||||
use primitives::generic::{self, Era};
|
||||
use primitives::weights::{Weight, DispatchInfo, DispatchClass, WeightMultiplier};
|
||||
use primitives::Perbill;
|
||||
use primitives::weights::{Weight, DispatchInfo, DispatchClass, WeightMultiplier, SimpleDispatchInfo};
|
||||
use primitives::transaction_validity::{ValidTransaction, TransactionPriority, TransactionLongevity};
|
||||
use primitives::traits::{self, CheckEqual, SimpleArithmetic, Zero, SignedExtension, Convert,
|
||||
SimpleBitOps, Hash, Member, MaybeDisplay, EnsureOrigin, CurrentHeight, BlockNumberToHash,
|
||||
@@ -203,6 +204,12 @@ pub trait Trait: 'static + Eq + Clone {
|
||||
|
||||
/// The maximum length of a block (in bytes).
|
||||
type MaximumBlockLength: Get<u32>;
|
||||
|
||||
/// The portion of the block that is available to normal transaction. The rest can only be used
|
||||
/// by operational transactions. This can be applied to any resource limit managed by the system
|
||||
/// module, including weight and length.
|
||||
type AvailableBlockRatio: Get<Perbill>;
|
||||
|
||||
}
|
||||
|
||||
pub type DigestOf<T> = generic::Digest<<T as Trait>::Hash>;
|
||||
@@ -218,24 +225,35 @@ decl_module! {
|
||||
Self::deposit_event_indexed(&[], event);
|
||||
}
|
||||
|
||||
/// A big dispatch that will disallow any other transaction to be included.
|
||||
// TODO: this must be preferable available for testing really (not possible at the moment).
|
||||
#[weight = SimpleDispatchInfo::MaxOperational]
|
||||
fn fill_block(origin) {
|
||||
ensure_root(origin)?;
|
||||
}
|
||||
|
||||
/// Make some on-chain remark.
|
||||
#[weight = SimpleDispatchInfo::FixedNormal(1_000_000)]
|
||||
fn remark(origin, _remark: Vec<u8>) {
|
||||
ensure_signed(origin)?;
|
||||
}
|
||||
|
||||
/// Set the number of pages in the WebAssembly environment's heap.
|
||||
#[weight = SimpleDispatchInfo::FixedOperational(10_000)]
|
||||
fn set_heap_pages(origin, pages: u64) {
|
||||
ensure_root(origin)?;
|
||||
storage::unhashed::put_raw(well_known_keys::HEAP_PAGES, &pages.encode());
|
||||
}
|
||||
|
||||
/// Set the new code.
|
||||
#[weight = SimpleDispatchInfo::FixedOperational(200_000)]
|
||||
pub fn set_code(origin, new: Vec<u8>) {
|
||||
ensure_root(origin)?;
|
||||
storage::unhashed::put_raw(well_known_keys::CODE, &new);
|
||||
}
|
||||
|
||||
/// Set some items of storage.
|
||||
#[weight = SimpleDispatchInfo::FixedOperational(10_000)]
|
||||
fn set_storage(origin, items: Vec<KeyValue>) {
|
||||
ensure_root(origin)?;
|
||||
for i in &items {
|
||||
@@ -244,6 +262,7 @@ decl_module! {
|
||||
}
|
||||
|
||||
/// Kill some items from storage.
|
||||
#[weight = SimpleDispatchInfo::FixedOperational(10_000)]
|
||||
fn kill_storage(origin, keys: Vec<Key>) {
|
||||
ensure_root(origin)?;
|
||||
for key in &keys {
|
||||
@@ -792,26 +811,28 @@ pub struct CheckWeight<T: Trait + Send + Sync>(PhantomData<T>);
|
||||
|
||||
impl<T: Trait + Send + Sync> CheckWeight<T> {
|
||||
|
||||
/// Get the quota divisor of each dispatch class type. This indicates that all operational
|
||||
/// Get the quota ratio of each dispatch class type. This indicates that all operational
|
||||
/// dispatches can use the full capacity of any resource, while user-triggered ones can consume
|
||||
/// a quarter.
|
||||
fn get_dispatch_limit_divisor(class: DispatchClass) -> Weight {
|
||||
/// a portion.
|
||||
fn get_dispatch_limit_ratio(class: DispatchClass) -> Perbill {
|
||||
match class {
|
||||
DispatchClass::Operational => 1,
|
||||
DispatchClass::Normal => 4,
|
||||
DispatchClass::Operational => Perbill::one(),
|
||||
// TODO: this must be some sort of a constant.
|
||||
DispatchClass::Normal => T::AvailableBlockRatio::get(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Checks if the current extrinsic can fit into the block with respect to block weight limits.
|
||||
///
|
||||
/// Upon successes, it returns the new block weight as a `Result`.
|
||||
fn check_weight(info: DispatchInfo) -> Result<Weight, DispatchError> {
|
||||
let current_weight = Module::<T>::all_extrinsics_weight();
|
||||
let maximum_weight = T::MaximumBlockWeight::get();
|
||||
let limit = maximum_weight / Self::get_dispatch_limit_divisor(info.class);
|
||||
let limit = Self::get_dispatch_limit_ratio(info.class) * maximum_weight;
|
||||
let added_weight = info.weight.min(limit);
|
||||
let next_weight = current_weight.saturating_add(added_weight);
|
||||
if next_weight > limit {
|
||||
return Err(DispatchError::BadState)
|
||||
return Err(DispatchError::Resource)
|
||||
}
|
||||
Ok(next_weight)
|
||||
}
|
||||
@@ -822,11 +843,11 @@ impl<T: Trait + Send + Sync> CheckWeight<T> {
|
||||
fn check_block_length(info: DispatchInfo, len: usize) -> Result<u32, DispatchError> {
|
||||
let current_len = Module::<T>::all_extrinsics_len();
|
||||
let maximum_len = T::MaximumBlockLength::get();
|
||||
let limit = maximum_len / Self::get_dispatch_limit_divisor(info.class);
|
||||
let limit = Self::get_dispatch_limit_ratio(info.class) * maximum_len;
|
||||
let added_len = len as u32;
|
||||
let next_len = current_len.saturating_add(added_len);
|
||||
if next_len > limit {
|
||||
return Err(DispatchError::BadState)
|
||||
return Err(DispatchError::Resource)
|
||||
}
|
||||
Ok(next_len)
|
||||
}
|
||||
@@ -872,8 +893,8 @@ impl<T: Trait + Send + Sync> SignedExtension for CheckWeight<T> {
|
||||
len: usize,
|
||||
) -> Result<ValidTransaction, DispatchError> {
|
||||
// There is no point in writing to storage here since changes are discarded. This basically
|
||||
// discards any transaction which is bigger than the length or weight limit alone, which is
|
||||
// a guarantee that it will fail in the pre-dispatch phase.
|
||||
// discards any transaction which is bigger than the length or weight limit **alone**,which
|
||||
// is a guarantee that it will fail in the pre-dispatch phase.
|
||||
let _ = Self::check_block_length(info, len)?;
|
||||
let _ = Self::check_weight(info)?;
|
||||
Ok(ValidTransaction { priority: Self::get_priority(info), ..Default::default() })
|
||||
@@ -1035,7 +1056,8 @@ mod tests {
|
||||
parameter_types! {
|
||||
pub const BlockHashCount: u64 = 10;
|
||||
pub const MaximumBlockWeight: Weight = 1024;
|
||||
pub const MaximumBlockLength: u32 = 2 * 1024;
|
||||
pub const AvailableBlockRatio: Perbill = Perbill::from_percent(75);
|
||||
pub const MaximumBlockLength: u32 = 1024;
|
||||
}
|
||||
|
||||
impl Trait for Test {
|
||||
@@ -1051,6 +1073,7 @@ mod tests {
|
||||
type Event = u16;
|
||||
type BlockHashCount = BlockHashCount;
|
||||
type MaximumBlockWeight = MaximumBlockWeight;
|
||||
type AvailableBlockRatio = AvailableBlockRatio;
|
||||
type MaximumBlockLength = MaximumBlockLength;
|
||||
}
|
||||
|
||||
@@ -1069,6 +1092,14 @@ mod tests {
|
||||
GenesisConfig::default().build_storage::<Test>().unwrap().0.into()
|
||||
}
|
||||
|
||||
fn normal_weight_limit() -> Weight {
|
||||
<Test as Trait>::AvailableBlockRatio::get() * <Test as Trait>::MaximumBlockWeight::get()
|
||||
}
|
||||
|
||||
fn normal_length_limit() -> u32 {
|
||||
<Test as Trait>::AvailableBlockRatio::get() * <Test as Trait>::MaximumBlockLength::get()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn origin_works() {
|
||||
let o = Origin::from(RawOrigin::<u64>::Signed(1u64));
|
||||
@@ -1222,15 +1253,16 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn signed_ext_check_weight_works_user_tx() {
|
||||
fn signed_ext_check_weight_works_normal_tx() {
|
||||
with_externalities(&mut new_test_ext(), || {
|
||||
let normal_limit = normal_weight_limit();
|
||||
let small = DispatchInfo { weight: 100, ..Default::default() };
|
||||
let medium = DispatchInfo {
|
||||
weight: <MaximumBlockWeight as Get<Weight>>::get() / 4 - 1,
|
||||
weight: normal_limit - 1,
|
||||
..Default::default()
|
||||
};
|
||||
let big = DispatchInfo {
|
||||
weight: <MaximumBlockWeight as Get<Weight>>::get() / 4 + 1,
|
||||
weight: normal_limit + 1,
|
||||
..Default::default()
|
||||
};
|
||||
let len = 0_usize;
|
||||
@@ -1265,11 +1297,12 @@ mod tests {
|
||||
with_externalities(&mut new_test_ext(), || {
|
||||
let max = DispatchInfo { weight: Weight::max_value(), ..Default::default() };
|
||||
let len = 0_usize;
|
||||
let normal_limit = normal_weight_limit();
|
||||
|
||||
assert_eq!(System::all_extrinsics_weight(), 0);
|
||||
let r = CheckWeight::<Test>(PhantomData).pre_dispatch(&1, max, len);
|
||||
assert!(r.is_ok());
|
||||
assert_eq!(System::all_extrinsics_weight(), <MaximumBlockWeight as Get<Weight>>::get() / 4);
|
||||
assert_eq!(System::all_extrinsics_weight(), normal_limit);
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1279,9 +1312,10 @@ mod tests {
|
||||
let normal = DispatchInfo { weight: 100, ..Default::default() };
|
||||
let op = DispatchInfo { weight: 100, class: DispatchClass::Operational };
|
||||
let len = 0_usize;
|
||||
let normal_limit = normal_weight_limit();
|
||||
|
||||
// given almost full block
|
||||
AllExtrinsicsWeight::put(<MaximumBlockWeight as Get<Weight>>::get() / 4);
|
||||
AllExtrinsicsWeight::put(normal_limit);
|
||||
// will not fit.
|
||||
assert!(CheckWeight::<Test>(PhantomData).pre_dispatch(&1, normal, len).is_err());
|
||||
// will fit.
|
||||
@@ -1289,7 +1323,7 @@ mod tests {
|
||||
|
||||
// likewise for length limit.
|
||||
let len = 100_usize;
|
||||
AllExtrinsicsLen::put(<MaximumBlockLength as Get<Weight>>::get() / 4);
|
||||
AllExtrinsicsLen::put(normal_length_limit());
|
||||
assert!(CheckWeight::<Test>(PhantomData).pre_dispatch(&1, normal, len).is_err());
|
||||
assert!(CheckWeight::<Test>(PhantomData).pre_dispatch(&1, op, len).is_ok());
|
||||
})
|
||||
@@ -1316,17 +1350,24 @@ mod tests {
|
||||
#[test]
|
||||
fn signed_ext_check_weight_block_size_works() {
|
||||
with_externalities(&mut new_test_ext(), || {
|
||||
let tx = DispatchInfo::default();
|
||||
|
||||
let reset_check_weight = |s, f| {
|
||||
let normal = DispatchInfo::default();
|
||||
let normal_limit = normal_weight_limit() as usize;
|
||||
let reset_check_weight = |tx, s, f| {
|
||||
AllExtrinsicsLen::put(0);
|
||||
let r = CheckWeight::<Test>(PhantomData).pre_dispatch(&1, tx, s);
|
||||
if f { assert!(r.is_err()) } else { assert!(r.is_ok()) }
|
||||
};
|
||||
|
||||
reset_check_weight(128, false);
|
||||
reset_check_weight(512, false);
|
||||
reset_check_weight(513, true);
|
||||
reset_check_weight(normal, normal_limit - 1, false);
|
||||
reset_check_weight(normal, normal_limit, false);
|
||||
reset_check_weight(normal, normal_limit + 1, true);
|
||||
|
||||
// Operational ones don't have this limit.
|
||||
let op = DispatchInfo { weight: 0, class: DispatchClass::Operational };
|
||||
reset_check_weight(op, normal_limit, false);
|
||||
reset_check_weight(op, normal_limit + 100, false);
|
||||
reset_check_weight(op, 1024, false);
|
||||
reset_check_weight(op, 1025, true);
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user