[0.43.0] - 2025-07-17
This is a reasonably small release which is mainly bug fixing, but has a couple of changes I'd like to elaborate on:
Remove codec::Encode
and codec::Decode
derives from generated APIs by default (#2008)
When generating an API using the #[subxt::subxt(...)]
macro (or programatically via subxt-codegen
), we had always previously added parity_scale_codec::Encode
and parity_scale_codec::Decode
derives to all of the generated types. Most places in Subxt have not made use of these for a long time (relying instead on scale_encode::EncodeAsType
and scale_decode::DecodeAsType
, since they allow encoding and encoding which takes the type information into account and can more gracefully handle incompatibilities).
We eventually hit an issue to which the most appropriate fix was just to remove these derives.
If you still need the parity_scale_codec::Encode
or parity_scale_codec::Decode
derives on certain types, you have two options:
- Use the
derive_for_type
attr to add them back where needed, eg:#[subxt::subxt( ... derive_for_type( path = "staging_xcm::v3::multilocation::MultiLocation", derive = "parity_scale_codec::Encode, parity_scale_codec::Decode", recursive ) )]
- Use the
derive_for_all_types
attr to add them back everywhere, eg:#[subxt::subxt( ... derive_for_all_types = "parity_scale_codec::Encode, parity_scale_codec::Decode" )]
Prefer (1) where possible to reduce the amount of generated code, and reduce the likelihood of running into issues around those derives in certain edge cases.
This PR changes some things around storage keys to remove one last requirement for Encode
and Decode
derives, and also as a side effect changes api.storage().call_raw()
slightly to no longer also try to decode the resulting type via Decode
, leaving this to the user (and also meaning it's much easier now for the user to obtain the raw bytes for some storage entry).
In other words, instead of doing something like:
let (compact_len, metadata) = rt
.call_raw::<(Compact<u32>, frame_metadata::RuntimeMetadataPrefixed)>(
"Metadata_metadata",
None,
)
.await?;
You would now do:
let meta_bytes = rt.call_raw("Metadata_metadata", None).await?;
let (compact_len, metadata): (Compact<u32>, frame_metadata::RuntimeMetadataPrefixed) =
Decode::decode(&mut &*meta_bytes)?;
Address some issues around tx mortality (#2025)
Prior to this change, the intended behavior was that any transaction submitted via an OnlineClient
would have a mortality of 32 blocks by default, and any transaction submitted via an OfflineClient
would be immortal by default. A couple of issues were present or cropped up however:
- If you explicitly configure the mortality via setting params like
PolkadotExtrinsicParamsBuilder::new().mortal(32).build()
, theOfflineClient
transaction would still be immortal, because it didn't have enough information to properly configure the mortality as asked for (by virtue of being offline and unable to fetch it). - The intended behaviour turned out to have been broken, and transactions were being submitted as immortal even via the
OnlineClient
by default, unless mortality was explicitly configured. - There was no easy way to actually set the mortality for an
OfflineClient
transaction; you'd have to do something like this:let params = DefaultExtrinsicParamsBuilder::new(); params.5 = CheckMortalityParams::mortal_from_unchecked(for_n_blocks, from_block_n, from_block_hash);
With this PR, transactions are now mortal by default using the OnlineClient
, we now return an error if you try to construct a transaction with the OfflineClient
and try to use params.mortal(..)
when configuring it, and we expose params.mortal_from_unchecked(..)
to allow configuration for offline transactions without the ugly code above.
In this PR, we also discovered an issue decoding Eras
and fixed this, so that decoding the mortality of a transaction when it is mortal should now work.
Add FFI example (#2037)
I'd like to do a quick shoutout to @wassimans, who submitted an excellent example for how to interact with Subxt via the C FFI in Python and Node.JS. This is something I've wanted to add for a while, so it's lovely to see this new example which highlights one of the strengths of Subxt over Javascript based compatitors in the space.
All of the non-trivial changes in this release are listed below:
Added
- Add FFI example (#2037)
Changed
- Remove
codec::Encode
andcodec::Decode
derives from generated APIs by default (#2008) - Address some issues around tx mortality (#2025)
Fixed
- Fix 'subxt explore storage': don't turn keys to bytes (#2038)
- Refactor: improve nonce and block injection in extrinsic params (#2032)
- Improve docs for
at_latest
(#2035) - Clippy fixes for latest Rustc (#2033)
- docs: fix minor comment typos (#2027)
- chore: remove redundant backtick in comment (#2020)
- Keep codec attrs even when Encode/Decode not used (#2023)
- Run CI on v0.N.x branches or PRs to them for ease of backporting (#2017)
- De-dup types early in CLI/macro so that derives/substitutes work for de-duped types (#2015)
- If only one hasher, always treat any key as a single and not NMap key, even if it's a tuple. (#2010)