Skip to content
Snippets Groups Projects
user avatar
Gavin Wood authored
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: default avatargeorgepisaltu <george.pisaltu@parity.io>
Signed-off-by: default avatarAlexandru Vasile <alexandru.vasile@parity.io>
Signed-off-by: default avatardependabot[bot] <support@github.com>
Signed-off-by: default avatarOliver Tale-Yazdi <oliver.tale-yazdi@parity.io>
Signed-off-by: default avatarAlexandru Gheorghe <alexandru.gheorghe@parity.io>
Signed-off-by: default avatarAndrei Sandu <andrei-mihail@parity.io>
Co-authored-by: default avatarNikhil Gupta <17176722+gupnik@users.noreply.github.com>
Co-authored-by: default avatargeorgepisaltu <52418509+georgepisaltu@users.noreply.github.com>
Co-authored-by: default avatarChevdor <chevdor@users.noreply.github.com>
Co-authored-by: default avatarBastian Köcher <git@kchr.de>
Co-authored-by: default avatarMaciej <maciej.zyszkiewicz@parity.io>
Co-authored-by: default avatarJavier Viola <javier@parity.io>
Co-authored-by: default avatarMarcin S. <marcin@realemail.net>
Co-authored-by: default avatarTsvetomir Dimitrov <tsvetomir@parity.io>
Co-authored-by: default avatarJavier Bullrich <javier@bullrich.dev>
Co-authored-by: default avatarKoute <koute@users.noreply.github.com>
Co-authored-by: default avatarAdrian Catangiu <adrian@parity.io>
Co-authored-by: Vladimir Istyufeev's avatarVladimir Istyufeev <vladimir@parity.io>
Co-authored-by: default avatarRoss Bulat <ross@parity.io>
Co-authored-by: default avatarGonçalo Pestana <g6pestana@gmail.com>
Co-authored-by: default avatarLiam Aharon <liam.aharon@hotmail.com>
Co-authored-by: default avatarSvyatoslav Nikolsky <svyatonik@gmail.com>
Co-authored-by: default avatarAndré Silva <123550+andresilva@users.noreply.github.com>
Co-authored-by: default avatarOliver Tale-Yazdi <oliver.tale-yazdi@parity.io>
Co-authored-by: default avatars0me0ne-unkn0wn <48632512+s0me0ne-unkn0wn@users.noreply.github.com>
Co-authored-by: default avatarordian <write@reusable.software>
Co-authored-by: default avatarSebastian Kunert <skunert49@gmail.com>
Co-authored-by: default avatarAaro Altonen <48052676+altonen@users.noreply.github.com>
Co-authored-by: default avatarDmitry Markin <dmitry@markin.tech>
Co-authored-by: default avatarAlexandru Vasile <60601340+lexnv@users.noreply.github.com>
Co-authored-by: default avatarAlexander Samusev <41779041+alvicsam@users.noreply.github.com>
Co-authored-by: default avatarJulian Eager <eagr@tutanota.com>
Co-authored-by: default avatarMichal Kucharczyk <1728078+michalkucharczyk@users.noreply.github.com>
Co-authored-by: default avatarDavide Galassi <davxy@datawok.net>
Co-authored-by: default avatarDónal Murray <donal.murray@parity.io>
Co-authored-by: default avataryjh <yjh465402634@gmail.com>
Co-authored-by: default avatarTom Mi <tommi@niemi.lol>
Co-authored-by: default avatardependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: default avatarWill | Paradox | ParaNodes.io <79228812+paradox-tt@users.noreply.github.com>
Co-authored-by: default avatarBastian Köcher <info@kchr.de>
Co-authored-by: default avatarJoshy Orndorff <JoshOrndorff@users.noreply.github.com>
Co-authored-by: default avatarJoshy Orndorff <git-user-email.h0ly5@simplelogin.com>
Co-authored-by: default avatarPG Herveou <pgherveou@gmail.com>
Co-authored-by: default avatarAlexander Theißen <alex.theissen@me.com>
Co-authored-by: default avatarKian Paimani <5588131+kianenigma@users.noreply.github.com>
Co-authored-by: default avatarJuan Girini <juangirini@gmail.com>
Co-authored-by: default avatarbader y <ibnbassem@gmail.com>
Co-authored-by: default avatarJames Wilson <james@jsdw.me>
Co-authored-by: default avatarjoe petrowski <25483142+joepetrowski@users.noreply.github.com>
Co-authored-by: default avatarasynchronous rob <rphmeier@gmail.com>
Co-authored-by: default avatarParth <desaiparth08@gmail.com>
Co-authored-by: default avatarAndrew Jones <ascjones@gmail.com>
Co-authored-by: default avatarJonathan Udd <jonathan@dwellir.com>
Co-authored-by: default avatarSerban Iorga <serban@parity.io>
Co-authored-by: default avatarEgor_P <egor@parity.io>
Co-authored-by: default avatarBranislav Kontur <bkontur@gmail.com>
Co-authored-by: default avatarEvgeny Snitko <evgeny@parity.io>
Co-authored-by: default avatarJust van Stam <vstam1@users.noreply.github.com>
Co-authored-by: default avatarFrancisco Aguirre <franciscoaguirreperez@gmail.com>
Co-authored-by: default avatargupnik <nikhilgupta.iitk@gmail.com>
Co-authored-by: default avatardzmitry-lahoda <dzmitry@lahoda.pro>
Co-authored-by: default avatarzhiqiangxu <652732310@qq.com>
Co-authored-by: default avatarNazar Mokrynskyi <nazar@mokrynskyi.com>
Co-authored-by: default avatarAnwesh <anweshknayak@gmail.com>
Co-authored-by: default avatarcheme <emericchevalier.pro@gmail.com>
Co-authored-by: default avatarSam Johnson <sam@durosoft.com>
Co-authored-by: default avatarkianenigma <kian@parity.io>
Co-authored-by: default avatarJegor Sidorenko <5252494+jsidorenko@users.noreply.github.com>
Co-authored-by: default avatarMuharem <ismailov.m.h@gmail.com>
Co-authored-by: default avatarjoepetrowski <joe@parity.io>
Co-authored-by: default avatarAlexandru Gheorghe <49718502+alexggh@users.noreply.github.com>
Co-authored-by: default avatarGabriel Facco de Arruda <arrudagates@gmail.com>
Co-authored-by: default avatarSquirrel <gilescope@gmail.com>
Co-authored-by: default avatarAndrei Sandu <54316454+sandreim@users.noreply.github.com>
Co-authored-by: default avatargeorgepisaltu <george.pisaltu@parity.io>
Co-authored-by: command-bot <>
fd5f9292

