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

Commit b0bc705

Browse files
kianenigmagavofyork
authored andcommitted
Weight annotation for block hooks. (#4058)
* Initial version that works with proper tests. * get rid of todos and grumbles and such. * Cleanup and fix line-width * fix test runtime test
1 parent f76ccb0 commit b0bc705

File tree

10 files changed

+339
-15
lines changed

10 files changed

+339
-15
lines changed

Cargo.lock

+2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

core/sr-primitives/Cargo.toml

+2
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ inherents = { package = "substrate-inherents", path = "../inherents", default-fe
2222
serde_json = "1.0.41"
2323
rand = "0.7.2"
2424
substrate-offchain = { path = "../offchain" }
25+
support = { package = "srml-support", path = "../../srml/support" }
26+
system = { package = "srml-system", path = "../../srml/system" }
2527

2628
[features]
2729
bench = []

core/sr-primitives/src/testing.rs

+11-1
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ pub type DigestItem = generic::DigestItem<H256>;
145145
pub type Digest = generic::Digest<H256>;
146146

147147
/// Block Header
148-
#[derive(PartialEq, Eq, Clone, Serialize, Debug, Encode, Decode)]
148+
#[derive(PartialEq, Eq, Clone, Serialize, Debug, Encode, Decode, Default)]
149149
#[serde(rename_all = "camelCase")]
150150
#[serde(deny_unknown_fields)]
151151
pub struct Header {
@@ -198,6 +198,16 @@ impl traits::Header for Header {
198198
}
199199
}
200200

201+
impl Header {
202+
/// A new header with the given number and default hash for all other fields.
203+
pub fn new_from_number(number: <Self as traits::Header>::Number) -> Self {
204+
Self {
205+
number,
206+
..Default::default()
207+
}
208+
}
209+
}
210+
201211
impl<'a> Deserialize<'a> for Header {
202212
fn deserialize<D: Deserializer<'a>>(de: D) -> Result<Self, D::Error> {
203213
let r = <Vec<u8>>::deserialize(de)?;

core/sr-primitives/src/weights.rs

+38-1
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,9 @@
3737
3838
#[cfg(feature = "std")]
3939
use serde::{Serialize, Deserialize};
40+
use impl_trait_for_tuples::impl_for_tuples;
4041
use codec::{Encode, Decode};
41-
use arithmetic::traits::Bounded;
42+
use arithmetic::traits::{Bounded, Zero};
4243
use crate::RuntimeDebug;
4344

4445
/// Re-export priority as type
@@ -62,6 +63,35 @@ pub trait ClassifyDispatch<T> {
6263
fn classify_dispatch(&self, target: T) -> DispatchClass;
6364
}
6465

66+
/// Means of determining the weight of a block's lifecycle hooks: on_initialize, on_finalize and
67+
/// such.
68+
pub trait WeighBlock<BlockNumber> {
69+
/// Return the weight of the block's on_initialize hook.
70+
fn on_initialize(_: BlockNumber) -> Weight { Zero::zero() }
71+
/// Return the weight of the block's on_finalize hook.
72+
fn on_finalize(_: BlockNumber) -> Weight { Zero::zero() }
73+
}
74+
75+
/// Maybe I can do something to remove the duplicate code here.
76+
#[impl_for_tuples(30)]
77+
impl<BlockNumber: Copy> WeighBlock<BlockNumber> for SingleModule {
78+
fn on_initialize(n: BlockNumber) -> Weight {
79+
let mut accumulated_weight: Weight = Zero::zero();
80+
for_tuples!(
81+
#( accumulated_weight = accumulated_weight.saturating_add(SingleModule::on_initialize(n)); )*
82+
);
83+
accumulated_weight
84+
}
85+
86+
fn on_finalize(n: BlockNumber) -> Weight {
87+
let mut accumulated_weight: Weight = Zero::zero();
88+
for_tuples!(
89+
#( accumulated_weight = accumulated_weight.saturating_add(SingleModule::on_finalize(n)); )*
90+
);
91+
accumulated_weight
92+
}
93+
}
94+
6595
/// A generalized group of dispatch types. This is only distinguishing normal, user-triggered transactions
6696
/// (`Normal`) and anything beyond which serves a higher purpose to the system (`Operational`).
6797
#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
@@ -181,3 +211,10 @@ impl Default for SimpleDispatchInfo {
181211
SimpleDispatchInfo::FixedNormal(10_000)
182212
}
183213
}
214+
215+
impl SimpleDispatchInfo {
216+
/// An _additive zero_ variant of SimpleDispatchInfo.
217+
pub fn zero() -> Self {
218+
Self::FixedNormal(0)
219+
}
220+
}

node/runtime/src/lib.rs

+33
Original file line numberDiff line numberDiff line change
@@ -697,6 +697,7 @@ impl_runtime_apis! {
697697
}
698698
}
699699
}
700+
700701
#[cfg(test)]
701702
mod tests {
702703
use super::*;
@@ -717,4 +718,36 @@ mod tests {
717718
let x = SubmitTransaction::default();
718719
is_submit_signed_transaction(x);
719720
}
721+
722+
#[test]
723+
fn block_hooks_weight_should_not_exceed_limits() {
724+
use sr_primitives::weights::WeighBlock;
725+
let check_for_block = |b| {
726+
let block_hooks_weight =
727+
<AllModules as WeighBlock<BlockNumber>>::on_initialize(b) +
728+
<AllModules as WeighBlock<BlockNumber>>::on_finalize(b);
729+
730+
assert_eq!(
731+
block_hooks_weight,
732+
0,
733+
"This test might fail simply because the value being compared to has increased to a \
734+
module declaring a new weight for a hook or call. In this case update the test and \
735+
happily move on.",
736+
);
737+
738+
// Invariant. Always must be like this to have a sane chain.
739+
assert!(block_hooks_weight < MaximumBlockWeight::get());
740+
741+
// Warning.
742+
if block_hooks_weight > MaximumBlockWeight::get() / 2 {
743+
println!(
744+
"block hooks weight is consuming more than a block's capacity. You probably want \
745+
to re-think this. This test will fail now."
746+
);
747+
assert!(false);
748+
}
749+
};
750+
751+
let _ = (0..100_000).for_each(check_for_block);
752+
}
720753
}

