mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-11 14:11:09 +00:00
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:
@@ -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};
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
@@ -1062,7 +1062,6 @@ mod tests {
|
||||
).execute_using_consensus_failure_handler::<_, NeverNativeValue, fn() -> _>(
|
||||
ExecutionManager::Both(|we, _ne| {
|
||||
consensus_failed = true;
|
||||
println!("HELLO!");
|
||||
we
|
||||
}),
|
||||
true,
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
|
||||
@@ -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::*;
|
||||
|
||||
@@ -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"]
|
||||
|
||||
@@ -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)?;
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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))]
|
||||
|
||||
|
||||
@@ -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 );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user