Per-transaction weight for srml (#2799)

* debug checkpoint.

* new

* Worked.

* Worked and weight propagated to executive.

* Works with some tests.

* Cleanup debug prints.

* More cleanup.

* Undo more logs.

* Undo a few more.

* Fix build.

* Allow len to be used in weight calculation.

* Remove noop function from dispath.

* Cleanup.

* Unify traits.

* Update docs and nits.

* line width

* Update core/sr-primitives/src/weights.rs

Co-Authored-By: Bastian Köcher <bkchr@users.noreply.github.com>

* Update core/sr-primitives/src/weights.rs

Co-Authored-By: Bastian Köcher <bkchr@users.noreply.github.com>

* Update core/sr-primitives/src/weights.rs

Co-Authored-By: Bastian Köcher <bkchr@users.noreply.github.com>

* Update core/sr-primitives/src/weights.rs

Co-Authored-By: Amar Singh <asinghchrony@protonmail.com>

* Update srml/example/src/lib.rs

Co-Authored-By: Bastian Köcher <bkchr@users.noreply.github.com>

* Final cleanup.

* Fix build.
This commit is contained in:
Kian Peymani
2019-06-12 14:38:30 +02:00
committed by GitHub
parent e53e9e9bda
commit 3496f11404
15 changed files with 288 additions and 54 deletions
+3
View File
@@ -32,6 +32,9 @@
#![cfg(feature="rhd")]
// FIXME #1020 doesn't compile
// NOTE: this is the legacy constant used for transaction size. No longer used except
// for the rhd code which is not updated. Placed here for compatibility.
const MAX_TRANSACTIONS_SIZE: u32 = 4 * 1024 * 1024;
use std::sync::Arc;
use std::sync::atomic::{AtomicUsize, Ordering};
-3
View File
@@ -73,9 +73,6 @@ pub mod well_known_keys {
/// Current extrinsic index (u32) is stored under this key.
pub const EXTRINSIC_INDEX: &'static [u8] = b":extrinsic_index";
/// Sum of all lengths of executed extrinsics (u32).
pub const ALL_EXTRINSICS_LEN: &'static [u8] = b":all_extrinsics_len";
/// Changes trie configuration is stored under this key.
pub const CHANGES_TRIE_CONFIG: &'static [u8] = b":changes_trie";
@@ -18,6 +18,7 @@
//! stage.
use crate::traits::{self, Member, SimpleArithmetic, MaybeDisplay};
use crate::weights::{Weighable, Weight};
/// Definition of something that the external world might want to say; its
/// existence implies that it has been checked and is good, particularly with
@@ -32,8 +33,7 @@ pub struct CheckedExtrinsic<AccountId, Index, Call> {
pub function: Call,
}
impl<AccountId, Index, Call> traits::Applyable
for CheckedExtrinsic<AccountId, Index, Call>
impl<AccountId, Index, Call> traits::Applyable for CheckedExtrinsic<AccountId, Index, Call>
where
AccountId: Member + MaybeDisplay,
Index: Member + MaybeDisplay + SimpleArithmetic,
@@ -55,3 +55,12 @@ where
(self.function, self.signed.map(|x| x.0))
}
}
impl<AccountId, Index, Call> Weighable for CheckedExtrinsic<AccountId, Index, Call>
where
Call: Weighable,
{
fn weight(&self, len: usize) -> Weight {
self.function.weight(len)
}
}
+1
View File
@@ -38,6 +38,7 @@ use codec::{Encode, Decode};
#[cfg(feature = "std")]
pub mod testing;
pub mod weights;
pub mod traits;
use traits::{SaturatedConversion, UniqueSaturatedInto};
@@ -20,6 +20,7 @@ use serde::{Serialize, Serializer, Deserialize, de::Error as DeError, Deserializ
use std::{fmt::Debug, ops::Deref, fmt};
use crate::codec::{Codec, Encode, Decode};
use crate::traits::{self, Checkable, Applyable, BlakeTwo256, Convert};
use crate::weights::{Weighable, Weight};
use crate::generic::DigestItem as GenDigestItem;
pub use substrate_primitives::H256;
use substrate_primitives::U256;
@@ -239,3 +240,9 @@ impl<Call> Applyable for TestXt<Call> where
(self.2, self.0)
}
}
impl<Call> Weighable for TestXt<Call> {
fn weight(&self, len: usize) -> Weight {
// for testing: weight == size.
len as Weight
}
}
@@ -0,0 +1,76 @@
// Copyright 2019 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/>.
//! Primitives for transaction weighting.
//!
//! Each dispatch function within `decl_module!` can now have an optional
//! `#[weight = $x]` attribute. $x can be any object that implements the
//! `Weighable` trait. By default, All transactions are annotated by
//! `#[weight = TransactionWeight::default()]`.
//!
//! Note that the decl_module macro _cannot_ enforce this and will simply fail
//! if an invalid struct is passed in.
/// The final type that each `#[weight = $x:expr]`'s
/// expression must evaluate to.
pub type Weight = u32;
/// A `Call` enum (aka transaction) that can be weighted using the custom weight attribute of
/// its dispatchable functions. Is implemented by default in the `decl_module!`.
///
/// Both the outer Call enum and the per-module individual ones will implement this.
/// The outer enum simply calls the inner ones based on call type.
pub trait Weighable {
/// Return the weight of this call.
/// The `len` argument is the encoded length of the transaction/call.
fn weight(&self, len: usize) -> Weight;
}
/// Default type used as the weight representative in a `#[weight = x]` attribute.
///
/// A user may pass in any other type that implements [`Weighable`]. If not, the `Default`
/// implementation of [`TransactionWeight`] is used.
pub enum TransactionWeight {
/// Basic weight (base, byte).
/// The values contained are the base weight and byte weight respectively.
Basic(Weight, Weight),
/// Maximum fee. This implies that this transaction _might_ get included but
/// no more transaction can be added. This can be done by setting the
/// implementation to _maximum block weight_.
Max,
/// Free. The transaction does not increase the total weight
/// (i.e. is not included in weight calculation).
Free,
}
impl Weighable for TransactionWeight {
fn weight(&self, len: usize) -> Weight {
match self {
TransactionWeight::Basic(base, byte) => base + byte * len as Weight,
TransactionWeight::Max => 3 * 1024 * 1024,
TransactionWeight::Free => 0,
}
}
}
impl Default for TransactionWeight {
fn default() -> Self {
// This implies that the weight is currently equal to tx-size, nothing more
// for all substrate transactions that do NOT explicitly annotate weight.
// TODO #2431 needs to be updated with proper max values.
TransactionWeight::Basic(0, 1)
}
}
-1
View File
@@ -1062,7 +1062,6 @@ mod tests {
).execute_using_consensus_failure_handler::<_, NeverNativeValue, fn() -> _>(
ExecutionManager::Both(|we, _ne| {
consensus_failed = true;
println!("HELLO!");
we
}),
true,
+1 -1
View File
@@ -58,7 +58,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion {
spec_name: create_runtime_str!("node"),
impl_name: create_runtime_str!("substrate-node"),
authoring_version: 10,
spec_version: 92,
spec_version: 93,
impl_version: 94,
apis: RUNTIME_API_VERSIONS,
};
+1 -1
View File
@@ -15,7 +15,7 @@
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
//! Democratic system: Handles administration of general stakeholder voting.
#![recursion_limit="128"]
#![cfg_attr(not(feature = "std"), no_std)]
use rstd::prelude::*;
+1 -1
View File
@@ -10,11 +10,11 @@ parity-codec = { version = "3.3", default-features = false }
srml-support = { path = "../support", default-features = false }
system = { package = "srml-system", path = "../system", default-features = false }
balances = { package = "srml-balances", path = "../balances", default-features = false }
sr-primitives = { path = "../../core/sr-primitives", default-features = false }
[dev-dependencies]
sr-io = { path = "../../core/sr-io" }
substrate-primitives = { path = "../../core/primitives" }
sr-primitives = { path = "../../core/sr-primitives" }
[features]
default = ["std"]
+18 -3
View File
@@ -16,7 +16,7 @@
//! # Example Module
//!
//! <!-- Original author of paragraph: @gavofyork -->
//! <!-- Original author of paragraph: @gavofyork -->
//! The Example: A simple example of a runtime module demonstrating
//! concepts, APIs and structures common to most runtime modules.
//!
@@ -64,7 +64,7 @@
//!
//! \## Overview
//!
//! <!-- Original author of paragraph: Various. See https://github.com/paritytech/substrate-developer-hub/issues/44 -->
//! <!-- Original author of paragraph: Various. See https://github.com/paritytech/substrate-developer-hub/issues/44 -->
//! // Short description of module purpose.
//! // Links to Traits that should be implemented.
//! // What this module is for.
@@ -205,7 +205,7 @@
//!
//! \```rust
//! use <INSERT_CUSTOM_MODULE_NAME>;
//!
//!
//! pub trait Trait: <INSERT_CUSTOM_MODULE_NAME>::Trait { }
//! \```
//!
@@ -251,6 +251,7 @@
use srml_support::{StorageValue, dispatch::Result, decl_module, decl_storage, decl_event};
use system::ensure_signed;
use sr_primitives::weights::TransactionWeight;
/// Our module's configuration trait. All our types and consts go in here. If the
/// module is dependent on specific other modules, then their configuration traits
@@ -388,6 +389,20 @@ decl_module! {
// no progress.
//
// If you don't respect these rules, it is likely that your chain will be attackable.
//
// Each transaction can optionally indicate a weight. The weight is passed in as a
// custom attribute and the value can be anything that implements the `Weighable`
// trait. Most often using substrate's default `TransactionWeight` is enough for you.
//
// A basic weight is a tuple of `(base_weight, byte_weight)`. Upon including each transaction
// in a block, the final weight is calculated as `base_weight + byte_weight * tx_size`.
// If this value, added to the weight of all included transactions, exceeds `MAX_TRANSACTION_WEIGHT`,
// the transaction is not included. If no weight attribute is provided, the `::default()`
// implementation of `TransactionWeight` is used.
//
// The example below showcases a transaction which is relatively costly, but less dependent on
// the input, hence `byte_weight` is configured smaller.
#[weight = TransactionWeight::Basic(100_000, 10)]
fn accumulate_dummy(origin, increase_by: T::Balance) -> Result {
// This is a public call, so we ensure that the origin is some signed account.
let _sender = ensure_signed(origin)?;
+49 -18
View File
@@ -82,14 +82,15 @@ use primitives::traits::{
OnInitialize, Digest, NumberFor, Block as BlockT, OffchainWorker,
ValidateUnsigned, DigestItem,
};
use primitives::weights::Weighable;
use primitives::{ApplyOutcome, ApplyError};
use primitives::transaction_validity::{TransactionValidity, TransactionPriority, TransactionLongevity};
use srml_support::{Dispatchable, traits::MakePayment};
use parity_codec::{Codec, Encode};
use system::extrinsics_root;
use primitives::{ApplyOutcome, ApplyError};
use primitives::transaction_validity::{TransactionValidity, TransactionPriority, TransactionLongevity};
mod internal {
pub const MAX_TRANSACTIONS_SIZE: u32 = 4 * 1024 * 1024;
pub const MAX_TRANSACTIONS_WEIGHT: u32 = 4 * 1024 * 1024;
pub enum ApplyError {
BadSignature(&'static str),
@@ -125,9 +126,11 @@ impl<
> ExecuteBlock<Block> for Executive<System, Block, Context, Payment, UnsignedValidator, AllModules>
where
Block::Extrinsic: Checkable<Context> + Codec,
<Block::Extrinsic as Checkable<Context>>::Checked: Applyable<Index=System::Index, AccountId=System::AccountId>,
<Block::Extrinsic as Checkable<Context>>::Checked:
Applyable<Index=System::Index, AccountId=System::AccountId> + Weighable,
<<Block::Extrinsic as Checkable<Context>>::Checked as Applyable>::Call: Dispatchable,
<<<Block::Extrinsic as Checkable<Context>>::Checked as Applyable>::Call as Dispatchable>::Origin: From<Option<System::AccountId>>,
<<<Block::Extrinsic as Checkable<Context>>::Checked as Applyable>::Call as Dispatchable>::Origin:
From<Option<System::AccountId>>,
UnsignedValidator: ValidateUnsigned<Call=<<Block::Extrinsic as Checkable<Context>>::Checked as Applyable>::Call>
{
fn execute_block(block: Block) {
@@ -145,9 +148,11 @@ impl<
> Executive<System, Block, Context, Payment, UnsignedValidator, AllModules>
where
Block::Extrinsic: Checkable<Context> + Codec,
<Block::Extrinsic as Checkable<Context>>::Checked: Applyable<Index=System::Index, AccountId=System::AccountId>,
<Block::Extrinsic as Checkable<Context>>::Checked:
Applyable<Index=System::Index, AccountId=System::AccountId> + Weighable,
<<Block::Extrinsic as Checkable<Context>>::Checked as Applyable>::Call: Dispatchable,
<<<Block::Extrinsic as Checkable<Context>>::Checked as Applyable>::Call as Dispatchable>::Origin: From<Option<System::AccountId>>,
<<<Block::Extrinsic as Checkable<Context>>::Checked as Applyable>::Call as Dispatchable>::Origin:
From<Option<System::AccountId>>,
UnsignedValidator: ValidateUnsigned<Call=<<Block::Extrinsic as Checkable<Context>>::Checked as Applyable>::Call>
{
/// Start the execution of a particular block.
@@ -157,7 +162,12 @@ where
Self::initialize_block_impl(header.number(), header.parent_hash(), header.extrinsics_root(), &digests);
}
fn initialize_block_impl(block_number: &System::BlockNumber, parent_hash: &System::Hash, extrinsics_root: &System::Hash, digest: &System::Digest) {
fn initialize_block_impl(
block_number: &System::BlockNumber,
parent_hash: &System::Hash,
extrinsics_root: &System::Hash,
digest: &System::Digest
) {
<system::Module<System>>::initialize(block_number, parent_hash, extrinsics_root, digest);
<AllModules as OnInitialize<System::BlockNumber>>::on_initialize(*block_number);
}
@@ -168,7 +178,8 @@ where
// Check that `parent_hash` is correct.
let n = header.number().clone();
assert!(
n > System::BlockNumber::zero() && <system::Module<System>>::block_hash(n - System::BlockNumber::one()) == *header.parent_hash(),
n > System::BlockNumber::zero()
&& <system::Module<System>>::block_hash(n - System::BlockNumber::one()) == *header.parent_hash(),
"Parent hash should be valid."
);
@@ -195,6 +206,7 @@ where
/// Execute given extrinsics and take care of post-extrinsics book-keeping.
fn execute_extrinsics_with_book_keeping(extrinsics: Vec<Block::Extrinsic>, block_number: NumberFor<Block>) {
extrinsics.into_iter().for_each(Self::apply_extrinsic_no_note);
// post-extrinsics book-keeping
@@ -244,12 +256,17 @@ where
}
/// Actually apply an extrinsic given its `encoded_len`; this doesn't note its hash.
fn apply_extrinsic_with_len(uxt: Block::Extrinsic, encoded_len: usize, to_note: Option<Vec<u8>>) -> result::Result<internal::ApplyOutcome, internal::ApplyError> {
fn apply_extrinsic_with_len(
uxt: Block::Extrinsic,
encoded_len: usize,
to_note: Option<Vec<u8>>
) -> result::Result<internal::ApplyOutcome, internal::ApplyError> {
// Verify that the signature is good.
let xt = uxt.check(&Default::default()).map_err(internal::ApplyError::BadSignature)?;
// Check the size of the block if that extrinsic is applied.
if <system::Module<System>>::all_extrinsics_len() + encoded_len as u32 > internal::MAX_TRANSACTIONS_SIZE {
// Check the weight of the block if that extrinsic is applied.
let weight = xt.weight(encoded_len);
if <system::Module<System>>::all_extrinsics_weight() + weight > internal::MAX_TRANSACTIONS_WEIGHT {
return Err(internal::ApplyError::FullBlock);
}
@@ -259,7 +276,6 @@ where
if index != &expected_index { return Err(
if index < &expected_index { internal::ApplyError::Stale } else { internal::ApplyError::Future }
) }
// pay any fees
Payment::make_payment(sender, encoded_len).map_err(|_| internal::ApplyError::CantPay)?;
@@ -534,27 +550,27 @@ mod tests {
}
#[test]
fn block_size_limit_enforced() {
fn block_weight_limit_enforced() {
let run_test = |should_fail: bool| {
let mut t = new_test_ext();
let xt = primitives::testing::TestXt(Some(1), 0, Call::transfer(33, 69));
let xt2 = primitives::testing::TestXt(Some(1), 1, Call::transfer(33, 69));
let encoded = xt2.encode();
let len = if should_fail { (internal::MAX_TRANSACTIONS_SIZE - 1) as usize } else { encoded.len() };
let len = if should_fail { (internal::MAX_TRANSACTIONS_WEIGHT - 1) as usize } else { encoded.len() };
with_externalities(&mut t, || {
Executive::initialize_block(&Header::new(1, H256::default(), H256::default(), [69u8; 32].into(), Digest::default()));
assert_eq!(<system::Module<Runtime>>::all_extrinsics_len(), 0);
assert_eq!(<system::Module<Runtime>>::all_extrinsics_weight(), 0);
Executive::apply_extrinsic(xt).unwrap();
let res = Executive::apply_extrinsic_with_len(xt2, len, Some(encoded));
if should_fail {
assert!(res.is_err());
assert_eq!(<system::Module<Runtime>>::all_extrinsics_len(), 28);
assert_eq!(<system::Module<Runtime>>::all_extrinsics_weight(), 28);
assert_eq!(<system::Module<Runtime>>::extrinsic_index(), Some(1));
} else {
assert!(res.is_ok());
assert_eq!(<system::Module<Runtime>>::all_extrinsics_len(), 56);
assert_eq!(<system::Module<Runtime>>::all_extrinsics_weight(), 56);
assert_eq!(<system::Module<Runtime>>::extrinsic_index(), Some(2));
}
});
@@ -564,6 +580,21 @@ mod tests {
run_test(true);
}
#[test]
fn default_block_weight() {
let xt = primitives::testing::TestXt(None, 0, Call::set_balance(33, 69, 69));
let mut t = new_test_ext();
with_externalities(&mut t, || {
Executive::apply_extrinsic(xt.clone()).unwrap();
Executive::apply_extrinsic(xt.clone()).unwrap();
Executive::apply_extrinsic(xt.clone()).unwrap();
assert_eq!(
<system::Module<Runtime>>::all_extrinsics_weight(),
3 * (0 /*base*/ + 22 /*len*/ * 1 /*byte*/)
);
});
}
#[test]
fn validate_unsigned() {
let xt = primitives::testing::TestXt(None, 0, Call::set_balance(33, 69, 69));
+1
View File
@@ -239,6 +239,7 @@
//! - [Session](../srml_session/index.html): Used to manage sessions. Also, a list of new validators is
//! stored in the Session module's `Validators` at the end of each era.
#![recursion_limit="128"]
#![cfg_attr(not(feature = "std"), no_std)]
#![cfg_attr(all(feature = "bench", test), feature(test))]
+111 -16
View File
@@ -23,6 +23,7 @@ pub use std::fmt;
pub use crate::rstd::result;
pub use crate::codec::{Codec, Decode, Encode, Input, Output, HasCompact, EncodeAsRef};
pub use srml_metadata::{FunctionMetadata, DecodeDifferent, DecodeDifferentArray, FunctionArgumentMetadata};
pub use sr_primitives::weights::{TransactionWeight, Weighable, Weight};
/// A type that cannot be instantiated.
pub enum Never {}
@@ -200,8 +201,7 @@ impl<T> Parameter for T where T: Codec + Clone + Eq {}
/// [`OffchainWorker`](../sr_primitives/traits/trait.OffchainWorker.html) trait.
#[macro_export]
macro_rules! decl_module {
// Macro transformations (to convert invocations with incomplete parameters to the canonical
// form)
// Entry point #1.
(
$(#[$attr:meta])*
pub struct $mod_type:ident<$trait_instance:ident: $trait_name:ident$(<I>, I: $instantiable:path $(= $module_default_instance:path)?)?>
@@ -221,6 +221,7 @@ macro_rules! decl_module {
$($t)*
);
};
// Entry point #2.
(
$(#[$attr:meta])*
pub struct $mod_type:ident<$trait_instance:ident: $trait_name:ident$(<I>, I: $instantiable:path $(= $module_default_instance:path)?)?>
@@ -241,6 +242,7 @@ macro_rules! decl_module {
);
};
// Normalization expansions. Fills the defaults.
(@normalize
$(#[$attr:meta])*
pub struct $mod_type:ident<$trait_instance:ident: $trait_name:ident$(<I>, I: $instantiable:path $(= $module_default_instance:path)?)?>
@@ -402,9 +404,13 @@ macro_rules! decl_module {
$($rest)*
);
};
// This puts the function statement into the [], decreasing `$rest` and moving toward finishing the parse.
(@normalize
$(#[$attr:meta])*
pub struct $mod_type:ident<$trait_instance:ident: $trait_name:ident$(<I>, $instance:ident: $instantiable:path $(= $module_default_instance:path)?)?>
pub struct $mod_type:ident<
$trait_instance:ident:
$trait_name:ident$(<I>, $instance:ident: $instantiable:path $(= $module_default_instance:path)?)?
>
for enum $call_type:ident where origin: $origin_type:ty, system = $system:ident
{ $( $deposit_event:tt )* }
{ $( $on_initialize:tt )* }
@@ -412,6 +418,7 @@ macro_rules! decl_module {
{ $( $offchain:tt )* }
[ $($t:tt)* ]
$(#[doc = $doc_attr:tt])*
#[weight = $weight:expr]
$fn_vis:vis fn $fn_name:ident(
$origin:ident $(, $(#[$codec_attr:ident])* $param_name:ident : $param:ty)*
) $( -> $result:ty )* { $( $impl:tt )* }
@@ -419,7 +426,9 @@ macro_rules! decl_module {
) => {
$crate::decl_module!(@normalize
$(#[$attr])*
pub struct $mod_type<$trait_instance: $trait_name$(<I>, $instance: $instantiable $(= $module_default_instance)?)?>
pub struct $mod_type<
$trait_instance: $trait_name$(<I>, $instance: $instantiable $(= $module_default_instance)?)?
>
for enum $call_type where origin: $origin_type, system = $system
{ $( $deposit_event )* }
{ $( $on_initialize )* }
@@ -428,6 +437,7 @@ macro_rules! decl_module {
[
$($t)*
$(#[doc = $doc_attr])*
#[weight = $weight]
$fn_vis fn $fn_name(
$origin $( , $(#[$codec_attr])* $param_name : $param )*
) $( -> $result )* { $( $impl )* }
@@ -436,6 +446,45 @@ macro_rules! decl_module {
$($rest)*
);
};
// Add #[weight] if none is defined.
(@normalize
$(#[$attr:meta])*
pub struct $mod_type:ident<
$trait_instance:ident:
$trait_name:ident$(<I>, $instance:ident: $instantiable:path $(= $module_default_instance:path)?)?
>
for enum $call_type:ident where origin: $origin_type:ty, system = $system:ident
{ $( $deposit_event:tt )* }
{ $( $on_initialize:tt )* }
{ $( $on_finalize:tt )* }
{ $( $offchain:tt )* }
[ $($t:tt)* ]
$(#[doc = $doc_attr:tt])*
$fn_vis:vis fn $fn_name:ident(
$from:ident $(, $(#[$codec_attr:ident])* $param_name:ident : $param:ty)*
) $( -> $result:ty )* { $( $impl:tt )* }
$($rest:tt)*
) => {
$crate::decl_module!(@normalize
$(#[$attr])*
pub struct $mod_type<
$trait_instance: $trait_name$(<I>, $instance: $instantiable $(= $module_default_instance)?)?
>
for enum $call_type where origin: $origin_type, system = $system
{ $( $deposit_event )* }
{ $( $on_initialize )* }
{ $( $on_finalize )* }
{ $( $offchain )* }
[ $($t)* ]
$(#[doc = $doc_attr])*
#[weight = $crate::dispatch::TransactionWeight::default()]
$fn_vis fn $fn_name(
$from $(, $(#[$codec_attr])* $param_name : $param )*
) $( -> $result )* { $( $impl )* }
$($rest)*
);
};
// Ignore any ident which is not `origin` with type `T::Origin`.
(@normalize
$(#[$attr:meta])*
pub struct $mod_type:ident<$trait_instance:ident: $trait_name:ident$(<I>, I: $instantiable:path $(= $module_default_instance:path)?)?>
@@ -446,6 +495,7 @@ macro_rules! decl_module {
{ $( $offchain:tt )* }
[ $($t:tt)* ]
$(#[doc = $doc_attr:tt])*
$(#[weight = $weight:expr])?
$fn_vis:vis fn $fn_name:ident(
$origin:ident : T::Origin $(, $(#[$codec_attr:ident])* $param_name:ident : $param:ty)*
) $( -> $result:ty )* { $( $impl:tt )* }
@@ -457,6 +507,7 @@ macro_rules! decl_module {
not use the `T::Origin` type.)"
)
};
// Ignore any ident which is `origin` but has a type, regardless of the type token itself.
(@normalize
$(#[$attr:meta])*
pub struct $mod_type:ident<$trait_instance:ident: $trait_name:ident$(<I>, I: $instantiable:path $(= $module_default_instance:path)?)?>
@@ -467,6 +518,7 @@ macro_rules! decl_module {
{ $( $offchain:tt )* }
[ $($t:tt)* ]
$(#[doc = $doc_attr:tt])*
$(#[weight = $weight:expr])?
$fn_vis:vis fn $fn_name:ident(
origin : $origin:ty $(, $(#[$codec_attr:ident])* $param_name:ident : $param:ty)*
) $( -> $result:ty )* { $( $impl:tt )* }
@@ -478,6 +530,7 @@ macro_rules! decl_module {
not use the `T::Origin` type.)"
)
};
// Add root if no origin is defined.
(@normalize
$(#[$attr:meta])*
pub struct $mod_type:ident<$trait_instance:ident: $trait_name:ident$(<I>, $instance:ident: $instantiable:path $(= $module_default_instance:path)?)?>
@@ -488,6 +541,7 @@ macro_rules! decl_module {
{ $( $offchain:tt )* }
[ $($t:tt)* ]
$(#[doc = $doc_attr:tt])*
$(#[weight = $weight:expr])?
$fn_vis:vis fn $fn_name:ident(
$( $(#[$codec_attr:ident])* $param_name:ident : $param:ty),*
) $( -> $result:ty )* { $( $impl:tt )* }
@@ -501,17 +555,18 @@ macro_rules! decl_module {
{ $( $on_initialize )* }
{ $( $on_finalize )* }
{ $( $offchain )* }
[
$($t)*
$(#[doc = $doc_attr])*
$fn_vis fn $fn_name(
root $( , $(#[$codec_attr])* $param_name : $param )*
) $( -> $result )* { $( $impl )* }
{ $($instance: $instantiable)? }
]
[ $($t)* ]
$(#[doc = $doc_attr])*
$(#[weight = $weight])?
$fn_vis fn $fn_name(
root $( , $(#[$codec_attr])* $param_name : $param )*
) $( -> $result )* { $( $impl )* }
$($rest)*
);
};
// Last normalize step. Triggers `@imp` expansion which is the real expansion.
(@normalize
$(#[$attr:meta])*
pub struct $mod_type:ident<$trait_instance:ident: $trait_name:ident$(<I>, I: $instantiable:path $(= $module_default_instance:path)?)?>
@@ -686,6 +741,7 @@ macro_rules! decl_module {
{}
};
// Expansion for root dispatch functions with no specified result type.
(@impl_function
$module:ident<$trait_instance:ident: $trait_name:ident$(<I>, $instance:ident: $instantiable:path)?>;
$origin_ty:ty;
@@ -700,6 +756,7 @@ macro_rules! decl_module {
}
};
// Expansion for root dispatch functions with explicit return types.
(@impl_function
$module:ident<$trait_instance:ident: $trait_name:ident$(<I>, $instance:ident: $instantiable:path)?>;
$origin_ty:ty;
@@ -715,6 +772,7 @@ macro_rules! decl_module {
}
};
// Expansion for _origin_ dispatch functions with no return type.
(@impl_function
$module:ident<$trait_instance:ident: $trait_name:ident$(<I>, $instance:ident: $instantiable:path)?>;
$origin_ty:ty;
@@ -733,6 +791,7 @@ macro_rules! decl_module {
}
};
// Expansion for _origin_ dispatch functions with explicit return type.
(@impl_function
$module:ident<$trait_instance:ident: $trait_name:ident$(<I>, $instance:ident: $instantiable:path)?>;
$origin_ty:ty;
@@ -868,6 +927,7 @@ macro_rules! decl_module {
for enum $call_type:ident where origin: $origin_type:ty, system = $system:ident {
$(
$(#[doc = $doc_attr:tt])*
#[weight = $weight:expr]
$fn_vis:vis fn $fn_name:ident(
$from:ident $( , $(#[$codec_attr:ident])* $param_name:ident : $param:ty)*
) $( -> $result:ty )* { $( $impl:tt )* }
@@ -908,7 +968,6 @@ macro_rules! decl_module {
$mod_type<$trait_instance: $trait_name $(<I>, $instance: $instantiable)?>;
$( $offchain )*
}
$crate::decl_module! {
@impl_deposit_event
$mod_type<$trait_instance: $trait_name $(<I>, $instance: $instantiable)?>;
@@ -951,6 +1010,18 @@ macro_rules! decl_module {
)*
}
// Implement weight calculation function for Call
impl<$trait_instance: $trait_name $(<I>, $instance: $instantiable)?> $crate::dispatch::Weighable
for $call_type<$trait_instance $(, $instance)?>
{
fn weight(&self, _len: usize) -> $crate::dispatch::Weight {
match self {
$( $call_type::$fn_name(..) => $crate::dispatch::Weighable::weight(&$weight, _len), )*
$call_type::__PhantomItem(_, _) => { unreachable!("__PhantomItem should never be used.") },
}
}
}
// manual implementation of clone/eq/partialeq because using derive erroneously requires
// clone/eq/partialeq from T.
impl<$trait_instance: $trait_name $(<I>, $instance: $instantiable)?> $crate::dispatch::Clone
@@ -1072,14 +1143,19 @@ macro_rules! impl_outer_dispatch {
$camelcase ( $crate::dispatch::CallableCallFor<$camelcase> )
,)*
}
impl $crate::dispatch::Weighable for $call_type {
fn weight(&self, len: usize) -> $crate::dispatch::Weight {
match self {
$( $call_type::$camelcase(call) => call.weight(len), )*
}
}
}
impl $crate::dispatch::Dispatchable for $call_type {
type Origin = $origin;
type Trait = $call_type;
fn dispatch(self, origin: $origin) -> $crate::dispatch::Result {
match self {
$(
$call_type::$camelcase(call) => call.dispatch(origin),
)*
$( $call_type::$camelcase(call) => call.dispatch(origin), )*
}
}
}
@@ -1271,6 +1347,7 @@ mod tests {
fn aux_0(_origin) -> Result { unreachable!() }
fn aux_1(_origin, #[compact] _data: u32) -> Result { unreachable!() }
fn aux_2(_origin, _data: i32, _data2: String) -> Result { unreachable!() }
#[weight = TransactionWeight::Basic(10, 100)]
fn aux_3() -> Result { unreachable!() }
fn aux_4(_data: i32) -> Result { unreachable!() }
fn aux_5(_origin, _data: i32, #[compact] _data2: u32) -> Result { unreachable!() }
@@ -1278,6 +1355,9 @@ mod tests {
fn on_initialize(n: T::BlockNumber) { if n.into() == 42 { panic!("on_initialize") } }
fn on_finalize(n: T::BlockNumber) { if n.into() == 42 { panic!("on_finalize") } }
fn offchain_worker() {}
#[weight = TransactionWeight::Max]
fn weighted() { unreachable!() }
}
}
@@ -1342,6 +1422,11 @@ mod tests {
]),
documentation: DecodeDifferent::Encode(&[]),
},
FunctionMetadata {
name: DecodeDifferent::Encode("weighted"),
arguments: DecodeDifferent::Encode(&[]),
documentation: DecodeDifferent::Encode(&[]),
},
];
struct TraitImpl {}
@@ -1396,4 +1481,14 @@ mod tests {
fn on_finalize_should_work() {
<Module<TraitImpl> as OnFinalize<u32>>::on_finalize(42);
}
#[test]
fn weight_should_attach_to_call_enum() {
// max weight. not dependent on input.
assert_eq!(Call::<TraitImpl>::weighted().weight(100), 3 * 1024 * 1024);
// default weight.
assert_eq!(Call::<TraitImpl>::aux_0().weight(5), 5 /*tx-len*/);
// custom basic
assert_eq!(Call::<TraitImpl>::aux_3().weight(5), 10 + 100 * 5 );
}
}
+8 -8
View File
@@ -315,8 +315,8 @@ decl_storage! {
pub AccountNonce get(account_nonce): map T::AccountId => T::Index;
/// Total extrinsics count for the current block.
ExtrinsicCount: Option<u32>;
/// Total length in bytes for all extrinsics put together, for the current block.
AllExtrinsicsLen: Option<u32>;
/// Total weight for all extrinsics put together, for the current block.
AllExtrinsicsWeight: Option<u32>;
/// Map of block numbers to block hashes.
pub BlockHash get(block_hash) build(|_| vec![(T::BlockNumber::zero(), hash69())]): map T::BlockNumber => T::Hash;
/// Extrinsics data for the current block (maps an extrinsic's index to its data).
@@ -530,9 +530,9 @@ impl<T: Trait> Module<T> {
<ExtrinsicCount<T>>::get().unwrap_or_default()
}
/// Gets a total length of all executed extrinsics.
pub fn all_extrinsics_len() -> u32 {
<AllExtrinsicsLen<T>>::get().unwrap_or_default()
/// Gets a total weight of all executed extrinsics.
pub fn all_extrinsics_weight() -> u32 {
<AllExtrinsicsWeight<T>>::get().unwrap_or_default()
}
/// Start the execution of a particular block.
@@ -563,7 +563,7 @@ impl<T: Trait> Module<T> {
/// Remove temporary "environment" entries in storage.
pub fn finalize() -> T::Header {
<ExtrinsicCount<T>>::kill();
<AllExtrinsicsLen<T>>::kill();
<AllExtrinsicsWeight<T>>::kill();
let number = <Number<T>>::take();
let parent_hash = <ParentHash<T>>::take();
@@ -714,10 +714,10 @@ impl<T: Trait> Module<T> {
}.into());
let next_extrinsic_index = Self::extrinsic_index().unwrap_or_default() + 1u32;
let total_length = encoded_len.saturating_add(Self::all_extrinsics_len());
let total_length = encoded_len.saturating_add(Self::all_extrinsics_weight());
storage::unhashed::put(well_known_keys::EXTRINSIC_INDEX, &next_extrinsic_index);
<AllExtrinsicsLen<T>>::put(&total_length);
<AllExtrinsicsWeight<T>>::put(&total_length);
}
/// To be called immediately after `note_applied_extrinsic` of the last extrinsic of the block