srml/example/src/lib.rs

+6-1
Original file line numberDiff line numberDiff line change
@@ -498,13 +498,18 @@ decl_module! {
498498
<Dummy<T>>::put(new_value);
499499
}
500500

501-
// The signature could also look like: `fn on_initialize()`
501+
// The signature could also look like: `fn on_initialize()`.
502+
// This function could also very well have a weight annotation, similar to any other. The
503+
// only difference being that if it is not annotated, the default is
504+
// `SimpleDispatchInfo::zero()`, which resolves into no weight.
505+
#[weight = SimpleDispatchInfo::FixedNormal(1000)]
502506
fn on_initialize(_n: T::BlockNumber) {
503507
// Anything that needs to be done at the start of the block.
504508
// We don't do anything here.
505509
}
506510

507511
// The signature could also look like: `fn on_finalize()`
512+
#[weight = SimpleDispatchInfo::FixedNormal(2000)]
508513
fn on_finalize(_n: T::BlockNumber) {
509514
// Anything that needs to be done at the end of the block.
510515
// We just kill our dummy storage item.

srml/executive/Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@ system = { package = "srml-system", path = "../system", default-features = false
1616
[dev-dependencies]
1717
hex-literal = "0.2.1"
1818
primitives = { package = "substrate-primitives", path = "../../core/primitives" }
19-
srml-indices = { path = "../indices" }
2019
balances = { package = "srml-balances", path = "../balances" }
20+
indices = { package = "srml-indices", path = "../indices" }
2121
transaction-payment = { package = "srml-transaction-payment", path = "../transaction-payment" }
2222

2323
[features]

srml/executive/src/lib.rs

+73-8
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,8 @@
7878

7979
use rstd::{prelude::*, marker::PhantomData};
8080
use sr_primitives::{
81-
generic::Digest, ApplyResult, weights::GetDispatchInfo,
81+
generic::Digest, ApplyResult,
82+
weights::{GetDispatchInfo, WeighBlock},
8283
traits::{
8384
self, Header, Zero, One, Checkable, Applyable, CheckEqual, OnFinalize, OnInitialize,
8485
NumberFor, Block as BlockT, OffchainWorker, Dispatchable,
@@ -110,7 +111,11 @@ impl<
110111
Block: traits::Block<Header=System::Header, Hash=System::Hash>,
111112
Context: Default,
112113
UnsignedValidator,
113-
AllModules: OnInitialize<System::BlockNumber> + OnFinalize<System::BlockNumber> + OffchainWorker<System::BlockNumber>,
114+
AllModules:
115+
OnInitialize<System::BlockNumber> +
116+
OnFinalize<System::BlockNumber> +
117+
OffchainWorker<System::BlockNumber> +
118+
WeighBlock<System::BlockNumber>,
114119
> ExecuteBlock<Block> for Executive<System, Block, Context, UnsignedValidator, AllModules>
115120
where
116121
Block::Extrinsic: Checkable<Context> + Codec,
@@ -130,7 +135,11 @@ impl<
130135
Block: traits::Block<Header=System::Header, Hash=System::Hash>,
131136
Context: Default,
132137
UnsignedValidator,
133-
AllModules: OnInitialize<System::BlockNumber> + OnFinalize<System::BlockNumber> + OffchainWorker<System::BlockNumber>,
138+
AllModules:
139+
OnInitialize<System::BlockNumber> +
140+
OnFinalize<System::BlockNumber> +
141+
OffchainWorker<System::BlockNumber> +
142+
WeighBlock<System::BlockNumber>,
134143
> Executive<System, Block, Context, UnsignedValidator, AllModules>
135144
where
136145
Block::Extrinsic: Checkable<Context> + Codec,
@@ -154,6 +163,12 @@ where
154163
) {
155164
<system::Module<System>>::initialize(block_number, parent_hash, extrinsics_root, digest);
156165
<AllModules as OnInitialize<System::BlockNumber>>::on_initialize(*block_number);
166+
<system::Module<System>>::register_extra_weight_unchecked(
167+
<AllModules as WeighBlock<System::BlockNumber>>::on_initialize(*block_number)
168+
);
169+
<system::Module<System>>::register_extra_weight_unchecked(
170+
<AllModules as WeighBlock<System::BlockNumber>>::on_finalize(*block_number)
171+
);
157172
}
158173

159174
fn initial_checks(block: &Block) {
@@ -309,12 +324,48 @@ mod tests {
309324
impl_outer_event, impl_outer_origin, parameter_types, impl_outer_dispatch,
310325
traits::{Currency, LockIdentifier, LockableCurrency, WithdrawReasons, WithdrawReason},
311326
};
312-
use system::Call as SystemCall;
327+
use system::{Call as SystemCall, ChainContext};
313328
use balances::Call as BalancesCall;
314329
use hex_literal::hex;
315330

331+
mod custom {
332+
use sr_primitives::weights::SimpleDispatchInfo;
333+
334+
pub trait Trait: system::Trait {}
335+
336+
support::decl_module! {
337+
pub struct Module<T: Trait> for enum Call where origin: T::Origin {
338+
#[weight = SimpleDispatchInfo::FixedNormal(100)]
339+
fn some_function(origin) {
340+
// NOTE: does not make any different.
341+
let _ = system::ensure_signed(origin);
342+
}
343+
#[weight = SimpleDispatchInfo::FixedOperational(200)]
344+
fn some_root_operation(origin) {
345+
let _ = system::ensure_root(origin);
346+
}
347+
#[weight = SimpleDispatchInfo::FreeNormal]
348+
fn some_unsigned_message(origin) {
349+
let _ = system::ensure_none(origin);
350+
}
351+
352+
// module hooks.
353+
// one with block number arg and one without
354+
#[weight = SimpleDispatchInfo::FixedNormal(25)]
355+
fn on_initialize(n: T::BlockNumber) {
356+
println!("on_initialize({})", n);
357+
}
358+
#[weight = SimpleDispatchInfo::FixedNormal(150)]
359+
fn on_finalize() {
360+
println!("on_finalize(?)");
361+
}
362+
}
363+
}
364+
}
365+
316366
type System = system::Module<Runtime>;
317367
type Balances = balances::Module<Runtime>;
368+
type Custom = custom::Module<Runtime>;
318369

319370
impl_outer_origin! {
320371
pub enum Origin for Runtime { }
@@ -386,6 +437,7 @@ mod tests {
386437
type WeightToFee = ConvertInto;
387438
type FeeMultiplierUpdate = ();
388439
}
440+
impl custom::Trait for Runtime {}
389441

390442
#[allow(deprecated)]
391443
impl ValidateUnsigned for Runtime {
@@ -409,8 +461,9 @@ mod tests {
409461
system::CheckWeight<Runtime>,
410462
transaction_payment::ChargeTransactionPayment<Runtime>
411463
);
464+
type AllModules = (System, Balances, Custom);
412465
type TestXt = sr_primitives::testing::TestXt<Call, SignedExtra>;
413-
type Executive = super::Executive<Runtime, Block<TestXt>, system::ChainContext<Runtime>, Runtime, ()>;
466+
type Executive = super::Executive<Runtime, Block<TestXt>, ChainContext<Runtime>, Runtime, AllModules>;
414467

415468
fn extra(nonce: u64, fee: u64) -> SignedExtra {
416469
(
@@ -534,7 +587,7 @@ mod tests {
534587
let xt = sr_primitives::testing::TestXt(sign_extra(1, 0, 0), Call::Balances(BalancesCall::transfer(33, 0)));
535588
let encoded = xt.encode();
536589
let encoded_len = encoded.len() as Weight;
537-
let limit = AvailableBlockRatio::get() * MaximumBlockWeight::get();
590+
let limit = AvailableBlockRatio::get() * MaximumBlockWeight::get() - 175;
538591
let num_to_exhaust_block = limit / encoded_len;
539592
t.execute_with(|| {
540593
Executive::initialize_block(&Header::new(
@@ -544,7 +597,8 @@ mod tests {
544597
[69u8; 32].into(),
545598
Digest::default(),
546599
));
547-
assert_eq!(<system::Module<Runtime>>::all_extrinsics_weight(), 0);
600+
// Initial block weight form the custom module.
601+
assert_eq!(<system::Module<Runtime>>::all_extrinsics_weight(), 175);
548602

549603
for nonce in 0..=num_to_exhaust_block {
550604
let xt = sr_primitives::testing::TestXt(
@@ -555,7 +609,7 @@ mod tests {
555609
assert!(res.is_ok());
556610
assert_eq!(
557611
<system::Module<Runtime>>::all_extrinsics_weight(),
558-
encoded_len * (nonce + 1),
612+
encoded_len * (nonce + 1) + 175,
559613
);
560614
assert_eq!(<system::Module<Runtime>>::extrinsic_index(), Some(nonce as u32 + 1));
561615
} else {
@@ -652,4 +706,15 @@ mod tests {
652706
execute_with_lock(WithdrawReasons::all());
653707
execute_with_lock(WithdrawReasons::except(WithdrawReason::TransactionPayment));
654708
}
709+
710+
#[test]
711+
fn block_hooks_weight_is_stored() {
712+
new_test_ext(0).execute_with(|| {
713+
714+
Executive::initialize_block(&Header::new_from_number(1));
715+
// NOTE: might need updates over time if system and balance introduce new weights. For
716+
// now only accounts for the custom module.
717+
assert_eq!(<system::Module<Runtime>>::all_extrinsics_weight(), 150 + 25);
718+
})
719+
}
655720
}

0 commit comments

Comments
 (0)