Skip to content

Allow multiple transaction extension version in UncheckedExtrinsic type.#7035

Merged
gui1117 merged 64 commits into
masterfrom
gui-transaction-extension-multiple-version
Mar 30, 2026
Merged

Allow multiple transaction extension version in UncheckedExtrinsic type.#7035
gui1117 merged 64 commits into
masterfrom
gui-transaction-extension-multiple-version

Conversation

@gui1117

@gui1117 gui1117 commented Jan 3, 2025

Copy link
Copy Markdown
Contributor

This PR enhance UncheckedExtrinsic type with a new optional generic: ExtensionOtherVersion.
This generic defaults to InvalidVersion meaning there is not other version than the regular version 0. This is the same behavior as before this PR.

New feature

To use this new feature, you can use the new types TxExtLineAtVers and MultiVersion to define a transaction extension with multiple version:

pub type TransactionExtensionV0 = ();
pub type TransactionExtensionV4 = ();
pub type TransactionExtensionV7 = ();

pub type OtherVersions = MultiVersion<
	TxExtLineAtVers<4, TransactionExtensionV4>;
	TxExtLineAtVers<7, TransactionExtensionV7>;
>;

pub type UncheckedExtrinsic = generic::UncheckedExtrinsic<
	AccountId,
	RuntimeCall,
	UintAuthorityId,
	TransactionExtensionV0, // The version 0, same as before
	OtherVersions, // The other versions.
>;

Breaking change

The types Preamble, CheckedExtrinsic and ExtrinsicFormat also have this new optional generic. Their type definition also have changed a bit, the General variant was 2 fields, the version and the extension, it is now only one field, the extension, and the version can be retrieve by calling extension.version()

The type inference for those types may fail because of this PR, to update the code, write some partial type: UncheckedExtrinsic<_, _, _, _>, Preamble<_, _, _>, ExtrinsicFormat<_, _> and CheckedExtrinsic<_, _, _>`.

Alternative implementation

This PR breaks the types a bit, I think it is very minimal and fine, but if this is annoying we can still keep the old types and write new types such as UncheckedExtrinsicV2, CheckedExtrinsicV2 etc..

@gui1117 gui1117 marked this pull request as ready for review January 8, 2025 09:44
@gui1117 gui1117 requested a review from a team as a code owner January 8, 2025 09:44
@gui1117 gui1117 added the T1-FRAME This PR/Issue is related to core FRAME, the framework. label Jan 8, 2025

@bkchr bkchr left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great work!

It would be ultra nice to have some proper example. Maybe as part of the guide here in the repo. This way it would be easier to replicate the stuff.

Comment on lines +1507 to +1508
/// For the transaction extension pipeline used for the signed extrinsics it is defined as the
/// version 0, if defined.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This sentence is confusing.

@gui1117 gui1117 Mar 16, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't really know if this trait should specify it but the idea is that in extrinsic v4, for signed extrinsics, there no version. So to get the pipeline used you need to fetch the version 0.

I rewrote saying extrinsic v4, pipeline version 0 is used, and for extrinsic v5, for bare extrinsics pipeline version 0 is used: 1a81f0a

Comment on lines +42 to +43
/// The generic `ExtensionOtherVersions` must not re-define a transaction extension pipeline for the
/// version 0, it will be ignored and overwritten by `ExtensionV0`.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't get what you mean by this.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried to reword here: 22f7bcc

The thing is that if ExtensionOtherVersions also define a pipeline for the version 0 then this version is just ignored.
The version 0 is the one defined by ExtensionV0.

Comment thread substrate/primitives/runtime/src/traits/vers_tx_ext/invalid.rs Outdated
Comment on lines +60 to +63
pub trait PipelineVersion {
/// Return the version for the given versioned transaction extension pipeline.
fn version(&self) -> u8;
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This makes sense to be its own trait, because it doesn't require the Call parameter, but PipelineWeight still makes no sense to have it separate?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I implemented here: 2abb369

The main issue is that the function extension_weight for UncheckedExtrinsic and CheckedExtrinsic and the dispatch info stuff doesn't bound the trait DispatchTransaction. But if I put the pipeline weight inside the pipeline trait, then I now need to bound the trait DispatchTransaction to access the weight on those type and in the dispatch info. Overall it is fine, it is just about adding a few bounds here and there. But this is the reason why I made it separate before.

Comment thread substrate/primitives/runtime/src/traits/vers_tx_ext/mod.rs Outdated
Comment thread substrate/frame/revive/src/evm/runtime.rs
/// An old-school transaction extrinsic which includes a signature of some hard-coded crypto.
/// Available only on extrinsic version 4.
Signed(Address, Signature, Extension),
Signed(Address, Signature, ExtensionV0),

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah you are right, if we don't support this any more with version 5, it will not be important.

///
/// Types of extrinsics:
/// - **Bare**: An extrinsic without a signature or any additional data. After being checked, bare
/// extrinsics can be applied, the apply logic is extended with `ExtensionV0`.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ExtensionV0 is only used for the deprecated unsigned transactions or?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Worth to be mentioned IMO.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is also used for inherents. Inherents still use transaction extension like CheckWeight to register the used weight.


/// A type implements [`DecodeWithVersion`] where inner decoding is implementing
/// [`codec::DecodeWithMemTracking`].
pub trait DecodeWithVersionWithMemTracking: DecodeWithVersion {}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Answering myself DecodeWithMemTracking requires Decode as super trait.

Co-authored-by: Bastian Köcher <git@kchr.de>
@gui1117 gui1117 requested a review from a team as a code owner March 15, 2026 22:58
@gui1117

gui1117 commented Mar 16, 2026

Copy link
Copy Markdown
Contributor Author

Great work!

It would be ultra nice to have some proper example. Maybe as part of the guide here in the repo. This way it would be easier to replicate the stuff.

I will write it then, but if we merge it before it is also good and I will do in a follow-up PR.

@gui1117

gui1117 commented Mar 27, 2026

Copy link
Copy Markdown
Contributor Author

Great work!
It would be ultra nice to have some proper example. Maybe as part of the guide here in the repo. This way it would be easier to replicate the stuff.

I will write it then, but if we merge it before it is also good and I will do in a follow-up PR.

I will do in a follow-up.

@pgherveou pgherveou left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for contracts team.
all changes under Revive seems mostly mechanical, if Build / CI pass that's good for me

@gui1117 gui1117 enabled auto-merge March 30, 2026 05:21
@gui1117 gui1117 added this pull request to the merge queue Mar 30, 2026
Merged via the queue into master with commit 89aa25d Mar 30, 2026
245 of 252 checks passed
@gui1117 gui1117 deleted the gui-transaction-extension-multiple-version branch March 30, 2026 06:55
sigurpol added a commit that referenced this pull request Mar 31, 2026
PR #7035 added new TypeInfo implementors, pushing rustc past its
diagnostic threshold for emitting `consider using --verbose` on the
TypeInfo/StorageEntryMetadataBuilder error.
github-merge-queue Bot pushed a commit that referenced this pull request Mar 31, 2026
PR #7035 added new TypeInfo implementors, pushing rustc past its
diagnostic threshold for emitting `consider using --verbose` on the
TypeInfo/StorageEntryMetadataBuilder error.
ggwpez added a commit to polkadot-fellows/runtimes that referenced this pull request May 4, 2026
Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

T1-FRAME This PR/Issue is related to core FRAME, the framework. T17-primitives Changes to primitives that are not covered by any other label.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants