Extensible transactions (and tips) (#3102)

* Make extrinsics extensible.

Also Remove old extrinsic types.

* Rest of mockup. Add tips.

* Fix some build issues

* Runtiem builds :)

* Substrate builds.

* Fix a doc test

* Compact encoding

* Extract out the era logic into an extension

* Weight Check signed extension. (#3115)

* Weight signed extension.

* Revert a bit + test for check era.

* Update Cargo.toml

* Update node/cli/src/factory_impl.rs

* Update node/executor/src/lib.rs

* Update node/executor/src/lib.rs

* Don't use len for weight - use data.

* Operational Transaction; second attempt (#3138)

* working poc added.

* some fixes.

* Update doc.

* Fix all tests + final logic.

* more refactoring.

* nits.

* System block limit in bytes.

* Silent the storage macro warnings.

* More logic more tests.

* Fix import.

* Refactor names.

* Fix build.

* Update srml/balances/src/lib.rs

* Final refactor.

* Bump transaction version

* Fix weight mult test.

* Fix more tests and improve doc.

* Bump.

* Make some tests work again.

* Fix subkey.

* Remove todos + bump.

* Ignore expensive test.

* Bump.
This commit is contained in:
Gavin Wood
2019-07-23 01:06:49 +08:00
committed by Kian Peymani
parent 4f5654b67d
commit 78bc5edc14
55 changed files with 1965 additions and 1646 deletions
+130 -42
View File
@@ -17,8 +17,8 @@
//! Primitives for transaction weighting.
//!
//! Each dispatch function within `decl_module!` can 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()]`.
//! `$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
//! (something that does not implement `Weighable`) is passed in.
@@ -26,59 +26,147 @@
use crate::{Fixed64, traits::Saturating};
use crate::codec::{Encode, Decode};
/// 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;
/// Maximum block saturation: 4mb
pub const MAX_TRANSACTIONS_WEIGHT: u32 = 4 * 1024 * 1024;
/// Target block saturation: 25% of max block saturation = 1mb
pub const IDEAL_TRANSACTIONS_WEIGHT: u32 = MAX_TRANSACTIONS_WEIGHT / 4;
/// 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;
/// A generalized group of dispatch types. This is only distinguishing normal, user-triggered transactions
/// (`Normal`) and anything beyond which serves a higher purpose to the system (`Operational`).
#[cfg_attr(feature = "std", derive(Debug))]
#[derive(PartialEq, Eq, Clone, Copy)]
pub enum DispatchClass {
/// A normal dispatch.
Normal,
/// An operational dispatch.
Operational,
}
/// 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 Default for DispatchClass {
fn default() -> Self {
DispatchClass::Normal
}
}
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 From<SimpleDispatchInfo> for DispatchClass {
fn from(tx: SimpleDispatchInfo) -> Self {
match tx {
SimpleDispatchInfo::FixedOperational(_) => DispatchClass::Operational,
SimpleDispatchInfo::MaxOperational => DispatchClass::Operational,
SimpleDispatchInfo::FreeOperational => DispatchClass::Operational,
SimpleDispatchInfo::FixedNormal(_) => DispatchClass::Normal,
SimpleDispatchInfo::MaxNormal => DispatchClass::Normal,
SimpleDispatchInfo::FreeNormal => DispatchClass::Normal,
}
}
}
impl Default for TransactionWeight {
/// 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,
}
impl DispatchInfo {
/// Determine if this dispatch should pay the base length-related fee or not.
pub fn pay_length_fee(&self) -> bool {
match self.class {
DispatchClass::Normal => true,
// For now we assume all operational transactions don't pay the length fee.
DispatchClass::Operational => false,
}
}
}
/// 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`).
pub trait WeighData<T> {
/// Weigh the data `T` given by `target`.
fn weigh_data(&self, target: T) -> Weight;
}
/// 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 the correct traits. If not, the `Default`
/// implementation of [`SimpleDispatchInfo`] is used.
///
/// For each generalized group (`Normal` and `Operation`):
/// - A `Fixed` variant means weight fee is charged normally and the weight is the number
/// specified in the inner value of the variant.
/// - A `Free` variant is equal to `::Fixed(0)`. Note that this does not guarantee inclusion.
/// - A `Max` variant is equal to `::Fixed(Weight::max_value())`.
///
/// Based on the final weight value, based on the above variants:
/// - A _weight-fee_ is deducted.
/// - The block weight is consumed proportionally.
///
/// As for the generalized groups themselves:
/// - `Normal` variants will be assigned a priority proportional to their weight. They can only
/// consume a portion (1/4) of the maximum block resource limits.
/// - `Operational` variants will be assigned the maximum priority. They can potentially consume
/// the entire block resource limit.
#[derive(Clone, Copy)]
pub enum SimpleDispatchInfo {
/// A normal dispatch with fixed weight.
FixedNormal(Weight),
/// A normal dispatch with the maximum weight.
MaxNormal,
/// A normal dispatch with no weight.
FreeNormal,
/// An operational dispatch with fixed weight.
FixedOperational(Weight),
/// An operational dispatch with the maximum weight.
MaxOperational,
/// An operational dispatch with no weight.
FreeOperational,
}
impl<T> WeighData<T> for SimpleDispatchInfo {
fn weigh_data(&self, _: T) -> Weight {
match self {
SimpleDispatchInfo::FixedNormal(w) => *w,
SimpleDispatchInfo::MaxNormal => Bounded::max_value(),
SimpleDispatchInfo::FreeNormal => Bounded::min_value(),
SimpleDispatchInfo::FixedOperational(w) => *w,
SimpleDispatchInfo::MaxOperational => Bounded::max_value(),
SimpleDispatchInfo::FreeOperational => Bounded::min_value(),
}
}
}
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 tx-size, nothing more
// 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::Basic(0, 1)
SimpleDispatchInfo::FixedNormal(100)
}
}