Skip to content

v0.28.0

Compare
Choose a tag to compare
@jsdw jsdw released this 12 Apr 10:08
· 476 commits to master since this release
v0.28.0
2a4da61

[0.28.0] - 2022-04-11

This is a fairly significant change; what follows is a description of the main changes to be aware of:

Unify how we encode and decode static and dynamic types (#842)

Prior to this, static types generated by codegen (ie subxt macro) would implement Encode and Decode from the parity-scale-codec library. This meant that they woule be encoded-to and decoded-from based on their shape. Dynamic types (eg the subxt::dynamic::Value type) would be encoded and decoded based on the node metadata instead.

This change makes use of the new scale-encode and scale-decode crates to auto-implement EncodeAsType and DecodeAsType on all of our static types. These traits allow types to take the node metadata into account when working out how best to encode and decode into them. By using metadata, we can be much more flexible/robust about how to encode/decode various types (as an example, nested transactions will now be portable across runtimes). Additionally, we can merge our codepaths for static and dynamic encoding/decoding, since both static and dynamic types can implement these traits. Read the PR description for more info.

A notable impact of this is that any types you wish to substitute when performing codegen (via the CLI tool or #[subxt] macro) must also implement EncodeAsType and DecodeAsType too. Substrate types, for instance, generally do not. To work around this, #886 introduces a Static type and enhances the type substitution logic so that you're able to wrap any types which only implement Encode and Decode to work (note that you lose out on the improvements from EncodeAsType and DecodeAsType when you do this):

#[subxt::subxt(
    runtime_metadata_path = "/path/to/metadata.scale",
    substitute_type(
        type = "sp_runtime::multiaddress::MultiAddress<A, B>",
        with = "::subxt::utils::Static<::sp_runtime::multiaddress::MultiAddress<A, B>>"
    )
)]
pub mod node_runtime {}

So, if you want to substitute in Substrate types, wrap them in ::subxt::utils::Static in the type substitution, as above. #886 also generally improves type substitution so that you can substitute the generic params in nested types, since it's required in the above.

Several types have been renamed as a result of this unification (though they aren't commonly made explicit use of). Additionally, to obtain the bytes from a storage address, instead of doing:

let addr_bytes = storage_address.to_bytes()

You must now do:

let addr_bytes = cxt.client().storage().address_bytes(&storage_address).unwrap();

This is because the address on it's own no longer requires as much static information, and relies more heavily now on the node metadata to encode it to bytes.

Expose Signer payload (#861)

This is not a breaking change, but notable in that is adds create_partial_signed_with_nonce and create_partial_signed to the TxClient to allow you to break extrinsic creation into two steps:

  1. building a payload, and then
  2. when a signature is provided, getting back an extrinsic ready to be submitted.

This allows a signer payload to be obtained from Subxt, handed off to some external application, and then once a signature has been obtained, that can be passed back to Subxt to complete the creation of an extrinsic. This opens the door to using browser wallet extensions, for instance, to sign Subxt payloads.

Stripping unneeded pallets from metadata (#879)

This is not a breaking change, but adds the ability to use the Subxt CLI tool to strip out all but some named list of pallets from a metadata bundle. Aside from allowing you to store a significantly smaller metadata bundle with only the APIs you need in it, it will also lead to faster codegen, since there's much less of it to do.

Use a command like subxt metadata --pallets Balances,System to select specific pallets. You can provide an existing metadata file to take that and strip it, outputting a smaller bundle. Alternately it will grab the metadata from a local node and strip that before outputting.

Dispatch error changes (#878)

The DispatchError returned from either attempting to submit an extrinsic, or from calling .dry_run() has changed. It's now far more complete with respect to the information it returns in each case, and the interface has been tidied up. Changes include:

  • For ModuleError's, instead of err.pallet and err.error, you can obtain error details using let details = err.details()? and then details.pallet() and details.error().
  • DryRunResult is now a custom enum with 3 states, Success, DispatchError or TransactionValidityError. The middle of these contains much more information than previously.
  • Errors in general have been marked #[non_exahustive] since they could grow and change at any time. (Owing to our use of scale-decode internally, we are not so contrained when it comes to having precise variant indexes or anything now, and can potentially deprecate rather than remove old variants as needed).
  • On a lower level, the rpc.dry_run() RPC call now returns the raw dry run bytes which can then be decoded with the help of metadata into our DryRunResult.

Extrinsic submission changes (#897)

It was found by @furoxr that Substrate nodes will stop sending transaction progress events under more circumstances than we originally expected. Thus, now calls like wait_for_finalized() and wait_for_in_block() will stop waiting for events when any of the following is sent from the node:

  • Usurped
  • Finalized
  • FinalityTimeout
  • Invalid
  • Dropped

Previously we'd only close the subscription and stop waiting when we saw a Finalized or FinalityTimeout event. Thanks for digging into this @furoxr!

Add at_latest() method (#900 and #904)

A small breaking change; previously we had .at(None) or .at(Some(block_hash)) methods in a few places to obtain things at either the latest block or some specific block hash.

This API has been clarified; we now have .at_latest() to obtain the thing at the latest block, or .at(block_hash) (note; no more option) to obtain the thing at some fixed block hash. In a few instances this has allowed us to ditch the async from the .at() call.

That covers the larger changes in this release. For more details, have a look at all of the notable PRs since the last release here:

Added

  • added at_latest (#900 and #904)
  • Metadata: Retain a subset of metadata pallets (#879)
  • Expose signer payload to allow external signing (#861)
  • Add ink! as a user of subxt (#837)
  • codegen: Add codegen error (#841)
  • codegen: allow documentation to be opted out of (#843)
  • re-export sp_core and sp_runtime (#853)
  • Allow generating only runtime types in subxt macro (#845)
  • Add 'Static' type and improve type substitution codegen to accept it (#886)

Changed

  • Improve Dispatch Errors (#878)
  • Use scale-encode and scale-decode to encode and decode based on metadata (#842)
  • For smoldot: support deserializing block number in header from hex or number (#863)
  • Bump Substrate dependencies to latest (#905)

Fixed

  • wait_for_finalized behavior if the tx dropped, usurped or invalid (#897)