Skip to content
This repository was archived by the owner on Nov 15, 2023. It is now read-only.
Merged
16 changes: 8 additions & 8 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::{Weigh, TransactionInfo};
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: crate::weights::TransactionInfo,
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,14 +75,14 @@ where
}

fn dispatch(self,
weight: crate::weights::Weight,
info: crate::weights::TransactionInfo,
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)))
Expand All @@ -93,7 +93,7 @@ impl<AccountId, Call, Extra> Weigh for CheckedExtrinsic<AccountId, Call, Extra>
where
Call: Weigh,
{
fn weigh(&self) -> Weight {
fn weigh(&self) -> TransactionInfo {
self.function.weigh()
}
}
17 changes: 10 additions & 7 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::{Weigh, TransactionInfo};
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: TransactionInfo,
_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: TransactionInfo,
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 {
fn weigh(&self) -> TransactionInfo {
// for testing: weight == size.
self.0.using_encoded(|d| d.len() as Weight)
TransactionInfo {
weight: self.0.using_encoded(|d| d.len() as u32),
..Default::default()
}
}
}
32 changes: 16 additions & 16 deletions core/sr-primitives/src/traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -825,31 +825,31 @@ pub trait SignedExtension:
fn validate(
&self,
_who: &Self::AccountId,
_weight: crate::weights::Weight,
_info: crate::weights::TransactionInfo,
_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: crate::weights::TransactionInfo,
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: crate::weights::TransactionInfo,
_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: crate::weights::TransactionInfo,
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 +869,33 @@ macro_rules! tuple_impl_indexed {
fn validate(
&self,
who: &Self::AccountId,
weight: crate::weights::Weight,
info: crate::weights::TransactionInfo,
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: crate::weights::TransactionInfo,
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: crate::weights::TransactionInfo,
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: crate::weights::TransactionInfo,
len: usize,
) -> Result<(), DispatchError> {
$($direct::pre_dispatch_unsigned(weight, len)?;)+
$($direct::pre_dispatch_unsigned(info, len)?;)+
Ok(())
}
}
Expand Down Expand Up @@ -944,14 +944,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: crate::weights::TransactionInfo,
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: crate::weights::TransactionInfo,
len: usize,
) -> Result<DispatchResult, DispatchError>;
}
Expand Down
83 changes: 63 additions & 20 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 object that implements the `ClassifyDispatch<T>` and `WeighData<T>` traits. 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 use crate::transaction_validity::TransactionPriority;

/// Numeric range of a transaction weight.
pub type Weight = u32;

/// 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 (`Operational`).
#[derive(Clone, Copy)]
pub enum DispatchClass {
/// A normal dispatch.
User,
/// An operational dispatch.
Operational,
}

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

impl From<&TransactionWeight> for DispatchClass {
fn from(tx: &TransactionWeight) -> Self {
match *tx {
TransactionWeight::Operational(_) => DispatchClass::Operational,
TransactionWeight::Fixed(_) => DispatchClass::User,
}
}
}

/// A bundle of static meta information collected from the `#[weight = $x]` tags.
#[derive(Clone, Copy, Default)]
pub struct TransactionInfo {
/// Weight of this transaction.
pub weight: Weight,
/// Class of this transaction.
pub class: DispatchClass,
}

/// 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.
// TODO: rename this to sth that says: this traits returns a bunch of static meta-information about
// the tx, including but NOT only weight. Also rename #[weight] to #[meta]?
pub trait Weigh {
/// Return the weight of this call. This is done independently of its encoded size.
fn weigh(&self) -> Weight;
/// Return the `TransactionInfo` static information of this call.
///
/// This is done independently of its encoded size.
fn weigh(&self) -> TransactionInfo;
}

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

/// Means of classifying a transaction.
pub trait ClassifyDispatch<T> {
/// Classify transaction based on input data `target`.
fn class(&self, target: T) -> DispatchClass;
}

/// Default type used as the weight representative in a `#[weight = x]` attribute.
///
/// A user may pass in any other type that implements [`Weigh`]. If not, the `Default`
/// A user may pass in any other type that implements the correct traits. 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.
/// A fixed-weight transaction. No dependency on state or input.
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,
/// An operational transaction.
Operational(Weight),
}

impl<T> WeighData<T> for TransactionWeight {
fn weigh_data(&self, _: T) -> Weight {
match self {
TransactionWeight::Fixed(w) => *w,
TransactionWeight::Max => 3 * 1024 * 1024,
TransactionWeight::Free => 0,
TransactionWeight::Operational(w) => *w,
}
}
}

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

impl Default for TransactionWeight {
fn default() -> Self {
// This implies that the weight is currently equal to 100, nothing more
Expand Down
5 changes: 3 additions & 2 deletions srml/balances/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1167,7 +1167,7 @@ impl<T: Trait<I>, I: Instance> rstd::fmt::Debug for TakeFees<T, I> {

use primitives::traits::{DispatchError, SaturatedConversion};
use primitives::transaction_validity::ValidTransaction;
use primitives::weights::Weight;
use primitives::weights::TransactionInfo;

impl<T: Trait<I>, I: Instance + Clone + Eq> SignedExtension for TakeFees<T, I> {
type AccountId = T::AccountId;
Expand All @@ -1177,9 +1177,10 @@ impl<T: Trait<I>, I: Instance + Clone + Eq> SignedExtension for TakeFees<T, I> {
fn validate(
&self,
who: &Self::AccountId,
weight: Weight,
info: TransactionInfo,
_len: usize,
) -> rstd::result::Result<ValidTransaction, DispatchError> {
let weight = info.weight;
let fee_x = T::Balance::from(weight);
// TODO: should be weight_and_size_to_fee(weight, _len)
let fee = T::TransactionBaseFee::get() + T::TransactionByteFee::get() * fee_x;
Expand Down
15 changes: 2 additions & 13 deletions srml/example/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -396,19 +396,8 @@ decl_module! {
//
// 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 `Weigh`
// 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)]
// TODO: update weight doc.
#[weight = TransactionWeight::Fixed(0)]
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)?;
Expand Down
8 changes: 4 additions & 4 deletions srml/executive/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -284,8 +284,8 @@ where
// AUDIT: Under no circumstances may this function panic from here onwards.

// Decode parameters and dispatch
let weight = xt.weigh();
let r = Applyable::dispatch(xt, weight, encoded_len)
let transaction_info = xt.weigh();
let r = Applyable::dispatch(xt, transaction_info, encoded_len)
.map_err(internal::ApplyError::from)?;

<system::Module<System>>::note_applied_extrinsic(&r, encoded_len as u32);
Expand Down Expand Up @@ -339,8 +339,8 @@ where
Err(_) => return TransactionValidity::Invalid(UNKNOWN_ERROR),
};

let weight = xt.weigh();
xt.validate::<UnsignedValidator>(weight, encoded_len)
let transaction_info = xt.weigh();
xt.validate::<UnsignedValidator>(transaction_info, encoded_len)
}

/// Start an offchain worker and generate extrinsics.
Expand Down
Loading