feat: support custom transaction extension values - #2273
Conversation
9d1ea0b to
ce9a555
Compare
|
|
||
| fn is_authorization_extension(&self, name: &str) -> bool { | ||
| frame_decode::extrinsics::TransactionExtensions::is_authorization_extension( | ||
| &self.known, |
There was a problem hiding this comment.
nit: This forwards only to known entries, so chain specific exntesions return false here? Would be worth having a subxt issue about this one to tackle later
There was a problem hiding this comment.
Filed #2276 for this, and left a comment on is_authorization_extension pointing at it.
Worth noting it is not purely cosmetic: in V5 the signer payload excludes the last authorization extension and everything before it, so a chain declaring its own authorization extension and supplying it via custom_extension would sign over bytes the runtime excludes. Latent for now since VerifyMultiSignature is the only authorization extension Subxt knows about.
lexnv
left a comment
There was a problem hiding this comment.
The shape looks good, just some tiny bits and pieces!
We could probably add some more V5 tests (ie around authorization_extension_check_is_forwarded and is_authorization_extension and probably some tests with a custom extension positioned before and after VerifyMultiSignature)
|
Added the V5 coverage you asked for. Since
The |
Allow callers to provide metadata-aware values for custom transaction extensions without implementing a new `Config`. The value is encoded against the extension type from runtime metadata, which fixes signing on chains such as Paseo Asset Hub. `DefaultTransactionExtensions<T>` and its `Params` become structs with private fields, so custom values can travel alongside the known ones. `known()`, `known_mut()` and `custom()` preserve access to them, and the tuples live on as `KnownDefaultTransactionExtensions<T>` and `KnownDefaultExtrinsicParams<T>`.
A custom extension name the runtime does not declare was silently ignored, so a typo produced a transaction signed without the extension the caller asked for. Reject it instead, naming the extension. Tests move to `CheckWeight` and `WeightReclaim`, which the bundled metadata actually declares.
f6cd585 to
62050a4
Compare
A V5 extrinsic carries every extension value, including custom ones on either side of the authorization extension. Pin those bytes, and record why a custom extension can never report itself as an authorization extension.
62050a4 to
882503c
Compare
lexnv
left a comment
There was a problem hiding this comment.
Nice job here @DenzelPenzel! Feel free to merge after addressing Tarik's comments and the tiny ones from my side 🙏
Use frame-decode's best_v5_general_transaction_extension_version to choose the newest extension version for which all required extension data is available, falling back to older versions otherwise. A chain adding a new non-optional extension no longer breaks clients without a value for it, and supplying one via custom_extension opts back into the newer version. extrinsic_extension_version_info now yields versions newest-first, as the frame-decode trait expects; the previous ascending order would have made the fallback always pick the oldest version. Also, per review: custom extension values are validated when the params are used to build extensions (the name must be declared in some extension version, the value must encode to the declared type, implicit data must be empty, duplicates are caught via a map entry), and the default params types derive Debug.
9194987 to
fec47d2
Compare
Summary
Allow callers to provide metadata-aware values for custom transaction extensions without implementing a new
Config:The value is encoded against the extension type from runtime metadata. This fixes signing on chains such as Paseo Asset Hub, where
RestrictOriginscontains a barebool.Fixes #2265.
Implementation
Breaking changes
DefaultTransactionExtensions<T>and itsParamstype changed from public tuple aliases to structs with private fields, so that custom extension values can be carried alongside the known ones. The tuples live on under new names:KnownDefaultTransactionExtensions<T>andKnownDefaultExtrinsicParams<T>.Code which configures transactions via the builder and passes the params through opaquely is source-compatible and produces byte-identical transactions. Code which relied on the tuple shape of the params migrates as follows:
DefaultExtrinsicParams::from_known(tuple)params.5 = ...params.known_mut().5 = ...¶ms.7¶ms.known().7Given the above, this should land in 0.51 rather than a 0.50.x patch.
Notes
cargo fmtfix for two test asserts that landed unformatted on master.