Skip to content
This repository was archived by the owner on Nov 15, 2023. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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