diff --git a/substrate/core/consensus/rhd/src/lib.rs b/substrate/core/consensus/rhd/src/lib.rs index ca4b9120eb..4a3e03759b 100644 --- a/substrate/core/consensus/rhd/src/lib.rs +++ b/substrate/core/consensus/rhd/src/lib.rs @@ -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}; diff --git a/substrate/core/primitives/src/storage.rs b/substrate/core/primitives/src/storage.rs index 4746d230d0..bf3c19573d 100644 --- a/substrate/core/primitives/src/storage.rs +++ b/substrate/core/primitives/src/storage.rs @@ -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"; diff --git a/substrate/core/sr-primitives/src/generic/checked_extrinsic.rs b/substrate/core/sr-primitives/src/generic/checked_extrinsic.rs index c0548c26e5..ee43b3af2e 100644 --- a/substrate/core/sr-primitives/src/generic/checked_extrinsic.rs +++ b/substrate/core/sr-primitives/src/generic/checked_extrinsic.rs @@ -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 { pub function: Call, } -impl traits::Applyable - for CheckedExtrinsic +impl traits::Applyable for CheckedExtrinsic where AccountId: Member + MaybeDisplay, Index: Member + MaybeDisplay + SimpleArithmetic, @@ -55,3 +55,12 @@ where (self.function, self.signed.map(|x| x.0)) } } + +impl Weighable for CheckedExtrinsic +where + Call: Weighable, +{ + fn weight(&self, len: usize) -> Weight { + self.function.weight(len) + } +} diff --git a/substrate/core/sr-primitives/src/lib.rs b/substrate/core/sr-primitives/src/lib.rs index 55e03e47f3..56525991ae 100644 --- a/substrate/core/sr-primitives/src/lib.rs +++ b/substrate/core/sr-primitives/src/lib.rs @@ -38,6 +38,7 @@ use codec::{Encode, Decode}; #[cfg(feature = "std")] pub mod testing; +pub mod weights; pub mod traits; use traits::{SaturatedConversion, UniqueSaturatedInto}; diff --git a/substrate/core/sr-primitives/src/testing.rs b/substrate/core/sr-primitives/src/testing.rs index 18c65d011e..f9061d99dc 100644 --- a/substrate/core/sr-primitives/src/testing.rs +++ b/substrate/core/sr-primitives/src/testing.rs @@ -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 Applyable for TestXt where (self.2, self.0) } } +impl Weighable for TestXt { + fn weight(&self, len: usize) -> Weight { + // for testing: weight == size. + len as Weight + } +} diff --git a/substrate/core/sr-primitives/src/weights.rs b/substrate/core/sr-primitives/src/weights.rs new file mode 100644 index 0000000000..3443992c73 --- /dev/null +++ b/substrate/core/sr-primitives/src/weights.rs @@ -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 . + +//! 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) + } +} diff --git a/substrate/core/state-machine/src/lib.rs b/substrate/core/state-machine/src/lib.rs index 93d70423d5..2c98cc8a30 100644 --- a/substrate/core/state-machine/src/lib.rs +++ b/substrate/core/state-machine/src/lib.rs @@ -1062,7 +1062,6 @@ mod tests { ).execute_using_consensus_failure_handler::<_, NeverNativeValue, fn() -> _>( ExecutionManager::Both(|we, _ne| { consensus_failed = true; - println!("HELLO!"); we }), true, diff --git a/substrate/node/runtime/src/lib.rs b/substrate/node/runtime/src/lib.rs index 1c9c0ca4fd..25dbc6f205 100644 --- a/substrate/node/runtime/src/lib.rs +++ b/substrate/node/runtime/src/lib.rs @@ -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, }; diff --git a/substrate/srml/democracy/src/lib.rs b/substrate/srml/democracy/src/lib.rs index b6d032d791..6af6798b13 100644 --- a/substrate/srml/democracy/src/lib.rs +++ b/substrate/srml/democracy/src/lib.rs @@ -15,7 +15,7 @@ // along with Substrate. If not, see . //! Democratic system: Handles administration of general stakeholder voting. - +#![recursion_limit="128"] #![cfg_attr(not(feature = "std"), no_std)] use rstd::prelude::*; diff --git a/substrate/srml/example/Cargo.toml b/substrate/srml/example/Cargo.toml index 7601a799f8..44a6a85e47 100644 --- a/substrate/srml/example/Cargo.toml +++ b/substrate/srml/example/Cargo.toml @@ -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"] diff --git a/substrate/srml/example/src/lib.rs b/substrate/srml/example/src/lib.rs index 33c023ee8a..be441a3e57 100644 --- a/substrate/srml/example/src/lib.rs +++ b/substrate/srml/example/src/lib.rs @@ -16,7 +16,7 @@ //! # Example Module //! -//! +//! //! The Example: A simple example of a runtime module demonstrating //! concepts, APIs and structures common to most runtime modules. //! @@ -64,7 +64,7 @@ //! //! \## Overview //! -//! +//! //! // Short description of module purpose. //! // Links to Traits that should be implemented. //! // What this module is for. @@ -205,7 +205,7 @@ //! //! \```rust //! use ; -//! +//! //! pub trait Trait: ::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)?; diff --git a/substrate/srml/executive/src/lib.rs b/substrate/srml/executive/src/lib.rs index d1c22fcb6a..3707716183 100644 --- a/substrate/srml/executive/src/lib.rs +++ b/substrate/srml/executive/src/lib.rs @@ -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 for Executive where Block::Extrinsic: Checkable + Codec, - >::Checked: Applyable, + >::Checked: + Applyable + Weighable, <>::Checked as Applyable>::Call: Dispatchable, - <<>::Checked as Applyable>::Call as Dispatchable>::Origin: From>, + <<>::Checked as Applyable>::Call as Dispatchable>::Origin: + From>, UnsignedValidator: ValidateUnsigned>::Checked as Applyable>::Call> { fn execute_block(block: Block) { @@ -145,9 +148,11 @@ impl< > Executive where Block::Extrinsic: Checkable + Codec, - >::Checked: Applyable, + >::Checked: + Applyable + Weighable, <>::Checked as Applyable>::Call: Dispatchable, - <<>::Checked as Applyable>::Call as Dispatchable>::Origin: From>, + <<>::Checked as Applyable>::Call as Dispatchable>::Origin: + From>, UnsignedValidator: ValidateUnsigned>::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 + ) { >::initialize(block_number, parent_hash, extrinsics_root, digest); >::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() && >::block_hash(n - System::BlockNumber::one()) == *header.parent_hash(), + n > System::BlockNumber::zero() + && >::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_number: NumberFor) { + 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>) -> result::Result { + fn apply_extrinsic_with_len( + uxt: Block::Extrinsic, + encoded_len: usize, + to_note: Option> + ) -> result::Result { // 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 >::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 >::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!(>::all_extrinsics_len(), 0); + assert_eq!(>::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!(>::all_extrinsics_len(), 28); + assert_eq!(>::all_extrinsics_weight(), 28); assert_eq!(>::extrinsic_index(), Some(1)); } else { assert!(res.is_ok()); - assert_eq!(>::all_extrinsics_len(), 56); + assert_eq!(>::all_extrinsics_weight(), 56); assert_eq!(>::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!( + >::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)); diff --git a/substrate/srml/staking/src/lib.rs b/substrate/srml/staking/src/lib.rs index e76b73a749..0754985a6f 100644 --- a/substrate/srml/staking/src/lib.rs +++ b/substrate/srml/staking/src/lib.rs @@ -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))] diff --git a/substrate/srml/support/src/dispatch.rs b/substrate/srml/support/src/dispatch.rs index f2db609dc3..452e94227c 100644 --- a/substrate/srml/support/src/dispatch.rs +++ b/substrate/srml/support/src/dispatch.rs @@ -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 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: $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: $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: $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$(, $instance:ident: $instantiable:path $(= $module_default_instance:path)?)?> + pub struct $mod_type:ident< + $trait_instance:ident: + $trait_name:ident$(, $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$(, $instance: $instantiable $(= $module_default_instance)?)?> + pub struct $mod_type< + $trait_instance: $trait_name$(, $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$(, $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$(, $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: $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: $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$(, $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: $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$(, $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$(, $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$(, $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$(, $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 $(, $instance: $instantiable)?>; $( $offchain )* } - $crate::decl_module! { @impl_deposit_event $mod_type<$trait_instance: $trait_name $(, $instance: $instantiable)?>; @@ -951,6 +1010,18 @@ macro_rules! decl_module { )* } + // Implement weight calculation function for Call + impl<$trait_instance: $trait_name $(, $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 $(, $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() { as OnFinalize>::on_finalize(42); } + + #[test] + fn weight_should_attach_to_call_enum() { + // max weight. not dependent on input. + assert_eq!(Call::::weighted().weight(100), 3 * 1024 * 1024); + // default weight. + assert_eq!(Call::::aux_0().weight(5), 5 /*tx-len*/); + // custom basic + assert_eq!(Call::::aux_3().weight(5), 10 + 100 * 5 ); + } } diff --git a/substrate/srml/system/src/lib.rs b/substrate/srml/system/src/lib.rs index 276b389dc1..61db997cfc 100644 --- a/substrate/srml/system/src/lib.rs +++ b/substrate/srml/system/src/lib.rs @@ -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; - /// Total length in bytes for all extrinsics put together, for the current block. - AllExtrinsicsLen: Option; + /// Total weight for all extrinsics put together, for the current block. + AllExtrinsicsWeight: Option; /// 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 Module { >::get().unwrap_or_default() } - /// Gets a total length of all executed extrinsics. - pub fn all_extrinsics_len() -> u32 { - >::get().unwrap_or_default() + /// Gets a total weight of all executed extrinsics. + pub fn all_extrinsics_weight() -> u32 { + >::get().unwrap_or_default() } /// Start the execution of a particular block. @@ -563,7 +563,7 @@ impl Module { /// Remove temporary "environment" entries in storage. pub fn finalize() -> T::Header { >::kill(); - >::kill(); + >::kill(); let number = >::take(); let parent_hash = >::take(); @@ -714,10 +714,10 @@ impl Module { }.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); - >::put(&total_length); + >::put(&total_length); } /// To be called immediately after `note_applied_extrinsic` of the last extrinsic of the block