Annoyance: Transaction extension tuple can't be more than 12 elements, and tuple of tuple changes order of inherited implication and is not discoverable with metadata #6569
TLDR: Transaction extension tuple can't be more than 12 elements, and tuple of tuple changes order of inherited implication, and the order is not discoverable with metadata because it only contains a vector of transaction extension.
Description:
The transaction extensions are define with a tuple of transaction extension, and is part of the extrinsic that is part of a block.
pub type TxExtension = (
frame_system::CheckNonZeroSender<Runtime>,
frame_system::CheckSpecVersion<Runtime>,
frame_system::CheckTxVersion<Runtime>,
frame_system::CheckGenesis<Runtime>,
frame_system::CheckEra<Runtime>,
frame_system::CheckNonce<Runtime>,
frame_system::CheckWeight<Runtime>,
pallet_transaction_payment::ChargeTransactionPayment<Runtime>,
cumulus_primitives_storage_weight_reclaim::StorageWeightReclaim<Runtime>,
frame_metadata_hash_extension::CheckMetadataHash<Runtime>,
);
/// Unchecked extrinsic type as expected by this runtime.
pub type UncheckedExtrinsic =
generic::UncheckedExtrinsic<Address, RuntimeCall, Signature, TxExtension>;
The block requires among other traits: Eq, PartialEq, Debug.
for (A, B), C, D) the inherited implications of A is ext_version, call, C_explicit, D_explicit, C_implicit, D_implicit, B_explicit, B_implicit.
for (A, B, C, D) the inherited implications of A is ext_version, call, B_explicit, C_explicit, D_explicit, B_implicit, C_implicit, D_implicit.
and for both the metadata is simply A, B, C
Solution:
Solution 1: Don't use tuple, make a new struct with 128 optional generics named TransactionExtensionPipeline, and derive traits on it.
EDIT: it doesn't work well when we need to give implicit or instanciate types. But with some From implementation it can be fine.
Solution 2: change the order of inherited implication to always be consistent in some way: need a new method to build the implication, and then tuple will return the interleaved (A_explicit, A_implicit, B_explicit, B_implicit) for its implication. Or 2 inherited implications arguments: explicit and implicit. (call and extension version would be explicits at the end.)
TLDR: Transaction extension tuple can't be more than 12 elements, and tuple of tuple changes order of inherited implication, and the order is not discoverable with metadata because it only contains a vector of transaction extension.
Description:
The transaction extensions are define with a tuple of transaction extension, and is part of the extrinsic that is part of a block.
The block requires among other traits:
Eq
,PartialEq
,Debug
.Those specific traits are implemented on tuple of at most 12 elements: https://doc.rust-lang.org/core/primitive.tuple.html#trait-implementations-1
To fit into 12 elements we may want to group some into tuples like:
But this changes the inherited implication passed to the grouped transaction extensions: The code is here: https://github.com/paritytech/polkadot-sdk/blob/25691b8e945a6453fa65fd5ae6eb54b6a523f280/substrate/primitives/runtime/src/traits/transaction_extension/mod.rs#L510-L533
To be more precise:
(A, B), C, D)
the inherited implications of A isext_version, call, C_explicit, D_explicit, C_implicit, D_implicit, B_explicit, B_implicit
.(A, B, C, D)
the inherited implications of A isext_version, call, B_explicit, C_explicit, D_explicit, B_implicit, C_implicit, D_implicit
. and for both the metadata is simplyA, B, C
Solution:
TransactionExtensionPipeline
, and derive traits on it. EDIT: it doesn't work well when we need to give implicit or instanciate types. But with someFrom
implementation it can be fine.(A_explicit, A_implicit, B_explicit, B_implicit)
for its implication. Or 2 inherited implications arguments: explicit and implicit. (call and extension version would be explicits at the end.)cc @georgepisaltu