Skip to content
This repository was archived by the owner on Nov 15, 2023. It is now read-only.
Merged
22 changes: 11 additions & 11 deletions core/sr-primitives/src/generic/checked_extrinsic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ use crate::traits::{
self, Member, MaybeDisplay, SignedExtension, DispatchError, Dispatchable, DispatchResult,
ValidateUnsigned
};
use crate::weights::{Weigh, Weight};
use crate::weights::{GetDispatchInfo, DispatchInfo};
use crate::transaction_validity::TransactionValidity;

/// Definition of something that the external world might want to say; its
Expand Down Expand Up @@ -57,13 +57,13 @@ where
}

fn validate<U: ValidateUnsigned<Call=Self::Call>>(&self,
weight: crate::weights::Weight,
info: DispatchInfo,
len: usize,
) -> TransactionValidity {
if let Some((ref id, ref extra)) = self.signed {
Extra::validate(extra, id, weight, len).into()
Extra::validate(extra, id, info, len).into()
} else {
match Extra::validate_unsigned(weight, len) {
match Extra::validate_unsigned(info, len) {
Ok(extra) => match U::validate_unsigned(&self.function) {
TransactionValidity::Valid(v) =>
TransactionValidity::Valid(v.combine_with(extra)),
Expand All @@ -75,25 +75,25 @@ where
}

fn dispatch(self,
weight: crate::weights::Weight,
info: DispatchInfo,
len: usize,
) -> Result<DispatchResult, DispatchError> {
let maybe_who = if let Some((id, extra)) = self.signed {
Extra::pre_dispatch(extra, &id, weight, len)?;
Extra::pre_dispatch(extra, &id, info, len)?;
Some(id)
} else {
Extra::pre_dispatch_unsigned(weight, len)?;
Extra::pre_dispatch_unsigned(info, len)?;
None
};
Ok(self.function.dispatch(Origin::from(maybe_who)))
}
}

impl<AccountId, Call, Extra> Weigh for CheckedExtrinsic<AccountId, Call, Extra>
impl<AccountId, Call, Extra> GetDispatchInfo for CheckedExtrinsic<AccountId, Call, Extra>
where
Call: Weigh,
Call: GetDispatchInfo,
{
fn weigh(&self) -> Weight {
self.function.weigh()
fn get_dispatch_info(&self) -> DispatchInfo {
self.function.get_dispatch_info()
}
}
19 changes: 11 additions & 8 deletions core/sr-primitives/src/testing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ use crate::traits::{
ValidateUnsigned, SignedExtension, Dispatchable,
};
use crate::{generic, KeyTypeId};
use crate::weights::{Weigh, Weight};
use crate::weights::{GetDispatchInfo, DispatchInfo};
pub use substrate_primitives::H256;
use substrate_primitives::U256;
use substrate_primitives::ed25519::{Public as AuthorityId};
Expand Down Expand Up @@ -240,7 +240,7 @@ impl<Origin, Call, Extra> Applyable for TestXt<Call, Extra> where

/// Checks to see if this is a valid *transaction*. It returns information on it if so.
fn validate<U: ValidateUnsigned<Call=Self::Call>>(&self,
_weight: Weight,
_info: DispatchInfo,
_len: usize,
) -> TransactionValidity {
TransactionValidity::Valid(Default::default())
Expand All @@ -249,23 +249,26 @@ impl<Origin, Call, Extra> Applyable for TestXt<Call, Extra> where
/// Executes all necessary logic needed prior to dispatch and deconstructs into function call,
/// index and sender.
fn dispatch(self,
weight: Weight,
info: DispatchInfo,
len: usize,
) -> Result<DispatchResult, DispatchError> {
let maybe_who = if let Some(who) = self.0 {
Extra::pre_dispatch(self.2, &who, weight, len)?;
Extra::pre_dispatch(self.2, &who, info, len)?;
Some(who)
} else {
Extra::pre_dispatch_unsigned(weight, len)?;
Extra::pre_dispatch_unsigned(info, len)?;
None
};
Ok(self.1.dispatch(maybe_who.into()))
}
}

impl<Call, Extra> Weigh for TestXt<Call, Extra> {
fn weigh(&self) -> Weight {
impl<Call: Encode, Extra: Encode> GetDispatchInfo for TestXt<Call, Extra> {
fn get_dispatch_info(&self) -> DispatchInfo {
// for testing: weight == size.
self.0.using_encoded(|d| d.len() as Weight)
DispatchInfo {
weight: self.encode().len() as u32,
..Default::default()
}
}
}
34 changes: 18 additions & 16 deletions core/sr-primitives/src/traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ use substrate_primitives::{self, Hasher, Blake2Hasher};
use crate::codec::{Codec, Encode, Decode, HasCompact};
use crate::transaction_validity::{ValidTransaction, TransactionValidity};
use crate::generic::{Digest, DigestItem};
use crate::weights::DispatchInfo;
pub use substrate_primitives::crypto::TypedKey;
pub use integer_sqrt::IntegerSquareRoot;
pub use num_traits::{
Expand Down Expand Up @@ -752,6 +753,7 @@ impl<T: BlindCheckable, Context> Checkable<Context> for T {
/// An abstract error concerning an attempt to verify, check or dispatch the transaction. This
/// cannot be more concrete because it's designed to work reasonably well over a broad range of
/// possible transaction types.
#[cfg_attr(feature = "std", derive(Debug))]
pub enum DispatchError {
/// General error to do with the inability to pay some fees (e.g. account balance too low).
Payment,
Expand Down Expand Up @@ -825,31 +827,31 @@ pub trait SignedExtension:
fn validate(
&self,
_who: &Self::AccountId,
_weight: crate::weights::Weight,
_info: DispatchInfo,
_len: usize,
) -> Result<ValidTransaction, DispatchError> { Ok(Default::default()) }

/// Do any pre-flight stuff for a signed transaction.
fn pre_dispatch(
self,
who: &Self::AccountId,
weight: crate::weights::Weight,
info: DispatchInfo,
len: usize,
) -> Result<(), DispatchError> { self.validate(who, weight, len).map(|_| ()) }
) -> Result<(), DispatchError> { self.validate(who, info, len).map(|_| ()) }

/// Validate an unsigned transaction for the transaction queue. Normally the default
/// implementation is fine since `ValidateUnsigned` is a better way of recognising and
/// validating unsigned transactions.
fn validate_unsigned(
_weight: crate::weights::Weight,
_info: DispatchInfo,
_len: usize,
) -> Result<ValidTransaction, DispatchError> { Ok(Default::default()) }

/// Do any pre-flight stuff for a unsigned transaction.
fn pre_dispatch_unsigned(
weight: crate::weights::Weight,
info: DispatchInfo,
len: usize,
) -> Result<(), DispatchError> { Self::validate_unsigned(weight, len).map(|_| ()) }
) -> Result<(), DispatchError> { Self::validate_unsigned(info, len).map(|_| ()) }
}

macro_rules! tuple_impl_indexed {
Expand All @@ -869,33 +871,33 @@ macro_rules! tuple_impl_indexed {
fn validate(
&self,
who: &Self::AccountId,
weight: crate::weights::Weight,
info: DispatchInfo,
len: usize,
) -> Result<ValidTransaction, DispatchError> {
let aggregator = vec![$(<$direct as SignedExtension>::validate(&self.$index, who, weight, len)?),+];
let aggregator = vec![$(<$direct as SignedExtension>::validate(&self.$index, who, info, len)?),+];
Ok(aggregator.into_iter().fold(ValidTransaction::default(), |acc, a| acc.combine_with(a)))
}
fn pre_dispatch(
self,
who: &Self::AccountId,
weight: crate::weights::Weight,
info: DispatchInfo,
len: usize,
) -> Result<(), DispatchError> {
$(self.$index.pre_dispatch(who, weight, len)?;)+
$(self.$index.pre_dispatch(who, info, len)?;)+
Ok(())
}
fn validate_unsigned(
weight: crate::weights::Weight,
info: DispatchInfo,
len: usize,
) -> Result<ValidTransaction, DispatchError> {
let aggregator = vec![$($direct::validate_unsigned(weight, len)?),+];
let aggregator = vec![$($direct::validate_unsigned(info, len)?),+];
Ok(aggregator.into_iter().fold(ValidTransaction::default(), |acc, a| acc.combine_with(a)))
}
fn pre_dispatch_unsigned(
weight: crate::weights::Weight,
info: DispatchInfo,
len: usize,
) -> Result<(), DispatchError> {
$($direct::pre_dispatch_unsigned(weight, len)?;)+
$($direct::pre_dispatch_unsigned(info, len)?;)+
Ok(())
}
}
Expand Down Expand Up @@ -944,14 +946,14 @@ pub trait Applyable: Sized + Send + Sync {

/// Checks to see if this is a valid *transaction*. It returns information on it if so.
fn validate<V: ValidateUnsigned<Call=Self::Call>>(&self,
weight: crate::weights::Weight,
info: DispatchInfo,
len: usize,
) -> TransactionValidity;

/// Executes all necessary logic needed prior to dispatch and deconstructs into function call,
/// index and sender.
fn dispatch(self,
weight: crate::weights::Weight,
info: DispatchInfo,
len: usize,
) -> Result<DispatchResult, DispatchError>;
}
Expand Down
125 changes: 91 additions & 34 deletions core/sr-primitives/src/weights.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,26 +16,64 @@

//! 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
//! `Weigh` trait. By default, All transactions are annotated by
//! `#[weight = TransactionWeight::default()]`.
//! Each dispatch function within `decl_module!` can have an optional `#[weight = $x]` attribute.
//! `$x` can be any type that implements the `ClassifyDispatch<T>` and `WeighData<T>` traits. By
//! default, All transactions are annotated with `#[weight = SimpleDispatchInfo::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 use crate::transaction_validity::TransactionPriority;
use crate::traits::Bounded;

/// Numeric range of a transaction weight.
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 Weigh {
/// Return the weight of this call. This is done independently of its encoded size.
fn weigh(&self) -> Weight;
/// A broad range of dispatch types. This is only distinguishing normal, user-triggered transactions
/// and anything beyond which serves a higher purpose to the system (`OperationalNormal`).
#[cfg_attr(feature = "std", derive(Debug))]
#[derive(PartialEq, Eq, Clone, Copy)]
pub enum DispatchClass {
/// A normal dispatch.
User,
/// An operational dispatch.
Operational,
}

impl Default for DispatchClass {
fn default() -> Self {
DispatchClass::User
}
}

impl From<SimpleDispatchInfo> for DispatchClass {
fn from(tx: SimpleDispatchInfo) -> Self {
match tx {
SimpleDispatchInfo::OperationalNormal(_) => DispatchClass::Operational,
SimpleDispatchInfo::FixedNormal(_) => DispatchClass::User,
SimpleDispatchInfo::MaxNormal => DispatchClass::User,
SimpleDispatchInfo::FreeNormal => DispatchClass::User,
}
}
}

/// A bundle of static information collected from the `#[weight = $x]` attributes.
#[cfg_attr(feature = "std", derive(PartialEq, Eq, Debug))]
#[derive(Clone, Copy, Default)]
pub struct DispatchInfo {
/// Weight of this transaction.
pub weight: Weight,
/// Class of this transaction.
pub class: DispatchClass,
}

/// A `Dispatchable` function (aka transaction) that can carry some static information along with it, using the
/// `#[weight]` attribute.
pub trait GetDispatchInfo {
/// Return a `DispatchInfo`, containing relevant information of this dispatch.
///
/// This is done independently of its encoded size.
fn get_dispatch_info(&self) -> DispatchInfo;
}

/// Means of weighing some particular kind of data (`T`).
Expand All @@ -44,38 +82,57 @@ pub trait WeighData<T> {
fn weigh_data(&self, target: T) -> Weight;
}

/// Default type used as the weight representative in a `#[weight = x]` attribute.
/// Means of classifying a dispatchable function.
pub trait ClassifyDispatch<T> {
/// Classify the dispatch function based on input data `target` of type `T`.
fn classify_dispatch(&self, target: T) -> DispatchClass;
}

/// Default type used with the `#[weight = x]` attribute in a substrate chain.
///
/// A user may pass in any other type that implements [`Weigh`]. 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.
Fixed(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,
/// A user may pass in any other type that implements the correct traits. If not, the `Default`
/// implementation of [`SimpleDispatchInfo`] is used.
#[derive(Clone, Copy)]
pub enum SimpleDispatchInfo {
/// A fixed-weight dispatch function. No dependency on state or input.
FixedNormal(Weight),
/// An operational dispatch function. Still incurs a weight-fee but typically has a higher
/// priority.
OperationalNormal(Weight),
/// A dispatch function with the maximum possible weight. This means:
/// - The weight-fee will be maximum possible, based on the system state.
/// - This transaction will also have a high priority (but not guaranteed to be included.)
/// - If included, no more _normal_ dispatches will be permitted in that block. Operational
/// dispatches might be included nonetheless.
MaxNormal,
/// Free. The transaction does not increase the total weight. This means:
/// - No weight-fee is charged.
/// - Block weight is not increased (very likely to be included, but not guaranteed).
FreeNormal,
}

impl<T> WeighData<T> for TransactionWeight {
impl<T> WeighData<T> for SimpleDispatchInfo {
fn weigh_data(&self, _: T) -> Weight {
match self {
TransactionWeight::Fixed(w) => *w,
TransactionWeight::Max => 3 * 1024 * 1024,
TransactionWeight::Free => 0,
SimpleDispatchInfo::FixedNormal(w) => *w,
SimpleDispatchInfo::OperationalNormal(w) => *w,
SimpleDispatchInfo::MaxNormal => Bounded::max_value(),
SimpleDispatchInfo::FreeNormal => Bounded::min_value(),
}
}
}

impl Default for TransactionWeight {
impl<T> ClassifyDispatch<T> for SimpleDispatchInfo {
fn classify_dispatch(&self, _: T) -> DispatchClass {
DispatchClass::from(*self)
}
}

impl Default for SimpleDispatchInfo {
fn default() -> Self {
// This implies that the weight is currently equal to 100, nothing more
// for all substrate transactions that do NOT explicitly annotate weight.
// TODO #2431 needs to be updated with proper max values.
TransactionWeight::Fixed(1)
SimpleDispatchInfo::FixedNormal(1)
}
}
3 changes: 3 additions & 0 deletions node-template/runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ pub fn native_version() -> NativeVersion {
parameter_types! {
pub const BlockHashCount: BlockNumber = 250;
pub const MaximumBlockWeight: Weight = 4 * 1024 * 1024;
pub const MaximumBlockSize: u32 = 2 * 1024;
}

impl system::Trait for Runtime {
Expand All @@ -138,6 +139,8 @@ impl system::Trait for Runtime {
type BlockHashCount = BlockHashCount;
/// Maximum weight of each block. With a default weight system of 1byte == 1weight, 4mb is ok.
type MaximumBlockWeight = MaximumBlockWeight;
/// Maximum size of all encoded transactions (in bytes) that are allowed in one block.
type MaximumBlockSize = MaximumBlockSize;
}

impl aura::Trait for Runtime {
Expand Down
Loading