NOTE: We have recently made significant changes to our repository structure. In order to streamline our development process and foster better contributions, we have merged three separate repositories Cumulus, Substrate and Polkadot into this repository. Read more about the changes here.

Polkadot SDK

StackExchange

The Polkadot SDK repository provides all the resources needed to start building on the Polkadot network, a multi-chain blockchain platform that enables different blockchains to interoperate and share information in a secure and scalable way. The Polkadot SDK comprises three main pieces of software:

Polkadot

PolkadotForum Polkadot-license

Implementation of a node for the https://polkadot.network in Rust, using the Substrate framework. This directory currently contains runtimes for the Westend and Rococo test networks. Polkadot, Kusama and their system chain runtimes are located in the runtimes repository maintained by the Polkadot Technical Fellowship.

Substrate

SubstrateRustDocs Substrate-license

Substrate is the primary blockchain SDK used by developers to create the parachains that make up the Polkadot network. Additionally, it allows for the development of self-sovereign blockchains that operate completely independently of Polkadot.

Cumulus

CumulusRustDocs Cumulus-license

Cumulus is a set of tools for writing Substrate-based Polkadot parachains.

Releases

[!NOTE]
Our release process is still Work-In-Progress and may not yet reflect the aspired outline here.

The Polkadot-SDK has two release channels: stable and nightly. Production software is advised to only use stable. nightly is meant for tinkerers to try out the latest features. The detailed release process is described in RELEASE.md.

Stable

stable releases have a support duration of three months. In this period, the release will not have any breaking changes. It will receive bug fixes, security fixes, performance fixes and new non-breaking features on a two week cadence.

Nightly

nightly releases are released every night from the master branch, potentially with breaking changes. They have pre-release version numbers in the format major.0.0-nightlyYYMMDD.

Upstream Dependencies

Below are the primary upstream dependencies utilized in this project:

Security

The security policy and procedures can be found in docs/contributor/SECURITY.md.

Contributing & Code of Conduct

Ensure you follow our contribution guidelines. In every interaction and contribution, this project adheres to the Contributor Covenant Code of Conduct.

Additional Resources

  • For monitoring upcoming changes and current proposals related to the technical implementation of the Polkadot network, visit the Requests for Comment (RFC) repository. While it's maintained by the Polkadot Fellowship, the RFC process welcomes contributions from everyone.