Skip to content
This repository has been archived by the owner on Nov 15, 2023. It is now read-only.

Optional PoV block limits #13164

Closed
wants to merge 31 commits into from
Closed
Show file tree
Hide file tree
Changes from 27 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions bin/node/runtime/src/impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ mod multiplier_tests {
BlockWeights::get()
.get(DispatchClass::Normal)
.max_total
.unwrap_or_else(|| BlockWeights::get().max_block)
.limited_or(BlockWeights::get().max_block)
}

fn min_multiplier() -> Multiplier {
Expand Down Expand Up @@ -284,8 +284,9 @@ mod multiplier_tests {
// `cargo test congested_chain_simulation -- --nocapture` to get some insight.

// almost full. The entire quota of normal transactions is taken.
let block_weight = BlockWeights::get().get(DispatchClass::Normal).max_total.unwrap() -
Weight::from_ref_time(100);
let block_weight =
BlockWeights::get().get(DispatchClass::Normal).max_total.exact_limits().unwrap() -
Weight::from_ref_time(100);

// Default substrate weight.
let tx_weight = frame_support::weights::constants::ExtrinsicBaseWeight::get();
Expand Down
14 changes: 8 additions & 6 deletions bin/node/runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -190,15 +190,15 @@ parameter_types! {
weights.base_extrinsic = ExtrinsicBaseWeight::get();
})
.for_class(DispatchClass::Normal, |weights| {
weights.max_total = Some(NORMAL_DISPATCH_RATIO * MAXIMUM_BLOCK_WEIGHT);
weights.max_total = (NORMAL_DISPATCH_RATIO * MAXIMUM_BLOCK_WEIGHT).into();
})
.for_class(DispatchClass::Operational, |weights| {
weights.max_total = Some(MAXIMUM_BLOCK_WEIGHT);
weights.max_total = (MAXIMUM_BLOCK_WEIGHT).into();
// Operational transactions have some extra reserved space, so that they
// are included even if block reached `MAXIMUM_BLOCK_WEIGHT`.
weights.reserved = Some(
weights.reserved = (
MAXIMUM_BLOCK_WEIGHT - NORMAL_DISPATCH_RATIO * MAXIMUM_BLOCK_WEIGHT
);
).into();
})
.avg_block_initialization(AVERAGE_ON_INITIALIZE_RATIO)
.build_or_panic();
Expand Down Expand Up @@ -614,7 +614,9 @@ parameter_types! {
pub const MultiPhaseUnsignedPriority: TransactionPriority = StakingUnsignedPriority::get() - 1u64;
pub MinerMaxWeight: Weight = RuntimeBlockWeights::get()
.get(DispatchClass::Normal)
.max_extrinsic.expect("Normal extrinsics have a weight limit configured; qed")
.max_extrinsic
.exact_limits()
.expect("Normal extrinsics have a weight limit configured; qed")
.saturating_sub(BlockExecutionWeight::get());
// Solution can occupy 90% of normal block size
pub MinerMaxLength: u32 = Perbill::from_rational(9u32, 10) *
Expand Down Expand Up @@ -1187,7 +1189,7 @@ parameter_types! {
.per_class
.get(DispatchClass::Normal)
.max_total
.unwrap_or(RuntimeBlockWeights::get().max_block);
.limited_or(RuntimeBlockWeights::get().max_block);
pub Schedule: pallet_contracts::Schedule<Runtime> = Default::default();
}

Expand Down
3 changes: 2 additions & 1 deletion frame/executive/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1125,7 +1125,8 @@ mod tests {
// on_initialize weight + base block execution weight
let block_weights = <Runtime as frame_system::Config>::BlockWeights::get();
let base_block_weight = Weight::from_ref_time(175) + block_weights.base_block;
let limit = block_weights.get(DispatchClass::Normal).max_total.unwrap() - base_block_weight;
let limit = block_weights.get(DispatchClass::Normal).max_total.exact_limits().unwrap() -
base_block_weight;
let num_to_exhaust_block = limit.ref_time() / (encoded_len + 5);
t.execute_with(|| {
Executive::initialize_block(&Header::new(
Expand Down
226 changes: 210 additions & 16 deletions frame/support/src/dispatch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -423,33 +423,35 @@ impl<T: Clone> PerDispatchClass<T> {

impl PerDispatchClass<Weight> {
/// Returns the total weight consumed by all extrinsics in the block.
///
/// Saturates on overflow.
pub fn total(&self) -> Weight {
let mut sum = Weight::zero();
for class in DispatchClass::all() {
sum = sum.saturating_add(*self.get(*class));
sum.saturating_accrue(*self.get(*class));
}
sum
}

/// Add some weight of a specific dispatch class, saturating at the numeric bounds of `Weight`.
pub fn add(&mut self, weight: Weight, class: DispatchClass) {
let value = self.get_mut(class);
*value = value.saturating_add(weight);
/// Add some weight to the given class. Saturates at the numeric bounds.
pub fn saturating_add(mut self, weight: Weight, class: DispatchClass) -> Self {
self.saturating_accrue(weight, class);
self
}

/// Increase the weight of the given class. Saturates at the numeric bounds.
pub fn saturating_accrue(&mut self, weight: Weight, class: DispatchClass) {
self.get_mut(class).saturating_accrue(weight);
}

/// Try to add some weight of a specific dispatch class, returning Err(()) if overflow would
/// occur.
pub fn checked_add(&mut self, weight: Weight, class: DispatchClass) -> Result<(), ()> {
let value = self.get_mut(class);
*value = value.checked_add(&weight).ok_or(())?;
Ok(())
/// Try to increase the weight of the given class. Saturates at the numeric bounds.
pub fn checked_accrue(&mut self, weight: Weight, class: DispatchClass) -> Result<(), ()> {
self.get_mut(class).checked_accrue(weight).ok_or(())
}

/// Subtract some weight of a specific dispatch class, saturating at the numeric bounds of
/// `Weight`.
pub fn sub(&mut self, weight: Weight, class: DispatchClass) {
let value = self.get_mut(class);
*value = value.saturating_sub(weight);
/// Reduce the weight of the given class. Saturates at the numeric bounds.
pub fn saturating_reduce(&mut self, weight: Weight, class: DispatchClass) {
self.get_mut(class).saturating_reduce(weight);
}
}

Expand Down Expand Up @@ -3693,3 +3695,195 @@ mod weight_tests {
assert_eq!(extract_actual_pays_fee(&Ok((Some(1000), Pays::Yes).into()), &pre), Pays::No);
}
}

#[cfg(test)]
mod per_dispatch_class_tests {
use super::*;
use sp_runtime::traits::Zero;
use DispatchClass::*;

// helper trait
trait IntoWeight {
fn into_weight(self) -> Weight;
}

impl IntoWeight for u64 {
fn into_weight(self) -> Weight {
Weight::from_all(self)
}
}

impl IntoWeight for (u64, u64) {
fn into_weight(self) -> Weight {
Weight::from_parts(self.0, self.1)
}
}

#[test]
fn saturating_add_works() {
let a = PerDispatchClass {
normal: (5, 10).into_weight(),
operational: (20, 30).into_weight(),
mandatory: Weight::MAX,
};
assert_eq!(
a.clone()
.saturating_add((20, 5).into_weight(), Normal)
.saturating_add((10, 10).into_weight(), Operational)
.saturating_add((u64::MAX, 3).into_weight(), Mandatory),
PerDispatchClass {
normal: (25, 15).into_weight(),
operational: (30, 40).into_weight(),
mandatory: Weight::MAX
}
);
let b = a
.saturating_add(Weight::MAX, Normal)
.saturating_add(Weight::MAX, Operational)
.saturating_add(Weight::MAX, Mandatory);
assert_eq!(
b,
PerDispatchClass {
normal: Weight::MAX,
operational: Weight::MAX,
mandatory: Weight::MAX
}
);
assert_eq!(b.total(), Weight::MAX);
}

#[test]
fn saturating_accrue_works() {
let mut a = PerDispatchClass::default();

a.saturating_accrue((10, 15).into_weight(), Normal);
assert_eq!(a.normal, (10, 15).into_weight());
assert_eq!(a.total(), (10, 15).into_weight());

a.saturating_accrue((20, 25).into_weight(), Operational);
assert_eq!(a.operational, (20, 25).into_weight());
assert_eq!(a.total(), (30, 40).into_weight());

a.saturating_accrue((30, 35).into_weight(), Mandatory);
assert_eq!(a.mandatory, (30, 35).into_weight());
assert_eq!(a.total(), (60, 75).into_weight());

a.saturating_accrue((u64::MAX, 10).into_weight(), Operational);
assert_eq!(a.operational, (u64::MAX, 35).into_weight());
assert_eq!(a.total(), (u64::MAX, 85).into_weight());

a.saturating_accrue((10, u64::MAX).into_weight(), Normal);
assert_eq!(a.normal, (20, u64::MAX).into_weight());
assert_eq!(a.total(), Weight::MAX);
}

#[test]
fn saturating_reduce_works() {
let mut a = PerDispatchClass {
normal: (10, u64::MAX).into_weight(),
mandatory: (u64::MAX, 10).into_weight(),
operational: (20, 20).into_weight(),
};

a.saturating_reduce((5, 100).into_weight(), Normal);
assert_eq!(a.normal, (5, u64::MAX - 100).into_weight());
assert_eq!(a.total(), (u64::MAX, u64::MAX - 70).into_weight());

a.saturating_reduce((15, 5).into_weight(), Operational);
assert_eq!(a.operational, (5, 15).into_weight());
assert_eq!(a.total(), (u64::MAX, u64::MAX - 75).into_weight());

a.saturating_reduce((50, 0).into_weight(), Mandatory);
assert_eq!(a.mandatory, (u64::MAX - 50, 10).into_weight());
assert_eq!(a.total(), (u64::MAX - 40, u64::MAX - 75).into_weight());

a.saturating_reduce((u64::MAX, 100).into_weight(), Operational);
assert!(a.operational.is_zero());
assert_eq!(a.total(), (u64::MAX - 45, u64::MAX - 90).into_weight());

a.saturating_reduce((5, u64::MAX).into_weight(), Normal);
assert!(a.normal.is_zero());
assert_eq!(a.total(), (u64::MAX - 50, 10).into_weight());
}

#[test]
fn checked_accrue_works() {
let mut a = PerDispatchClass::default();

a.checked_accrue((1, 2).into_weight(), Normal).unwrap();
a.checked_accrue((3, 4).into_weight(), Operational).unwrap();
a.checked_accrue((5, 6).into_weight(), Mandatory).unwrap();
a.checked_accrue((7, 8).into_weight(), Operational).unwrap();
a.checked_accrue((9, 0).into_weight(), Normal).unwrap();

assert_eq!(
a,
PerDispatchClass {
normal: (10, 2).into_weight(),
operational: (10, 12).into_weight(),
mandatory: (5, 6).into_weight(),
}
);

a.checked_accrue((u64::MAX - 10, u64::MAX - 2).into_weight(), Normal).unwrap();
a.checked_accrue((0, 0).into_weight(), Normal).unwrap();
a.checked_accrue((1, 0).into_weight(), Normal).unwrap_err();
a.checked_accrue((0, 1).into_weight(), Normal).unwrap_err();

assert_eq!(
a,
PerDispatchClass {
normal: Weight::MAX,
operational: (10, 12).into_weight(),
mandatory: (5, 6).into_weight(),
}
);
}

#[test]
fn checked_accrue_does_not_modify_on_error() {
let mut a = PerDispatchClass {
normal: 0.into_weight(),
operational: Weight::MAX / 2 + 2.into_weight(),
mandatory: 10.into_weight(),
};

a.checked_accrue(Weight::MAX / 2, Operational).unwrap_err();
a.checked_accrue(Weight::MAX - 9.into_weight(), Mandatory).unwrap_err();
a.checked_accrue(Weight::MAX, Normal).unwrap(); // This one works

assert_eq!(
a,
PerDispatchClass {
normal: Weight::MAX,
operational: Weight::MAX / 2 + 2.into_weight(),
mandatory: 10.into_weight(),
}
);
}

#[test]
fn total_works() {
assert!(PerDispatchClass::default().total().is_zero());

assert_eq!(
PerDispatchClass {
normal: 0.into_weight(),
operational: (10, 20).into_weight(),
mandatory: (20, u64::MAX).into_weight(),
}
.total(),
(30, u64::MAX).into_weight()
);

assert_eq!(
PerDispatchClass {
normal: (u64::MAX - 10, 10).into_weight(),
operational: (3, u64::MAX).into_weight(),
mandatory: (4, u64::MAX).into_weight(),
}
.total(),
(u64::MAX - 3, u64::MAX).into_weight()
);
}
}
Loading