FRAME: Create TransactionExtension as a replacement for SignedExtension (#2280)

Closes #2160

First part of [Extrinsic
Horizon](https://github.com/paritytech/polkadot-sdk/issues/2415)

Introduces a new trait `TransactionExtension` to replace
`SignedExtension`. Introduce the idea of transactions which obey the
runtime's extensions and have according Extension data (né Extra data)
yet do not have hard-coded signatures.

Deprecate the terminology of "Unsigned" when used for
transactions/extrinsics owing to there now being "proper" unsigned
transactions which obey the extension framework and "old-style" unsigned
which do not. Instead we have __*General*__ for the former and
__*Bare*__ for the latter. (Ultimately, the latter will be phased out as
a type of transaction, and Bare will only be used for Inherents.)

Types of extrinsic are now therefore:
- Bare (no hardcoded signature, no Extra data; used to be known as
"Unsigned")
- Bare transactions (deprecated): Gossiped, validated with
`ValidateUnsigned` (deprecated) and the `_bare_compat` bits of
`TransactionExtension` (deprecated).
  - Inherents: Not gossiped, validated with `ProvideInherent`.
- Extended (Extra data): Gossiped, validated via `TransactionExtension`.
  - Signed transactions (with a hardcoded signature).
  - General transactions (without a hardcoded signature).

`TransactionExtension` differs from `SignedExtension` because:
- A signature on the underlying transaction may validly not be present.
- It may alter the origin during validation.
- `pre_dispatch` is renamed to `prepare` and need not contain the checks
present in `validate`.
- `validate` and `prepare` is passed an `Origin` rather than a
`AccountId`.
- `validate` may pass arbitrary information into `prepare` via a new
user-specifiable type `Val`.
- `AdditionalSigned`/`additional_signed` is renamed to
`Implicit`/`implicit`. It is encoded *for the entire transaction* and
passed in to each extension as a new argument to `validate`. This
facilitates the ability of extensions to acts as underlying crypto.

There is a new `DispatchTransaction` trait which contains only default
function impls and is impl'ed for any `TransactionExtension` impler. It
provides several utility functions which reduce some of the tedium from
using `TransactionExtension` (indeed, none of its regular functions
should now need to be called directly).

Three transaction version discriminator ("versions") are now
permissible:
- 0b000000100: Bare (used to be called "Unsigned"): contains Signature
or Extra (extension data). After bare transactions are no longer
supported, this will strictly identify an Inherents only.
- 0b100000100: Old-school "Signed" Transaction: contains Signature and
Extra (extension data).
- 0b010000100: New-school "General" Transaction: contains Extra
(extension data), but no Signature.

For the New-school General Transaction, it becomes trivial for authors
to publish extensions to the mechanism for authorizing an Origin, e.g.
through new kinds of key-signing schemes, ZK proofs, pallet state,
mutations over pre-authenticated origins or any combination of the
above.

## Code Migration

### NOW: Getting it to build

Wrap your `SignedExtension`s in `AsTransactionExtension`. This should be
accompanied by renaming your aggregate type in line with the new
terminology. E.g. Before:

```rust
/// The SignedExtension to the basic transaction logic.
pub type SignedExtra = (
	/* snip */
	MySpecialSignedExtension,
);
/// Unchecked extrinsic type as expected by this runtime.
pub type UncheckedExtrinsic =
	generic::UncheckedExtrinsic<Address, RuntimeCall, Signature, SignedExtra>;
```

After:

```rust
/// The extension to the basic transaction logic.
pub type TxExtension = (
	/* snip */
	AsTransactionExtension<MySpecialSignedExtension>,
);
/// Unchecked extrinsic type as expected by this runtime.
pub type UncheckedExtrinsic =
	generic::UncheckedExtrinsic<Address, RuntimeCall, Signature, TxExtension>;
```

You'll also need to alter any transaction building logic to add a
`.into()` to make the conversion happen. E.g. Before:

```rust
fn construct_extrinsic(
		/* snip */
) -> UncheckedExtrinsic {
	let extra: SignedExtra = (
		/* snip */
		MySpecialSignedExtension::new(/* snip */),
	);
	let payload = SignedPayload::new(call.clone(), extra.clone()).unwrap();
	let signature = payload.using_encoded(|e| sender.sign(e));
	UncheckedExtrinsic::new_signed(
		/* snip */
		Signature::Sr25519(signature),
		extra,
	)
}
```

After:

```rust
fn construct_extrinsic(
		/* snip */
) -> UncheckedExtrinsic {
	let tx_ext: TxExtension = (
		/* snip */
		MySpecialSignedExtension::new(/* snip */).into(),
	);
	let payload = SignedPayload::new(call.clone(), tx_ext.clone()).unwrap();
	let signature = payload.using_encoded(|e| sender.sign(e));
	UncheckedExtrinsic::new_signed(
		/* snip */
		Signature::Sr25519(signature),
		tx_ext,
	)
}
```

### SOON: Migrating to `TransactionExtension`

Most `SignedExtension`s can be trivially converted to become a
`TransactionExtension`. There are a few things to know.

- Instead of a single trait like `SignedExtension`, you should now
implement two traits individually: `TransactionExtensionBase` and
`TransactionExtension`.
- Weights are now a thing and must be provided via the new function `fn
weight`.

#### `TransactionExtensionBase`

This trait takes care of anything which is not dependent on types
specific to your runtime, most notably `Call`.

- `AdditionalSigned`/`additional_signed` is renamed to
`Implicit`/`implicit`.
- Weight must be returned by implementing the `weight` function. If your
extension is associated with a pallet, you'll probably want to do this
via the pallet's existing benchmarking infrastructure.

#### `TransactionExtension`

Generally:
- `pre_dispatch` is now `prepare` and you *should not reexecute the
`validate` functionality in there*!
- You don't get an account ID any more; you get an origin instead. If
you need to presume an account ID, then you can use the trait function
`AsSystemOriginSigner::as_system_origin_signer`.
- You get an additional ticket, similar to `Pre`, called `Val`. This
defines data which is passed from `validate` into `prepare`. This is
important since you should not be duplicating logic from `validate` to
`prepare`, you need a way of passing your working from the former into
the latter. This is it.
- This trait takes two type parameters: `Call` and `Context`. `Call` is
the runtime call type which used to be an associated type; you can just
move it to become a type parameter for your trait impl. `Context` is not
currently used and you can safely implement over it as an unbounded
type.
- There's no `AccountId` associated type any more. Just remove it.

Regarding `validate`:
- You get three new parameters in `validate`; all can be ignored when
migrating from `SignedExtension`.
- `validate` returns a tuple on success; the second item in the tuple is
the new ticket type `Self::Val` which gets passed in to `prepare`. If
you use any information extracted during `validate` (off-chain and
on-chain, non-mutating) in `prepare` (on-chain, mutating) then you can
pass it through with this. For the tuple's last item, just return the
`origin` argument.

Regarding `prepare`:
- This is renamed from `pre_dispatch`, but there is one change:
- FUNCTIONALITY TO VALIDATE THE TRANSACTION NEED NOT BE DUPLICATED FROM
`validate`!!
- (This is different to `SignedExtension` which was required to run the
same checks in `pre_dispatch` as in `validate`.)

Regarding `post_dispatch`:
- Since there are no unsigned transactions handled by
`TransactionExtension`, `Pre` is always defined, so the first parameter
is `Self::Pre` rather than `Option<Self::Pre>`.

If you make use of `SignedExtension::validate_unsigned` or
`SignedExtension::pre_dispatch_unsigned`, then:
- Just use the regular versions of these functions instead.
- Have your logic execute in the case that the `origin` is `None`.
- Ensure your transaction creation logic creates a General Transaction
rather than a Bare Transaction; this means having to include all
`TransactionExtension`s' data.
- `ValidateUnsigned` can still be used (for now) if you need to be able
to construct transactions which contain none of the extension data,
however these will be phased out in stage 2 of the Transactions Horizon,
so you should consider moving to an extension-centric design.

## TODO

- [x] Introduce `CheckSignature` impl of `TransactionExtension` to
ensure it's possible to have crypto be done wholly in a
`TransactionExtension`.
- [x] Deprecate `SignedExtension` and move all uses in codebase to
`TransactionExtension`.
  - [x] `ChargeTransactionPayment`
  - [x] `DummyExtension`
  - [x] `ChargeAssetTxPayment` (asset-tx-payment)
  - [x] `ChargeAssetTxPayment` (asset-conversion-tx-payment)
  - [x] `CheckWeight`
  - [x] `CheckTxVersion`
  - [x] `CheckSpecVersion`
  - [x] `CheckNonce`
  - [x] `CheckNonZeroSender`
  - [x] `CheckMortality`
  - [x] `CheckGenesis`
  - [x] `CheckOnlySudoAccount`
  - [x] `WatchDummy`
  - [x] `PrevalidateAttests`
  - [x] `GenericSignedExtension`
  - [x] `SignedExtension` (chain-polkadot-bulletin)
  - [x] `RefundSignedExtensionAdapter`
- [x] Implement `fn weight` across the board.
- [ ] Go through all pre-existing extensions which assume an account
signer and explicitly handle the possibility of another kind of origin.
- [x] `CheckNonce` should probably succeed in the case of a non-account
origin.
- [x] `CheckNonZeroSender` should succeed in the case of a non-account
origin.
- [x] `ChargeTransactionPayment` and family should fail in the case of a
non-account origin.
  - [ ] 
- [x] Fix any broken tests.

---------

Signed-off-by: georgepisaltu <george.pisaltu@parity.io>
Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>
Signed-off-by: dependabot[bot] <support@github.com>
Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>
Signed-off-by: Alexandru Gheorghe <alexandru.gheorghe@parity.io>
Signed-off-by: Andrei Sandu <andrei-mihail@parity.io>
Co-authored-by: Nikhil Gupta <17176722+gupnik@users.noreply.github.com>
Co-authored-by: georgepisaltu <52418509+georgepisaltu@users.noreply.github.com>
Co-authored-by: Chevdor <chevdor@users.noreply.github.com>
Co-authored-by: Bastian Köcher <git@kchr.de>
Co-authored-by: Maciej <maciej.zyszkiewicz@parity.io>
Co-authored-by: Javier Viola <javier@parity.io>
Co-authored-by: Marcin S. <marcin@realemail.net>
Co-authored-by: Tsvetomir Dimitrov <tsvetomir@parity.io>
Co-authored-by: Javier Bullrich <javier@bullrich.dev>
Co-authored-by: Koute <koute@users.noreply.github.com>
Co-authored-by: Adrian Catangiu <adrian@parity.io>
Co-authored-by: Vladimir Istyufeev <vladimir@parity.io>
Co-authored-by: Ross Bulat <ross@parity.io>
Co-authored-by: Gonçalo Pestana <g6pestana@gmail.com>
Co-authored-by: Liam Aharon <liam.aharon@hotmail.com>
Co-authored-by: Svyatoslav Nikolsky <svyatonik@gmail.com>
Co-authored-by: André Silva <123550+andresilva@users.noreply.github.com>
Co-authored-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>
Co-authored-by: s0me0ne-unkn0wn <48632512+s0me0ne-unkn0wn@users.noreply.github.com>
Co-authored-by: ordian <write@reusable.software>
Co-authored-by: Sebastian Kunert <skunert49@gmail.com>
Co-authored-by: Aaro Altonen <48052676+altonen@users.noreply.github.com>
Co-authored-by: Dmitry Markin <dmitry@markin.tech>
Co-authored-by: Alexandru Vasile <60601340+lexnv@users.noreply.github.com>
Co-authored-by: Alexander Samusev <41779041+alvicsam@users.noreply.github.com>
Co-authored-by: Julian Eager <eagr@tutanota.com>
Co-authored-by: Michal Kucharczyk <1728078+michalkucharczyk@users.noreply.github.com>
Co-authored-by: Davide Galassi <davxy@datawok.net>
Co-authored-by: Dónal Murray <donal.murray@parity.io>
Co-authored-by: yjh <yjh465402634@gmail.com>
Co-authored-by: Tom Mi <tommi@niemi.lol>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Will | Paradox | ParaNodes.io <79228812+paradox-tt@users.noreply.github.com>
Co-authored-by: Bastian Köcher <info@kchr.de>
Co-authored-by: Joshy Orndorff <JoshOrndorff@users.noreply.github.com>
Co-authored-by: Joshy Orndorff <git-user-email.h0ly5@simplelogin.com>
Co-authored-by: PG Herveou <pgherveou@gmail.com>
Co-authored-by: Alexander Theißen <alex.theissen@me.com>
Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com>
Co-authored-by: Juan Girini <juangirini@gmail.com>
Co-authored-by: bader y <ibnbassem@gmail.com>
Co-authored-by: James Wilson <james@jsdw.me>
Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com>
Co-authored-by: asynchronous rob <rphmeier@gmail.com>
Co-authored-by: Parth <desaiparth08@gmail.com>
Co-authored-by: Andrew Jones <ascjones@gmail.com>
Co-authored-by: Jonathan Udd <jonathan@dwellir.com>
Co-authored-by: Serban Iorga <serban@parity.io>
Co-authored-by: Egor_P <egor@parity.io>
Co-authored-by: Branislav Kontur <bkontur@gmail.com>
Co-authored-by: Evgeny Snitko <evgeny@parity.io>
Co-authored-by: Just van Stam <vstam1@users.noreply.github.com>
Co-authored-by: Francisco Aguirre <franciscoaguirreperez@gmail.com>
Co-authored-by: gupnik <nikhilgupta.iitk@gmail.com>
Co-authored-by: dzmitry-lahoda <dzmitry@lahoda.pro>
Co-authored-by: zhiqiangxu <652732310@qq.com>
Co-authored-by: Nazar Mokrynskyi <nazar@mokrynskyi.com>
Co-authored-by: Anwesh <anweshknayak@gmail.com>
Co-authored-by: cheme <emericchevalier.pro@gmail.com>
Co-authored-by: Sam Johnson <sam@durosoft.com>
Co-authored-by: kianenigma <kian@parity.io>
Co-authored-by: Jegor Sidorenko <5252494+jsidorenko@users.noreply.github.com>
Co-authored-by: Muharem <ismailov.m.h@gmail.com>
Co-authored-by: joepetrowski <joe@parity.io>
Co-authored-by: Alexandru Gheorghe <49718502+alexggh@users.noreply.github.com>
Co-authored-by: Gabriel Facco de Arruda <arrudagates@gmail.com>
Co-authored-by: Squirrel <gilescope@gmail.com>
Co-authored-by: Andrei Sandu <54316454+sandreim@users.noreply.github.com>
Co-authored-by: georgepisaltu <george.pisaltu@parity.io>
Co-authored-by: command-bot <>
This commit is contained in:
Gavin Wood
2024-03-04 20:12:43 +01:00
committed by GitHub
parent b0741d4f78
commit fd5f9292f5
349 changed files with 25581 additions and 17082 deletions
@@ -18,81 +18,115 @@
//! Generic implementation of an extrinsic that has passed the verification
//! stage.
use codec::Encode;
use crate::{
traits::{
self, DispatchInfoOf, Dispatchable, MaybeDisplay, Member, PostDispatchInfoOf,
SignedExtension, ValidateUnsigned,
self, transaction_extension::TransactionExtension, DispatchInfoOf, DispatchTransaction,
Dispatchable, MaybeDisplay, Member, PostDispatchInfoOf, ValidateUnsigned,
},
transaction_validity::{TransactionSource, TransactionValidity},
};
/// The kind of extrinsic this is, including any fields required of that kind. This is basically
/// the full extrinsic except the `Call`.
#[derive(PartialEq, Eq, Clone, sp_core::RuntimeDebug)]
pub enum ExtrinsicFormat<AccountId, Extension> {
/// Extrinsic is bare; it must pass either the bare forms of `TransactionExtension` or
/// `ValidateUnsigned`, both deprecated, or alternatively a `ProvideInherent`.
Bare,
/// Extrinsic has a default `Origin` of `Signed(AccountId)` and must pass all
/// `TransactionExtension`s regular checks and includes all extension data.
Signed(AccountId, Extension),
/// Extrinsic has a default `Origin` of `None` and must pass all `TransactionExtension`s.
/// regular checks and includes all extension data.
General(Extension),
}
// TODO: Rename ValidateUnsigned to ValidateInherent
// TODO: Consider changing ValidateInherent API to avoid need for duplicating validate
// code into pre_dispatch (rename that to `prepare`).
// TODO: New extrinsic type corresponding to `ExtrinsicFormat::General`, which is
// unsigned but includes extension data.
// TODO: Move usage of `signed` to `format`:
// - Inherent instead of None.
// - Signed(id, extension) instead of Some((id, extra)).
// - Introduce General(extension) for one without a signature.
/// Definition of something that the external world might want to say; its existence implies that it
/// has been checked and is good, particularly with regards to the signature.
///
/// This is typically passed into [`traits::Applyable::apply`], which should execute
/// [`CheckedExtrinsic::function`], alongside all other bits and bobs.
#[derive(PartialEq, Eq, Clone, sp_core::RuntimeDebug)]
pub struct CheckedExtrinsic<AccountId, Call, Extra> {
pub struct CheckedExtrinsic<AccountId, Call, Extension> {
/// Who this purports to be from and the number of extrinsics have come before
/// from the same signer, if anyone (note this is not a signature).
pub signed: Option<(AccountId, Extra)>,
pub format: ExtrinsicFormat<AccountId, Extension>,
/// The function that should be called.
pub function: Call,
}
impl<AccountId, Call, Extra, RuntimeOrigin> traits::Applyable
for CheckedExtrinsic<AccountId, Call, Extra>
impl<AccountId, Call, Extension, RuntimeOrigin> traits::Applyable
for CheckedExtrinsic<AccountId, Call, Extension>
where
AccountId: Member + MaybeDisplay,
Call: Member + Dispatchable<RuntimeOrigin = RuntimeOrigin>,
Extra: SignedExtension<AccountId = AccountId, Call = Call>,
Call: Member + Dispatchable<RuntimeOrigin = RuntimeOrigin> + Encode,
Extension: TransactionExtension<Call, ()>,
RuntimeOrigin: From<Option<AccountId>>,
{
type Call = Call;
fn validate<U: ValidateUnsigned<Call = Self::Call>>(
fn validate<I: ValidateUnsigned<Call = Self::Call>>(
&self,
// TODO [#5006;ToDr] should source be passed to `SignedExtension`s?
// Perhaps a change for 2.0 to avoid breaking too much APIs?
source: TransactionSource,
info: &DispatchInfoOf<Self::Call>,
len: usize,
) -> TransactionValidity {
if let Some((ref id, ref extra)) = self.signed {
Extra::validate(extra, id, &self.function, info, len)
} else {
let valid = Extra::validate_unsigned(&self.function, info, len)?;
let unsigned_validation = U::validate_unsigned(source, &self.function)?;
Ok(valid.combine_with(unsigned_validation))
match self.format {
ExtrinsicFormat::Bare => {
let inherent_validation = I::validate_unsigned(source, &self.function)?;
#[allow(deprecated)]
let legacy_validation = Extension::validate_bare_compat(&self.function, info, len)?;
Ok(legacy_validation.combine_with(inherent_validation))
},
ExtrinsicFormat::Signed(ref signer, ref extension) => {
let origin = Some(signer.clone()).into();
extension.validate_only(origin, &self.function, info, len).map(|x| x.0)
},
ExtrinsicFormat::General(ref extension) =>
extension.validate_only(None.into(), &self.function, info, len).map(|x| x.0),
}
}
fn apply<U: ValidateUnsigned<Call = Self::Call>>(
fn apply<I: ValidateUnsigned<Call = Self::Call>>(
self,
info: &DispatchInfoOf<Self::Call>,
len: usize,
) -> crate::ApplyExtrinsicResultWithInfo<PostDispatchInfoOf<Self::Call>> {
let (maybe_who, maybe_pre) = if let Some((id, extra)) = self.signed {
let pre = Extra::pre_dispatch(extra, &id, &self.function, info, len)?;
(Some(id), Some(pre))
} else {
Extra::pre_dispatch_unsigned(&self.function, info, len)?;
U::pre_dispatch(&self.function)?;
(None, None)
};
let res = self.function.dispatch(RuntimeOrigin::from(maybe_who));
let post_info = match res {
Ok(info) => info,
Err(err) => err.post_info,
};
Extra::post_dispatch(
maybe_pre,
info,
&post_info,
len,
&res.map(|_| ()).map_err(|e| e.error),
)?;
Ok(res)
match self.format {
ExtrinsicFormat::Bare => {
I::pre_dispatch(&self.function)?;
// TODO: Remove below once `pre_dispatch_unsigned` is removed from `LegacyExtension`
// or `LegacyExtension` is removed.
#[allow(deprecated)]
Extension::validate_bare_compat(&self.function, info, len)?;
#[allow(deprecated)]
Extension::pre_dispatch_bare_compat(&self.function, info, len)?;
let res = self.function.dispatch(None.into());
let post_info = res.unwrap_or_else(|err| err.post_info);
let pd_res = res.map(|_| ()).map_err(|e| e.error);
// TODO: Remove below once `pre_dispatch_unsigned` is removed from `LegacyExtension`
// or `LegacyExtension` is removed.
#[allow(deprecated)]
Extension::post_dispatch_bare_compat(info, &post_info, len, &pd_res)?;
Ok(res)
},
ExtrinsicFormat::Signed(signer, extension) =>
extension.dispatch_transaction(Some(signer).into(), self.function, info, len),
ExtrinsicFormat::General(extension) =>
extension.dispatch_transaction(None.into(), self.function, info, len),
}
}
}
@@ -29,9 +29,9 @@ mod unchecked_extrinsic;
pub use self::{
block::{Block, BlockId, SignedBlock},
checked_extrinsic::CheckedExtrinsic,
checked_extrinsic::{CheckedExtrinsic, ExtrinsicFormat},
digest::{Digest, DigestItem, DigestItemRef, OpaqueDigestItemId},
era::{Era, Phase},
header::Header,
unchecked_extrinsic::{SignedPayload, UncheckedExtrinsic},
unchecked_extrinsic::{Preamble, SignedPayload, UncheckedExtrinsic},
};
File diff suppressed because it is too large Load Diff
+14 -5
View File
@@ -125,6 +125,11 @@ pub use sp_arithmetic::{
Perquintill, Rational128, Rounding, UpperOf,
};
pub use transaction_validity::{
InvalidTransaction, TransactionSource, TransactionValidityError, UnknownTransaction,
ValidTransaction,
};
pub use either::Either;
/// The number of bytes of the module-specific `error` field defined in [`ModuleError`].
@@ -443,21 +448,21 @@ impl std::fmt::Display for MultiSigner {
impl Verify for MultiSignature {
type Signer = MultiSigner;
fn verify<L: Lazy<[u8]>>(&self, mut msg: L, signer: &AccountId32) -> bool {
match (self, signer) {
(Self::Ed25519(ref sig), who) => match ed25519::Public::from_slice(who.as_ref()) {
match self {
Self::Ed25519(ref sig) => match ed25519::Public::from_slice(signer.as_ref()) {
Ok(signer) => sig.verify(msg, &signer),
Err(()) => false,
},
(Self::Sr25519(ref sig), who) => match sr25519::Public::from_slice(who.as_ref()) {
Self::Sr25519(ref sig) => match sr25519::Public::from_slice(signer.as_ref()) {
Ok(signer) => sig.verify(msg, &signer),
Err(()) => false,
},
(Self::Ecdsa(ref sig), who) => {
Self::Ecdsa(ref sig) => {
let m = sp_io::hashing::blake2_256(msg.get());
match sp_io::crypto::secp256k1_ecdsa_recover_compressed(sig.as_ref(), &m) {
Ok(pubkey) =>
&sp_io::hashing::blake2_256(pubkey.as_ref()) ==
<dyn AsRef<[u8; 32]>>::as_ref(who),
<dyn AsRef<[u8; 32]>>::as_ref(signer),
_ => false,
}
},
@@ -944,9 +949,13 @@ impl<'a> ::serde::Deserialize<'a> for OpaqueExtrinsic {
}
}
// TODO: OpaqueExtrinsics cannot act like regular extrinsics, right?!
impl traits::Extrinsic for OpaqueExtrinsic {
type Call = ();
type SignaturePayload = ();
fn is_bare(&self) -> bool {
false
}
}
/// Print something that implements `Printable` from the runtime.
+17 -178
View File
@@ -21,24 +21,16 @@ use crate::{
codec::{Codec, Decode, Encode, MaxEncodedLen},
generic,
scale_info::TypeInfo,
traits::{
self, Applyable, BlakeTwo256, Checkable, DispatchInfoOf, Dispatchable, OpaqueKeys,
PostDispatchInfoOf, SignaturePayload, SignedExtension, ValidateUnsigned,
},
transaction_validity::{TransactionSource, TransactionValidity, TransactionValidityError},
ApplyExtrinsicResultWithInfo, KeyTypeId,
traits::{self, BlakeTwo256, Dispatchable, OpaqueKeys},
DispatchResultWithInfo, KeyTypeId,
};
use serde::{de::Error as DeError, Deserialize, Deserializer, Serialize, Serializer};
use serde::{de::Error as DeError, Deserialize, Deserializer, Serialize};
use sp_core::{
crypto::{key_types, ByteArray, CryptoType, Dummy},
U256,
};
pub use sp_core::{sr25519, H256};
use std::{
cell::RefCell,
fmt::{self, Debug},
ops::Deref,
};
use std::{cell::RefCell, fmt::Debug};
/// A dummy type which can be used instead of regular cryptographic primitives.
///
@@ -198,42 +190,6 @@ impl Header {
}
}
/// An opaque extrinsic wrapper type.
#[derive(PartialEq, Eq, Clone, Debug, Encode, Decode)]
pub struct ExtrinsicWrapper<Xt>(Xt);
impl<Xt> traits::Extrinsic for ExtrinsicWrapper<Xt> {
type Call = ();
type SignaturePayload = ();
fn is_signed(&self) -> Option<bool> {
None
}
}
impl<Xt: Encode> serde::Serialize for ExtrinsicWrapper<Xt> {
fn serialize<S>(&self, seq: S) -> Result<S::Ok, S::Error>
where
S: ::serde::Serializer,
{
self.using_encoded(|bytes| seq.serialize_bytes(bytes))
}
}
impl<Xt> From<Xt> for ExtrinsicWrapper<Xt> {
fn from(xt: Xt) -> Self {
ExtrinsicWrapper(xt)
}
}
impl<Xt> Deref for ExtrinsicWrapper<Xt> {
type Target = Xt;
fn deref(&self) -> &Self::Target {
&self.0
}
}
/// Testing block
#[derive(PartialEq, Eq, Clone, Serialize, Debug, Encode, Decode, TypeInfo)]
pub struct Block<Xt> {
@@ -283,139 +239,22 @@ where
}
}
/// The signature payload of a `TestXt`.
type TxSingaturePayload<Extra> = (u64, Extra);
/// Wrapper over a `u64` that can be used as a `RuntimeCall`.
#[derive(PartialEq, Eq, Debug, Clone, Encode, Decode, TypeInfo)]
pub struct MockCallU64(pub u64);
impl<Extra: TypeInfo> SignaturePayload for TxSingaturePayload<Extra> {
type SignatureAddress = u64;
type Signature = ();
type SignatureExtra = Extra;
}
/// Test transaction, tuple of (sender, call, signed_extra)
/// with index only used if sender is some.
///
/// If sender is some then the transaction is signed otherwise it is unsigned.
#[derive(PartialEq, Eq, Clone, Encode, Decode, TypeInfo)]
pub struct TestXt<Call, Extra> {
/// Signature of the extrinsic.
pub signature: Option<TxSingaturePayload<Extra>>,
/// Call of the extrinsic.
pub call: Call,
}
impl<Call, Extra> TestXt<Call, Extra> {
/// Create a new `TextXt`.
pub fn new(call: Call, signature: Option<(u64, Extra)>) -> Self {
Self { call, signature }
impl Dispatchable for MockCallU64 {
type RuntimeOrigin = u64;
type Config = ();
type Info = ();
type PostInfo = ();
fn dispatch(self, _origin: Self::RuntimeOrigin) -> DispatchResultWithInfo<Self::PostInfo> {
Ok(())
}
}
impl<Call, Extra> Serialize for TestXt<Call, Extra>
where
TestXt<Call, Extra>: Encode,
{
fn serialize<S>(&self, seq: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
self.using_encoded(|bytes| seq.serialize_bytes(bytes))
}
}
impl<Call, Extra> Debug for TestXt<Call, Extra> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "TestXt({:?}, ...)", self.signature.as_ref().map(|x| &x.0))
}
}
impl<Call: Codec + Sync + Send, Context, Extra> Checkable<Context> for TestXt<Call, Extra> {
type Checked = Self;
fn check(self, _: &Context) -> Result<Self::Checked, TransactionValidityError> {
Ok(self)
}
#[cfg(feature = "try-runtime")]
fn unchecked_into_checked_i_know_what_i_am_doing(
self,
_: &Context,
) -> Result<Self::Checked, TransactionValidityError> {
unreachable!()
}
}
impl<Call: Codec + Sync + Send + TypeInfo, Extra: TypeInfo> traits::Extrinsic
for TestXt<Call, Extra>
{
type Call = Call;
type SignaturePayload = TxSingaturePayload<Extra>;
fn is_signed(&self) -> Option<bool> {
Some(self.signature.is_some())
}
fn new(c: Call, sig: Option<Self::SignaturePayload>) -> Option<Self> {
Some(TestXt { signature: sig, call: c })
}
}
impl<Call, Extra> traits::ExtrinsicMetadata for TestXt<Call, Extra>
where
Call: Codec + Sync + Send,
Extra: SignedExtension<AccountId = u64, Call = Call>,
{
type SignedExtensions = Extra;
const VERSION: u8 = 0u8;
}
impl<Origin, Call, Extra> Applyable for TestXt<Call, Extra>
where
Call: 'static
+ Sized
+ Send
+ Sync
+ Clone
+ Eq
+ Codec
+ Debug
+ Dispatchable<RuntimeOrigin = Origin>,
Extra: SignedExtension<AccountId = u64, Call = Call>,
Origin: From<Option<u64>>,
{
type Call = Call;
/// Checks to see if this is a valid *transaction*. It returns information on it if so.
fn validate<U: ValidateUnsigned<Call = Self::Call>>(
&self,
source: TransactionSource,
info: &DispatchInfoOf<Self::Call>,
len: usize,
) -> TransactionValidity {
if let Some((ref id, ref extra)) = self.signature {
Extra::validate(extra, id, &self.call, info, len)
} else {
let valid = Extra::validate_unsigned(&self.call, info, len)?;
let unsigned_validation = U::validate_unsigned(source, &self.call)?;
Ok(valid.combine_with(unsigned_validation))
}
}
/// Executes all necessary logic needed prior to dispatch and deconstructs into function call,
/// index and sender.
fn apply<U: ValidateUnsigned<Call = Self::Call>>(
self,
info: &DispatchInfoOf<Self::Call>,
len: usize,
) -> ApplyExtrinsicResultWithInfo<PostDispatchInfoOf<Self::Call>> {
let maybe_who = if let Some((who, extra)) = self.signature {
Extra::pre_dispatch(extra, &who, &self.call, info, len)?;
Some(who)
} else {
Extra::pre_dispatch_unsigned(&self.call, info, len)?;
U::pre_dispatch(&self.call)?;
None
};
Ok(self.call.dispatch(maybe_who.into()))
impl From<u64> for MockCallU64 {
fn from(value: u64) -> Self {
Self(value)
}
}
@@ -19,7 +19,7 @@
use crate::{
generic::Digest,
scale_info::{MetaType, StaticTypeInfo, TypeInfo},
scale_info::{StaticTypeInfo, TypeInfo},
transaction_validity::{
TransactionSource, TransactionValidity, TransactionValidityError, UnknownTransaction,
ValidTransaction,
@@ -52,6 +52,12 @@ use std::fmt::Display;
#[cfg(feature = "std")]
use std::str::FromStr;
pub mod transaction_extension;
pub use transaction_extension::{
DispatchTransaction, TransactionExtension, TransactionExtensionBase,
TransactionExtensionInterior, TransactionExtensionMetadata, ValidateResult,
};
/// A lazy value.
pub trait Lazy<T: ?Sized> {
/// Get a reference to the underlying value.
@@ -1253,7 +1259,7 @@ pub trait Header:
// that is then used to define `UncheckedExtrinsic`.
// ```ignore
// pub type UncheckedExtrinsic =
// generic::UncheckedExtrinsic<Address, RuntimeCall, Signature, SignedExtra>;
// generic::UncheckedExtrinsic<Address, RuntimeCall, Signature, TxExtension>;
// ```
// This `UncheckedExtrinsic` is supplied to the `Block`.
// ```ignore
@@ -1323,19 +1329,31 @@ pub trait Extrinsic: Sized {
/// Is this `Extrinsic` signed?
/// If no information are available about signed/unsigned, `None` should be returned.
#[deprecated = "Use and implement `!is_bare()` instead"]
fn is_signed(&self) -> Option<bool> {
None
}
/// Create new instance of the extrinsic.
///
/// Extrinsics can be split into:
/// 1. Inherents (no signature; created by validators during block production)
/// 2. Unsigned Transactions (no signature; represent "system calls" or other special kinds of
/// calls) 3. Signed Transactions (with signature; a regular transactions with known origin)
/// Returns `true` if this `Extrinsic` is bare.
fn is_bare(&self) -> bool {
#[allow(deprecated)]
!self
.is_signed()
.expect("`is_signed` must return `Some` on production extrinsics; qed")
}
/// Create a new old-school extrinsic, either a bare extrinsic if `_signed_data` is `None` or
/// a signed transaction is it is `Some`.
#[deprecated = "Use `new_inherent` or the `CreateTransaction` trait instead"]
fn new(_call: Self::Call, _signed_data: Option<Self::SignaturePayload>) -> Option<Self> {
None
}
/// Create a new inherent extrinsic.
fn new_inherent(function: Self::Call) -> Self {
#[allow(deprecated)]
Self::new(function, None).expect("Extrinsic must provide inherents; qed")
}
}
/// Something that acts like a [`SignaturePayload`](Extrinsic::SignaturePayload) of an
@@ -1371,7 +1389,8 @@ pub trait ExtrinsicMetadata {
const VERSION: u8;
/// Signed extensions attached to this `Extrinsic`.
type SignedExtensions: SignedExtension;
// TODO: metadata-v16: rename to `Extension`.
type Extra;
}
/// Extract the hashing type for a block.
@@ -1456,6 +1475,8 @@ pub trait Dispatchable {
-> crate::DispatchResultWithInfo<Self::PostInfo>;
}
/// Shortcut to reference the `Origin` type of a `Dispatchable`.
pub type OriginOf<T> = <T as Dispatchable>::RuntimeOrigin;
/// Shortcut to reference the `Info` type of a `Dispatchable`.
pub type DispatchInfoOf<T> = <T as Dispatchable>::Info;
/// Shortcut to reference the `PostInfo` type of a `Dispatchable`.
@@ -1474,8 +1495,49 @@ impl Dispatchable for () {
}
}
/// Dispatchable impl containing an arbitrary value which panics if it actually is dispatched.
#[derive(Clone, Eq, PartialEq, Encode, Decode, RuntimeDebug, TypeInfo)]
pub struct FakeDispatchable<Inner>(pub Inner);
impl<Inner> From<Inner> for FakeDispatchable<Inner> {
fn from(inner: Inner) -> Self {
Self(inner)
}
}
impl<Inner> FakeDispatchable<Inner> {
/// Take `self` and return the underlying inner value.
pub fn deconstruct(self) -> Inner {
self.0
}
}
impl<Inner> AsRef<Inner> for FakeDispatchable<Inner> {
fn as_ref(&self) -> &Inner {
&self.0
}
}
impl<Inner> Dispatchable for FakeDispatchable<Inner> {
type RuntimeOrigin = ();
type Config = ();
type Info = ();
type PostInfo = ();
fn dispatch(
self,
_origin: Self::RuntimeOrigin,
) -> crate::DispatchResultWithInfo<Self::PostInfo> {
panic!("This implementation should not be used for actual dispatch.");
}
}
/// Runtime Origin which includes a System Origin variant whose `AccountId` is the parameter.
pub trait AsSystemOriginSigner<AccountId> {
/// Extract a reference of the inner value of the System `Origin::Signed` variant, if self has
/// that variant.
fn as_system_origin_signer(&self) -> Option<&AccountId>;
}
/// Means by which a transaction may be extended. This type embodies both the data and the logic
/// that should be additionally associated with the transaction. It should be plain old data.
#[deprecated = "Use `TransactionExtension` instead."]
pub trait SignedExtension:
Codec + Debug + Sync + Send + Clone + Eq + PartialEq + StaticTypeInfo
{
@@ -1493,7 +1555,7 @@ pub trait SignedExtension:
/// Any additional data that will go into the signed payload. This may be created dynamically
/// from the transaction using the `additional_signed` function.
type AdditionalSigned: Encode + TypeInfo;
type AdditionalSigned: Codec + TypeInfo;
/// The type that encodes information that can be passed from pre_dispatch to post-dispatch.
type Pre;
@@ -1532,38 +1594,6 @@ pub trait SignedExtension:
len: usize,
) -> Result<Self::Pre, TransactionValidityError>;
/// Validate an unsigned transaction for the transaction queue.
///
/// This function can be called frequently by the transaction queue
/// to obtain transaction validity against current state.
/// It should perform all checks that determine a valid unsigned transaction,
/// and quickly eliminate ones that are stale or incorrect.
///
/// Make sure to perform the same checks in `pre_dispatch_unsigned` function.
fn validate_unsigned(
_call: &Self::Call,
_info: &DispatchInfoOf<Self::Call>,
_len: usize,
) -> TransactionValidity {
Ok(ValidTransaction::default())
}
/// Do any pre-flight stuff for a unsigned transaction.
///
/// Note this function by default delegates to `validate_unsigned`, so that
/// all checks performed for the transaction queue are also performed during
/// the dispatch phase (applying the extrinsic).
///
/// If you ever override this function, you need to make sure to always
/// perform the same validation as in `validate_unsigned`.
fn pre_dispatch_unsigned(
call: &Self::Call,
info: &DispatchInfoOf<Self::Call>,
len: usize,
) -> Result<(), TransactionValidityError> {
Self::validate_unsigned(call, info, len).map(|_| ()).map_err(Into::into)
}
/// Do any post-flight stuff for an extrinsic.
///
/// If the transaction is signed, then `_pre` will contain the output of `pre_dispatch`,
@@ -1594,126 +1624,47 @@ pub trait SignedExtension:
///
/// As a [`SignedExtension`] can be a tuple of [`SignedExtension`]s we need to return a `Vec`
/// that holds the metadata of each one. Each individual `SignedExtension` must return
/// *exactly* one [`SignedExtensionMetadata`].
/// *exactly* one [`TransactionExtensionMetadata`].
///
/// This method provides a default implementation that returns a vec containing a single
/// [`SignedExtensionMetadata`].
fn metadata() -> Vec<SignedExtensionMetadata> {
sp_std::vec![SignedExtensionMetadata {
/// [`TransactionExtensionMetadata`].
fn metadata() -> Vec<TransactionExtensionMetadata> {
sp_std::vec![TransactionExtensionMetadata {
identifier: Self::IDENTIFIER,
ty: scale_info::meta_type::<Self>(),
additional_signed: scale_info::meta_type::<Self::AdditionalSigned>()
}]
}
}
/// Information about a [`SignedExtension`] for the runtime metadata.
pub struct SignedExtensionMetadata {
/// The unique identifier of the [`SignedExtension`].
pub identifier: &'static str,
/// The type of the [`SignedExtension`].
pub ty: MetaType,
/// The type of the [`SignedExtension`] additional signed data for the payload.
pub additional_signed: MetaType,
}
#[impl_for_tuples(1, 12)]
impl<AccountId, Call: Dispatchable> SignedExtension for Tuple {
for_tuples!( where #( Tuple: SignedExtension<AccountId=AccountId, Call=Call,> )* );
type AccountId = AccountId;
type Call = Call;
const IDENTIFIER: &'static str = "You should call `identifier()`!";
for_tuples!( type AdditionalSigned = ( #( Tuple::AdditionalSigned ),* ); );
for_tuples!( type Pre = ( #( Tuple::Pre ),* ); );
fn additional_signed(&self) -> Result<Self::AdditionalSigned, TransactionValidityError> {
Ok(for_tuples!( ( #( Tuple.additional_signed()? ),* ) ))
}
fn validate(
&self,
who: &Self::AccountId,
call: &Self::Call,
info: &DispatchInfoOf<Self::Call>,
len: usize,
) -> TransactionValidity {
let valid = ValidTransaction::default();
for_tuples!( #( let valid = valid.combine_with(Tuple.validate(who, call, info, len)?); )* );
Ok(valid)
}
fn pre_dispatch(
self,
who: &Self::AccountId,
call: &Self::Call,
info: &DispatchInfoOf<Self::Call>,
len: usize,
) -> Result<Self::Pre, TransactionValidityError> {
Ok(for_tuples!( ( #( Tuple.pre_dispatch(who, call, info, len)? ),* ) ))
}
/// Validate an unsigned transaction for the transaction queue.
///
/// This function can be called frequently by the transaction queue
/// to obtain transaction validity against current state.
/// It should perform all checks that determine a valid unsigned transaction,
/// and quickly eliminate ones that are stale or incorrect.
fn validate_unsigned(
call: &Self::Call,
info: &DispatchInfoOf<Self::Call>,
len: usize,
_call: &Self::Call,
_info: &DispatchInfoOf<Self::Call>,
_len: usize,
) -> TransactionValidity {
let valid = ValidTransaction::default();
for_tuples!( #( let valid = valid.combine_with(Tuple::validate_unsigned(call, info, len)?); )* );
Ok(valid)
Ok(ValidTransaction::default())
}
/// Do any pre-flight stuff for an unsigned transaction.
///
/// Note this function by default delegates to `validate_unsigned`, so that
/// all checks performed for the transaction queue are also performed during
/// the dispatch phase (applying the extrinsic).
///
/// If you ever override this function, you need not perform the same validation as in
/// `validate_unsigned`.
fn pre_dispatch_unsigned(
call: &Self::Call,
info: &DispatchInfoOf<Self::Call>,
len: usize,
_call: &Self::Call,
_info: &DispatchInfoOf<Self::Call>,
_len: usize,
) -> Result<(), TransactionValidityError> {
for_tuples!( #( Tuple::pre_dispatch_unsigned(call, info, len)?; )* );
Ok(())
}
fn post_dispatch(
pre: Option<Self::Pre>,
info: &DispatchInfoOf<Self::Call>,
post_info: &PostDispatchInfoOf<Self::Call>,
len: usize,
result: &DispatchResult,
) -> Result<(), TransactionValidityError> {
match pre {
Some(x) => {
for_tuples!( #( Tuple::post_dispatch(Some(x.Tuple), info, post_info, len, result)?; )* );
},
None => {
for_tuples!( #( Tuple::post_dispatch(None, info, post_info, len, result)?; )* );
},
}
Ok(())
}
fn metadata() -> Vec<SignedExtensionMetadata> {
let mut ids = Vec::new();
for_tuples!( #( ids.extend(Tuple::metadata()); )* );
ids
}
}
impl SignedExtension for () {
type AccountId = u64;
type AdditionalSigned = ();
type Call = ();
type Pre = ();
const IDENTIFIER: &'static str = "UnitSignedExtension";
fn additional_signed(&self) -> sp_std::result::Result<(), TransactionValidityError> {
Ok(())
}
fn pre_dispatch(
self,
who: &Self::AccountId,
call: &Self::Call,
info: &DispatchInfoOf<Self::Call>,
len: usize,
) -> Result<Self::Pre, TransactionValidityError> {
self.validate(who, call, info, len).map(|_| ())
}
}
/// An "executable" piece of information, used by the standard Substrate Executive in order to
@@ -1762,6 +1713,7 @@ pub trait GetNodeBlockType {
/// function is called right before dispatching the call wrapped by an unsigned extrinsic. The
/// [`validate_unsigned`](Self::validate_unsigned) function is mainly being used in the context of
/// the transaction pool to check the validity of the call wrapped by an unsigned extrinsic.
// TODO: Rename to ValidateBareTransaction (or just remove).
pub trait ValidateUnsigned {
/// The call to validate
type Call;
@@ -0,0 +1,133 @@
// This file is part of Substrate.
// Copyright (C) Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: Apache-2.0
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//! The [AsTransactionExtension] adapter struct for adapting [SignedExtension]s to
//! [TransactionExtension]s.
#![allow(deprecated)]
use scale_info::TypeInfo;
use sp_core::RuntimeDebug;
use crate::{
traits::{AsSystemOriginSigner, SignedExtension, ValidateResult},
InvalidTransaction,
};
use super::*;
/// Adapter to use a `SignedExtension` in the place of a `TransactionExtension`.
#[derive(TypeInfo, Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug)]
#[deprecated = "Convert your SignedExtension to a TransactionExtension."]
pub struct AsTransactionExtension<SE: SignedExtension>(pub SE);
impl<SE: SignedExtension + Default> Default for AsTransactionExtension<SE> {
fn default() -> Self {
Self(SE::default())
}
}
impl<SE: SignedExtension> From<SE> for AsTransactionExtension<SE> {
fn from(value: SE) -> Self {
Self(value)
}
}
impl<SE: SignedExtension> TransactionExtensionBase for AsTransactionExtension<SE> {
const IDENTIFIER: &'static str = SE::IDENTIFIER;
type Implicit = SE::AdditionalSigned;
fn implicit(&self) -> Result<Self::Implicit, TransactionValidityError> {
self.0.additional_signed()
}
fn metadata() -> Vec<TransactionExtensionMetadata> {
SE::metadata()
}
}
impl<SE: SignedExtension, Context> TransactionExtension<SE::Call, Context>
for AsTransactionExtension<SE>
where
<SE::Call as Dispatchable>::RuntimeOrigin: AsSystemOriginSigner<SE::AccountId> + Clone,
{
type Val = ();
type Pre = SE::Pre;
fn validate(
&self,
origin: <SE::Call as Dispatchable>::RuntimeOrigin,
call: &SE::Call,
info: &DispatchInfoOf<SE::Call>,
len: usize,
_context: &mut Context,
_self_implicit: Self::Implicit,
_inherited_implication: &impl Encode,
) -> ValidateResult<Self::Val, SE::Call> {
let who = origin.as_system_origin_signer().ok_or(InvalidTransaction::BadSigner)?;
let r = self.0.validate(who, call, info, len)?;
Ok((r, (), origin))
}
fn prepare(
self,
_: (),
origin: &<SE::Call as Dispatchable>::RuntimeOrigin,
call: &SE::Call,
info: &DispatchInfoOf<SE::Call>,
len: usize,
_context: &Context,
) -> Result<Self::Pre, TransactionValidityError> {
let who = origin.as_system_origin_signer().ok_or(InvalidTransaction::BadSigner)?;
self.0.pre_dispatch(who, call, info, len)
}
fn post_dispatch(
pre: Self::Pre,
info: &DispatchInfoOf<SE::Call>,
post_info: &PostDispatchInfoOf<SE::Call>,
len: usize,
result: &DispatchResult,
_context: &Context,
) -> Result<(), TransactionValidityError> {
SE::post_dispatch(Some(pre), info, post_info, len, result)
}
fn validate_bare_compat(
call: &SE::Call,
info: &DispatchInfoOf<SE::Call>,
len: usize,
) -> TransactionValidity {
SE::validate_unsigned(call, info, len)
}
fn pre_dispatch_bare_compat(
call: &SE::Call,
info: &DispatchInfoOf<SE::Call>,
len: usize,
) -> Result<(), TransactionValidityError> {
SE::pre_dispatch_unsigned(call, info, len)
}
fn post_dispatch_bare_compat(
info: &DispatchInfoOf<SE::Call>,
post_info: &PostDispatchInfoOf<SE::Call>,
len: usize,
result: &DispatchResult,
) -> Result<(), TransactionValidityError> {
SE::post_dispatch(None, info, post_info, len, result)
}
}
@@ -0,0 +1,141 @@
// This file is part of Substrate.
// Copyright (C) Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: Apache-2.0
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//! The [DispatchTransaction] trait.
use super::*;
/// Single-function utility trait with a blanket impl over [TransactionExtension] in order to
/// provide transaction dispatching functionality. We avoid implementing this directly on the trait
/// since we never want it to be overriden by the trait implementation.
pub trait DispatchTransaction<Call: Dispatchable> {
/// The origin type of the transaction.
type Origin;
/// The info type.
type Info;
/// The resultant type.
type Result;
/// The `Val` of the extension.
type Val;
/// The `Pre` of the extension.
type Pre;
/// Just validate a transaction.
///
/// The is basically the same as [validate](TransactionExtension::validate), except that there
/// is no need to supply the bond data.
fn validate_only(
&self,
origin: Self::Origin,
call: &Call,
info: &Self::Info,
len: usize,
) -> Result<(ValidTransaction, Self::Val, Self::Origin), TransactionValidityError>;
/// Prepare and validate a transaction, ready for dispatch.
fn validate_and_prepare(
self,
origin: Self::Origin,
call: &Call,
info: &Self::Info,
len: usize,
) -> Result<(Self::Pre, Self::Origin), TransactionValidityError>;
/// Dispatch a transaction with the given base origin and call.
fn dispatch_transaction(
self,
origin: Self::Origin,
call: Call,
info: &Self::Info,
len: usize,
) -> Self::Result;
/// Do everything which would be done in a [dispatch_transaction](Self::dispatch_transaction),
/// but instead of executing the call, execute `substitute` instead. Since this doesn't actually
/// dispatch the call, it doesn't need to consume it and so `call` can be passed as a reference.
fn test_run(
self,
origin: Self::Origin,
call: &Call,
info: &Self::Info,
len: usize,
substitute: impl FnOnce(
Self::Origin,
) -> crate::DispatchResultWithInfo<<Call as Dispatchable>::PostInfo>,
) -> Self::Result;
}
impl<T: TransactionExtension<Call, ()>, Call: Dispatchable + Encode> DispatchTransaction<Call>
for T
{
type Origin = <Call as Dispatchable>::RuntimeOrigin;
type Info = DispatchInfoOf<Call>;
type Result = crate::ApplyExtrinsicResultWithInfo<PostDispatchInfoOf<Call>>;
type Val = T::Val;
type Pre = T::Pre;
fn validate_only(
&self,
origin: Self::Origin,
call: &Call,
info: &DispatchInfoOf<Call>,
len: usize,
) -> Result<(ValidTransaction, T::Val, Self::Origin), TransactionValidityError> {
self.validate(origin, call, info, len, &mut (), self.implicit()?, call)
}
fn validate_and_prepare(
self,
origin: Self::Origin,
call: &Call,
info: &DispatchInfoOf<Call>,
len: usize,
) -> Result<(T::Pre, Self::Origin), TransactionValidityError> {
let (_, val, origin) = self.validate_only(origin, call, info, len)?;
let pre = self.prepare(val, &origin, &call, info, len, &())?;
Ok((pre, origin))
}
fn dispatch_transaction(
self,
origin: <Call as Dispatchable>::RuntimeOrigin,
call: Call,
info: &DispatchInfoOf<Call>,
len: usize,
) -> Self::Result {
let (pre, origin) = self.validate_and_prepare(origin, &call, info, len)?;
let res = call.dispatch(origin);
let post_info = res.unwrap_or_else(|err| err.post_info);
let pd_res = res.map(|_| ()).map_err(|e| e.error);
T::post_dispatch(pre, info, &post_info, len, &pd_res, &())?;
Ok(res)
}
fn test_run(
self,
origin: Self::Origin,
call: &Call,
info: &Self::Info,
len: usize,
substitute: impl FnOnce(
Self::Origin,
) -> crate::DispatchResultWithInfo<<Call as Dispatchable>::PostInfo>,
) -> Self::Result {
let (pre, origin) = self.validate_and_prepare(origin, &call, info, len)?;
let res = substitute(origin);
let post_info = match res {
Ok(info) => info,
Err(err) => err.post_info,
};
let pd_res = res.map(|_| ()).map_err(|e| e.error);
T::post_dispatch(pre, info, &post_info, len, &pd_res, &())?;
Ok(res)
}
}
@@ -0,0 +1,526 @@
// This file is part of Substrate.
// Copyright (C) Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: Apache-2.0
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//! The transaction extension trait.
use crate::{
scale_info::{MetaType, StaticTypeInfo},
transaction_validity::{TransactionValidity, TransactionValidityError, ValidTransaction},
DispatchResult,
};
use codec::{Codec, Decode, Encode};
use impl_trait_for_tuples::impl_for_tuples;
#[doc(hidden)]
pub use sp_std::marker::PhantomData;
use sp_std::{self, fmt::Debug, prelude::*};
use sp_weights::Weight;
use tuplex::{PopFront, PushBack};
use super::{DispatchInfoOf, Dispatchable, OriginOf, PostDispatchInfoOf};
mod as_transaction_extension;
mod dispatch_transaction;
#[allow(deprecated)]
pub use as_transaction_extension::AsTransactionExtension;
pub use dispatch_transaction::DispatchTransaction;
/// Shortcut for the result value of the `validate` function.
pub type ValidateResult<Val, Call> =
Result<(ValidTransaction, Val, OriginOf<Call>), TransactionValidityError>;
/// Simple blanket implementation trait to denote the bounds of a type which can be contained within
/// a [`TransactionExtension`].
pub trait TransactionExtensionInterior:
Codec + Debug + Sync + Send + Clone + Eq + PartialEq + StaticTypeInfo
{
}
impl<T: Codec + Debug + Sync + Send + Clone + Eq + PartialEq + StaticTypeInfo>
TransactionExtensionInterior for T
{
}
/// Base for [TransactionExtension]s; this contains the associated types and does not require any
/// generic parameterization.
pub trait TransactionExtensionBase: TransactionExtensionInterior {
/// Unique identifier of this signed extension.
///
/// This will be exposed in the metadata to identify the signed extension used in an extrinsic.
const IDENTIFIER: &'static str;
/// Any additional data which was known at the time of transaction construction and can be
/// useful in authenticating the transaction. This is determined dynamically in part from the
/// on-chain environment using the `implicit` function and not directly contained in the
/// transaction itself and therefore is considered "implicit".
type Implicit: Codec + StaticTypeInfo;
/// Determine any additional data which was known at the time of transaction construction and
/// can be useful in authenticating the transaction. The expected usage of this is to include in
/// any data which is signed and verified as part of transactiob validation. Also perform any
/// pre-signature-verification checks and return an error if needed.
fn implicit(&self) -> Result<Self::Implicit, TransactionValidityError> {
use crate::InvalidTransaction::IndeterminateImplicit;
Ok(Self::Implicit::decode(&mut &[][..]).map_err(|_| IndeterminateImplicit)?)
}
/// The weight consumed by executing this extension instance fully during transaction dispatch.
fn weight(&self) -> Weight {
Weight::zero()
}
/// Returns the metadata for this extension.
///
/// As a [`TransactionExtension`] can be a tuple of [`TransactionExtension`]s we need to return
/// a `Vec` that holds the metadata of each one. Each individual `TransactionExtension` must
/// return *exactly* one [`TransactionExtensionMetadata`].
///
/// This method provides a default implementation that returns a vec containing a single
/// [`TransactionExtensionMetadata`].
fn metadata() -> Vec<TransactionExtensionMetadata> {
sp_std::vec![TransactionExtensionMetadata {
identifier: Self::IDENTIFIER,
ty: scale_info::meta_type::<Self>(),
// TODO: Metadata-v16: Rename to "implicit"
additional_signed: scale_info::meta_type::<Self::Implicit>()
}]
}
}
/// Means by which a transaction may be extended. This type embodies both the data and the logic
/// that should be additionally associated with the transaction. It should be plain old data.
///
/// The simplest transaction extension would be the Unit type (and empty pipeline) `()`. This
/// executes no additional logic and implies a dispatch of the transaction's call using the
/// inherited origin (either `None` or `Signed`, depending on whether this is a signed or general
/// transaction).
///
/// Transaction extensions are capable of altering certain associated semantics:
///
/// - They may define the origin with which the transaction's call should be dispatched.
/// - They may define various parameters used by the transction queue to determine under what
/// conditions the transaction should be retained and introduced on-chain.
/// - They may define whether this transaction is acceptable for introduction on-chain at all.
///
/// Each of these semantics are defined by the `validate` function.
///
/// **NOTE: Transaction extensions cannot under any circumctances alter the call itself.**
///
/// Transaction extensions are capable of defining logic which is executed additionally to the
/// dispatch of the call:
///
/// - They may define logic which must be executed prior to the dispatch of the call.
/// - They may also define logic which must be executed after the dispatch of the call.
///
/// Each of these semantics are defined by the `prepare` and `post_dispatch` functions respectively.
///
/// Finally, transaction extensions may define additional data to help define the implications of
/// the logic they introduce. This additional data may be explicitly defined by the transaction
/// author (in which case it is included as part of the transaction body), or it may be implicitly
/// defined by the transaction extension based around the on-chain state (which the transaction
/// author is assumed to know). This data may be utilized by the above logic to alter how a node's
/// transaction queue treats this transaction.
///
/// ## Default implementations
///
/// Of the 5 functions in this trait, 3 of them must return a value of an associated type on
/// success, and none of these types implement [Default] or anything like it. This means that
/// default implementations cannot be provided for these functions. However, a macro is provided
/// [impl_tx_ext_default](crate::impl_tx_ext_default) which is capable of generating default
/// implementations for each of these 3 functions. If you do not wish to introduce additional logic
/// into the transaction pipeline, then it is recommended that you use this macro to implement these
/// functions.
///
/// ## Pipelines, Inherited Implications, and Authorized Origins
///
/// Requiring a single transaction extension to define all of the above semantics would be
/// cumbersome and would lead to a lot of boilerplate. Instead, transaction extensions are
/// aggregated into pipelines, which are tuples of transaction extensions. Each extension in the
/// pipeline is executed in order, and the output of each extension is aggregated and/or relayed as
/// the input to the next extension in the pipeline.
///
/// This ordered composition happens with all datatypes ([Val](TransactionExtension::Val),
/// [Pre](TransactionExtension::Pre) and [Implicit](TransactionExtensionBase::Implicit)) as well as
/// all functions. There are important consequences stemming from how the composition affects the
/// meaning of the `origin` and `implication` parameters as well as the results. Whereas the
/// [prepare](TransactionExtension::prepare) and
/// [post_dispatch](TransactionExtension::post_dispatch) functions are clear in their meaning, the
/// [validate](TransactionExtension::validate) function is fairly sophisticated and warrants
/// further explanation.
///
/// Firstly, the `origin` parameter. The `origin` passed into the first item in a pipeline is simply
/// that passed into the tuple itself. It represents an authority who has authorized the implication
/// of the transaction, as of the extension it has been passed into *and any further extensions it
/// may pass though, all the way to, and including, the transaction's dispatch call itself. Each
/// following item in the pipeline is passed the origin which the previous item returned. The origin
/// returned from the final item in the pipeline is the origin which is returned by the tuple
/// itself.
///
/// This means that if a constituent extension returns a different origin to the one it was called
/// with, then (assuming no other extension changes it further) *this new origin will be used for
/// all extensions following it in the pipeline, and will be returned from the pipeline to be used
/// as the origin for the call's dispatch*. The call itself as well as all these extensions
/// following may each imply consequence for this origin. We call this the *inherited implication*.
///
/// The *inherited implication* is the cumulated on-chain effects born by whatever origin is
/// returned. It is expressed to the [validate](TransactionExtension::validate) function only as the
/// `implication` argument which implements the [Encode] trait. A transaction extension may define
/// its own implications through its own fields and the
/// [implicit](TransactionExtensionBase::implicit) function. This is only utilized by extensions
/// which preceed it in a pipeline or, if the transaction is an old-school signed trasnaction, the
/// underlying transaction verification logic.
///
/// **The inherited implication passed as the `implication` parameter to
/// [validate](TransactionExtension::validate) does not include the extension's inner data itself
/// nor does it include the result of the extension's `implicit` function.** If you both provide an
/// implication and rely on the implication, then you need to manually aggregate your extensions
/// implication with the aggregated implication passed in.
pub trait TransactionExtension<Call: Dispatchable, Context>: TransactionExtensionBase {
/// The type that encodes information that can be passed from validate to prepare.
type Val;
/// The type that encodes information that can be passed from prepare to post-dispatch.
type Pre;
/// Validate a transaction for the transaction queue.
///
/// This function can be called frequently by the transaction queue to obtain transaction
/// validity against current state. It should perform all checks that determine a valid
/// transaction, that can pay for its execution and quickly eliminate ones that are stale or
/// incorrect.
///
/// Parameters:
/// - `origin`: The origin of the transaction which this extension inherited; coming from an
/// "old-school" *signed transaction*, this will be a system `RawOrigin::Signed` value. If the
/// transaction is a "new-school" *General Transaction*, then this will be a system
/// `RawOrigin::None` value. If this extension is an item in a composite, then it could be
/// anything which was previously returned as an `origin` value in the result of a `validate`
/// call.
/// - `call`: The `Call` wrapped by this extension.
/// - `info`: Information concerning, and inherent to, the transaction's call.
/// - `len`: The total length of the encoded transaction.
/// - `inherited_implication`: The *implication* which this extension inherits. This is a tuple
/// of the transaction's call and some additional opaque-but-encodable data. Coming directly
/// from a transaction, the latter is [()]. However, if this extension is expressed as part of
/// a composite type, then the latter component is equal to any further implications to which
/// the returned `origin` could potentially apply. See Pipelines, Inherited Implications, and
/// Authorized Origins for more information.
/// - `context`: Some opaque mutable context, as yet unused.
///
/// Returns a [ValidateResult], which is a [Result] whose success type is a tuple of
/// [ValidTransaction] (defining useful metadata for the transaction queue), the [Self::Val]
/// token of this transaction, which gets passed into [prepare](TransactionExtension::prepare),
/// and the origin of the transaction, which gets passed into
/// [prepare](TransactionExtension::prepare) and is ultimately used for dispatch.
fn validate(
&self,
origin: OriginOf<Call>,
call: &Call,
info: &DispatchInfoOf<Call>,
len: usize,
context: &mut Context,
self_implicit: Self::Implicit,
inherited_implication: &impl Encode,
) -> ValidateResult<Self::Val, Call>;
/// Do any pre-flight stuff for a transaction after validation.
///
/// This is for actions which do not happen in the transaction queue but only immediately prior
/// to the point of dispatch on-chain. This should not return an error, since errors should
/// already have been identified during the [validate](TransactionExtension::validate) call. If
/// an error is returned, the transaction will be considered invalid but no state changes will
/// happen and therefore work done in [validate](TransactionExtension::validate) will not be
/// paid for.
///
/// Unlike `validate`, this function may consume `self`.
///
/// Parameters:
/// - `val`: `Self::Val` returned by the result of the `validate` call.
/// - `origin`: The origin returned by the result of the `validate` call.
/// - `call`: The `Call` wrapped by this extension.
/// - `info`: Information concerning, and inherent to, the transaction's call.
/// - `len`: The total length of the encoded transaction.
/// - `context`: Some opaque mutable context, as yet unused.
///
/// Returns a [Self::Pre] value on success, which gets passed into
/// [post_dispatch](TransactionExtension::post_dispatch) and after the call is dispatched.
///
/// IMPORTANT: **Checks made in validation need not be repeated here.**
fn prepare(
self,
val: Self::Val,
origin: &OriginOf<Call>,
call: &Call,
info: &DispatchInfoOf<Call>,
len: usize,
context: &Context,
) -> Result<Self::Pre, TransactionValidityError>;
/// Do any post-flight stuff for an extrinsic.
///
/// `_pre` contains the output of `prepare`.
///
/// This gets given the `DispatchResult` `_result` from the extrinsic and can, if desired,
/// introduce a `TransactionValidityError`, causing the block to become invalid for including
/// it.
///
/// Parameters:
/// - `pre`: `Self::Pre` returned by the result of the `prepare` call prior to dispatch.
/// - `info`: Information concerning, and inherent to, the transaction's call.
/// - `post_info`: Information concerning the dispatch of the transaction's call.
/// - `len`: The total length of the encoded transaction.
/// - `result`: The result of the dispatch.
/// - `context`: Some opaque mutable context, as yet unused.
///
/// WARNING: It is dangerous to return an error here. To do so will fundamentally invalidate the
/// transaction and any block that it is included in, causing the block author to not be
/// compensated for their work in validating the transaction or producing the block so far. It
/// can only be used safely when you *know* that the transaction is one that would only be
/// introduced by the current block author.
fn post_dispatch(
_pre: Self::Pre,
_info: &DispatchInfoOf<Call>,
_post_info: &PostDispatchInfoOf<Call>,
_len: usize,
_result: &DispatchResult,
_context: &Context,
) -> Result<(), TransactionValidityError> {
Ok(())
}
/// Compatibility function for supporting the `SignedExtension::validate_unsigned` function.
///
/// DO NOT USE! THIS MAY BE REMOVED AT ANY TIME!
#[deprecated = "Only for compatibility. DO NOT USE."]
fn validate_bare_compat(
_call: &Call,
_info: &DispatchInfoOf<Call>,
_len: usize,
) -> TransactionValidity {
Ok(ValidTransaction::default())
}
/// Compatibility function for supporting the `SignedExtension::pre_dispatch_unsigned` function.
///
/// DO NOT USE! THIS MAY BE REMOVED AT ANY TIME!
#[deprecated = "Only for compatibility. DO NOT USE."]
fn pre_dispatch_bare_compat(
_call: &Call,
_info: &DispatchInfoOf<Call>,
_len: usize,
) -> Result<(), TransactionValidityError> {
Ok(())
}
/// Compatibility function for supporting the `SignedExtension::post_dispatch` function where
/// `pre` is `None`.
///
/// DO NOT USE! THIS MAY BE REMOVED AT ANY TIME!
#[deprecated = "Only for compatibility. DO NOT USE."]
fn post_dispatch_bare_compat(
_info: &DispatchInfoOf<Call>,
_post_info: &PostDispatchInfoOf<Call>,
_len: usize,
_result: &DispatchResult,
) -> Result<(), TransactionValidityError> {
Ok(())
}
}
/// Implict
#[macro_export]
macro_rules! impl_tx_ext_default {
($call:ty ; $context:ty ; , $( $rest:tt )*) => {
impl_tx_ext_default!{$call ; $context ; $( $rest )*}
};
($call:ty ; $context:ty ; validate $( $rest:tt )*) => {
fn validate(
&self,
origin: $crate::traits::OriginOf<$call>,
_call: &$call,
_info: &$crate::traits::DispatchInfoOf<$call>,
_len: usize,
_context: &mut $context,
_self_implicit: Self::Implicit,
_inherited_implication: &impl $crate::codec::Encode,
) -> $crate::traits::ValidateResult<Self::Val, $call> {
Ok((Default::default(), Default::default(), origin))
}
impl_tx_ext_default!{$call ; $context ; $( $rest )*}
};
($call:ty ; $context:ty ; prepare $( $rest:tt )*) => {
fn prepare(
self,
_val: Self::Val,
_origin: &$crate::traits::OriginOf<$call>,
_call: &$call,
_info: &$crate::traits::DispatchInfoOf<$call>,
_len: usize,
_context: & $context,
) -> Result<Self::Pre, $crate::TransactionValidityError> {
Ok(Default::default())
}
impl_tx_ext_default!{$call ; $context ; $( $rest )*}
};
($call:ty ; $context:ty ;) => {};
}
/// Information about a [`TransactionExtension`] for the runtime metadata.
pub struct TransactionExtensionMetadata {
/// The unique identifier of the [`TransactionExtension`].
pub identifier: &'static str,
/// The type of the [`TransactionExtension`].
pub ty: MetaType,
/// The type of the [`TransactionExtension`] additional signed data for the payload.
// TODO: Rename "implicit"
pub additional_signed: MetaType,
}
#[impl_for_tuples(1, 12)]
impl TransactionExtensionBase for Tuple {
for_tuples!( where #( Tuple: TransactionExtensionBase )* );
const IDENTIFIER: &'static str = "Use `metadata()`!";
for_tuples!( type Implicit = ( #( Tuple::Implicit ),* ); );
fn implicit(&self) -> Result<Self::Implicit, TransactionValidityError> {
Ok(for_tuples!( ( #( Tuple.implicit()? ),* ) ))
}
fn weight(&self) -> Weight {
let mut weight = Weight::zero();
for_tuples!( #( weight += Tuple.weight(); )* );
weight
}
fn metadata() -> Vec<TransactionExtensionMetadata> {
let mut ids = Vec::new();
for_tuples!( #( ids.extend(Tuple::metadata()); )* );
ids
}
}
#[impl_for_tuples(1, 12)]
impl<Call: Dispatchable, Context> TransactionExtension<Call, Context> for Tuple {
for_tuples!( where #( Tuple: TransactionExtension<Call, Context> )* );
for_tuples!( type Val = ( #( Tuple::Val ),* ); );
for_tuples!( type Pre = ( #( Tuple::Pre ),* ); );
fn validate(
&self,
origin: <Call as Dispatchable>::RuntimeOrigin,
call: &Call,
info: &DispatchInfoOf<Call>,
len: usize,
context: &mut Context,
self_implicit: Self::Implicit,
inherited_implication: &impl Encode,
) -> Result<
(ValidTransaction, Self::Val, <Call as Dispatchable>::RuntimeOrigin),
TransactionValidityError,
> {
let valid = ValidTransaction::default();
let val = ();
let following_explicit_implications = for_tuples!( ( #( &self.Tuple ),* ) );
let following_implicit_implications = self_implicit;
for_tuples!(#(
// Implication of this pipeline element not relevant for later items, so we pop it.
let (_item, following_explicit_implications) = following_explicit_implications.pop_front();
let (item_implicit, following_implicit_implications) = following_implicit_implications.pop_front();
let (item_valid, item_val, origin) = {
let implications = (
// The first is the implications born of the fact we return the mutated
// origin.
inherited_implication,
// This is the explicitly made implication born of the fact the new origin is
// passed into the next items in this pipeline-tuple.
&following_explicit_implications,
// This is the implicitly made implication born of the fact the new origin is
// passed into the next items in this pipeline-tuple.
&following_implicit_implications,
);
Tuple.validate(origin, call, info, len, context, item_implicit, &implications)?
};
let valid = valid.combine_with(item_valid);
let val = val.push_back(item_val);
)* );
Ok((valid, val, origin))
}
fn prepare(
self,
val: Self::Val,
origin: &<Call as Dispatchable>::RuntimeOrigin,
call: &Call,
info: &DispatchInfoOf<Call>,
len: usize,
context: &Context,
) -> Result<Self::Pre, TransactionValidityError> {
Ok(for_tuples!( ( #(
Tuple::prepare(self.Tuple, val.Tuple, origin, call, info, len, context)?
),* ) ))
}
fn post_dispatch(
pre: Self::Pre,
info: &DispatchInfoOf<Call>,
post_info: &PostDispatchInfoOf<Call>,
len: usize,
result: &DispatchResult,
context: &Context,
) -> Result<(), TransactionValidityError> {
for_tuples!( #( Tuple::post_dispatch(pre.Tuple, info, post_info, len, result, context)?; )* );
Ok(())
}
}
impl TransactionExtensionBase for () {
const IDENTIFIER: &'static str = "UnitTransactionExtension";
type Implicit = ();
fn implicit(&self) -> sp_std::result::Result<Self::Implicit, TransactionValidityError> {
Ok(())
}
fn weight(&self) -> Weight {
Weight::zero()
}
}
impl<Call: Dispatchable, Context> TransactionExtension<Call, Context> for () {
type Val = ();
type Pre = ();
fn validate(
&self,
origin: <Call as Dispatchable>::RuntimeOrigin,
_call: &Call,
_info: &DispatchInfoOf<Call>,
_len: usize,
_context: &mut Context,
_self_implicit: Self::Implicit,
_inherited_implication: &impl Encode,
) -> Result<
(ValidTransaction, (), <Call as Dispatchable>::RuntimeOrigin),
TransactionValidityError,
> {
Ok((ValidTransaction::default(), (), origin))
}
fn prepare(
self,
_val: (),
_origin: &<Call as Dispatchable>::RuntimeOrigin,
_call: &Call,
_info: &DispatchInfoOf<Call>,
_len: usize,
_context: &Context,
) -> Result<(), TransactionValidityError> {
Ok(())
}
}
@@ -82,6 +82,8 @@ pub enum InvalidTransaction {
MandatoryValidation,
/// The sending address is disabled or known to be invalid.
BadSigner,
/// The implicit data was unable to be calculated.
IndeterminateImplicit,
}
impl InvalidTransaction {
@@ -113,6 +115,8 @@ impl From<InvalidTransaction> for &'static str {
"Transaction dispatch is mandatory; transactions must not be validated.",
InvalidTransaction::Custom(_) => "InvalidTransaction custom error",
InvalidTransaction::BadSigner => "Invalid signing address",
InvalidTransaction::IndeterminateImplicit =>
"The implicit data was unable to be calculated",
}
}
}
@@ -338,7 +342,7 @@ pub struct ValidTransactionBuilder {
impl ValidTransactionBuilder {
/// Set the priority of a transaction.
///
/// Note that the final priority for `FRAME` is combined from all `SignedExtension`s.
/// Note that the final priority for `FRAME` is combined from all `TransactionExtension`s.
/// Most likely for unsigned transactions you want the priority to be higher
/// than for regular transactions. We recommend exposing a base priority for unsigned
/// transactions as a runtime module parameter, so that the runtime can tune inter-module