diff --git a/CHANGELOG.md b/CHANGELOG.md index 6ba5324029..397f3c7eb9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,210 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.23.0] - 2022-08-11 + +This is one of the most significant releases to date in Subxt, and carries with it a number of significant breaking changes, but in exchange, a number of significant improvements. The most significant PR is [#593](https://github.com/paritytech/subxt/pull/593); the fundamental change that this makes is to separate creating a query/transaction/address from submitting it. This gives us flexibility when creating queries; they can be either dynamically or statically generated, but also flexibility in our client, enabling methods to be exposed for online or offline use. + +The best place to look to get a feel for what's changed, aside from the documentation itself, is the `examples` folder. What follows are some examples of the changes you'll need to make, which all follow a similar pattern: + +### Submitting a transaction + +Previously, we'd build a client which is tied to the static codegen, and then use the client to build and submit a transaction like so: + +```rust +let api = ClientBuilder::new() + .build() + .await? + .to_runtime_api::>>(); + +let balance_transfer = api + .tx() + .balances() + .transfer(dest, 10_000)? + .sign_and_submit_then_watch_default(&signer) + .await? + .wait_for_finalized_success() + .await?; +``` + +Now, we build a transaction separately (in this case, using static codegen to guide us as before) and then submit it to a client like so: + +``` rust +let api = OnlineClient::::new().await?; + +let balance_transfer_tx = polkadot::tx().balances().transfer(dest, 10_000); + +let balance_transfer = api + .tx() + .sign_and_submit_then_watch_default(&balance_transfer_tx, &signer) + .await? + .wait_for_finalized_success() + .await?; +``` + +See the `examples/examples/submit_and_watch.rs` example for more. + +### Fetching a storage entry + +Previously, we build and submit a storage query in one step: + +```rust +let api = ClientBuilder::new() + .build() + .await? + .to_runtime_api::>>(); + +let entry = api.storage().staking().bonded(&addr, None).await; +``` + +Now, we build the storage query separately and submit it to the client: + +```rust +let api = OnlineClient::::new().await?; + +let staking_bonded = polkadot::storage().staking().bonded(&addr); + +let entry = api.storage().fetch(&staking_bonded, None).await; +``` + +Note that previously, the generated code would do the equivalent of `fetch_or_default` if possible, or `fetch` if no default existed. You must now decide whether to: +- fetch an entry, returning `None` if it's not found (`api.storage().fetch(..)`), or +- fetch an entry, returning the default if it's not found (`api.storage().fetch_or_default(..)`). + +The static types will protect you against using `fetch_or_default` when no such default exists, and so the recommendation is to try changing all storage requests to use `fetch_or_default`, falling back to using `fetch` where doing so leads to compile errors. + +See `examples/examples/concurrent_storage_requests.rs` for an example of fetching entries. + +### Iterating over storage entries + +Previously: + +```rust +let api = ClientBuilder::new() + .build() + .await? + .to_runtime_api::>>(); + +let mut iter = api + .storage() + .xcm_pallet() + .version_notifiers_iter(None) + .await?; + +while let Some((key, value)) = iter.next().await? { + // ... +} +``` + +Now, as before, building the storage query to iterate over is separate from using it: + +```rust +let api = OnlineClient::::new().await?; + +let key_addr = polkadot::storage() + .xcm_pallet() + .version_notifiers_root(); + +let mut iter = api + .storage() + .iter(key_addr, 10, None).await?; + +while let Some((key, value)) = iter.next().await? { + // ... +} +``` + +Note that the `_root()` suffix on generated storage queries accesses the root entry at that address, +and is available when the address is a map that can be iterated over. By not appending `_root()`, you'll +be asked to provide the values needed to access a specific entry in the map. + +See the `examples/examples/storage_iterating.rs` example for more. + +### Accessing constants + +Before, we'd build a client and use the client to select and query a constant: + +```rust +let api = ClientBuilder::new() + .build() + .await? + .to_runtime_api::>>(); + +let existential_deposit = api + .constants() + .balances() + .existential_deposit()?; +``` + +Now, similar to the other examples, we separately build a constant _address_ and provide that address to the client to look it up: + +```rust +let api = OnlineClient::::new().await?; + +let address = polkadot::constants() + .balances() + .existential_deposit(); + +let existential_deposit = api.constants().at(&address)?; +``` + +See the `examples/examples/fetch_constants.rs` example for more. + +### Subscribing to events + +Event subscriptions themselves are relatively unchanged (although the data you can access/get back has changed a little). Before: + +```rust +let api = ClientBuilder::new() + .build() + .await? + .to_runtime_api::>>(); + +let mut event_sub = api.events().subscribe().await?; + +while let Some(events) = event_sub.next().await { + // ... +} +``` + +Now, we simply swap the client out for our new one, and the rest is similar: + +```rust +let api = OnlineClient::::new().await?; + +let mut event_sub = api.events().subscribe().await?; + +while let Some(events) = event_sub.next().await { + // ... +} +``` + +See the `examples/examples/subscribe_all_events.rs` example for more. + +The general pattern, as seen above, is that we break apart constructing a query/address and using it. You can now construct queries dynamically instead and forego all static codegen by using the functionality exposed in the `subxt::dynamic` module instead. + +Other smaller breaking changes have happened, but they should be easier to address by following compile errors. + +For more details about all of the changes, the full commit history since the last release is as follows: + +### Added + +- Expose the extrinsic hash from TxProgress ([#614](https://github.com/paritytech/subxt/pull/614)) +- Add support for `ws` in `subxt-cli` ([#579](https://github.com/paritytech/subxt/pull/579)) +- Expose the SCALE encoded call data of an extrinsic ([#573](https://github.com/paritytech/subxt/pull/573)) +- Validate absolute path for `substitute_type` ([#577](https://github.com/paritytech/subxt/pull/577)) + +### Changed + +- Rework Subxt API to support offline and dynamic transactions ([#593](https://github.com/paritytech/subxt/pull/593)) +- Use scale-decode to help optimise event decoding ([#607](https://github.com/paritytech/subxt/pull/607)) +- Decode raw events using scale_value and return the decoded Values, too ([#576](https://github.com/paritytech/subxt/pull/576)) +- dual license ([#590](https://github.com/paritytech/subxt/pull/590)) +- Don't hash constant values; only their types ([#587](https://github.com/paritytech/subxt/pull/587)) +- metadata: Exclude `field::type_name` from metadata validation ([#595](https://github.com/paritytech/subxt/pull/595)) +- Bump Swatinem/rust-cache from 1.4.0 to 2.0.0 ([#597](https://github.com/paritytech/subxt/pull/597)) +- Update jsonrpsee requirement from 0.14.0 to 0.15.1 ([#603](https://github.com/paritytech/subxt/pull/603)) + ## [0.22.0] - 2022-06-20 With this release, subxt can subscribe to the node's runtime upgrades to ensure that the metadata is updated and diff --git a/cli/Cargo.toml b/cli/Cargo.toml index 63fd287a28..397c003fc3 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "subxt-cli" -version = "0.22.0" +version = "0.23.0" authors = ["Parity Technologies "] edition = "2021" @@ -16,9 +16,9 @@ path = "src/main.rs" [dependencies] # perform subxt codegen -subxt-codegen = { version = "0.22.0", path = "../codegen" } +subxt-codegen = { version = "0.23.0", path = "../codegen" } # perform node compatibility -subxt-metadata = { version = "0.22.0", path = "../metadata" } +subxt-metadata = { version = "0.23.0", path = "../metadata" } # parse command line args structopt = "0.3.25" # colourful error reports diff --git a/codegen/Cargo.toml b/codegen/Cargo.toml index e6500ca2fd..1936cfd6af 100644 --- a/codegen/Cargo.toml +++ b/codegen/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "subxt-codegen" -version = "0.22.0" +version = "0.23.0" authors = ["Parity Technologies "] edition = "2021" @@ -20,7 +20,7 @@ proc-macro-error = "1.0.4" quote = "1.0.8" syn = "1.0.58" scale-info = { version = "2.0.0", features = ["bit-vec"] } -subxt-metadata = { version = "0.22.0", path = "../metadata" } +subxt-metadata = { version = "0.23.0", path = "../metadata" } [dev-dependencies] bitvec = { version = "1.0.0", default-features = false, features = ["alloc"] } diff --git a/examples/Cargo.toml b/examples/Cargo.toml index 7f5ab9d08c..00d8ef480d 100644 --- a/examples/Cargo.toml +++ b/examples/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "subxt-examples" -version = "0.22.0" +version = "0.23.0" authors = ["Parity Technologies "] edition = "2021" publish = false diff --git a/macro/Cargo.toml b/macro/Cargo.toml index 2a3f94abc2..b88d57d0b9 100644 --- a/macro/Cargo.toml +++ b/macro/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "subxt-macro" -version = "0.22.0" +version = "0.23.0" authors = ["Parity Technologies "] edition = "2021" autotests = false @@ -19,4 +19,4 @@ darling = "0.14.0" proc-macro-error = "1.0.4" syn = "1.0.58" -subxt-codegen = { path = "../codegen", version = "0.22.0" } +subxt-codegen = { path = "../codegen", version = "0.23.0" } diff --git a/metadata/Cargo.toml b/metadata/Cargo.toml index 1c2e0787ef..6737037b60 100644 --- a/metadata/Cargo.toml +++ b/metadata/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "subxt-metadata" -version = "0.22.0" +version = "0.23.0" authors = ["Parity Technologies "] edition = "2021" autotests = false diff --git a/subxt/Cargo.toml b/subxt/Cargo.toml index 3d5229e408..4c11208c44 100644 --- a/subxt/Cargo.toml +++ b/subxt/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "subxt" -version = "0.22.0" +version = "0.23.0" authors = ["Parity Technologies "] edition = "2021" @@ -33,8 +33,8 @@ thiserror = "1.0.24" tracing = "0.1.34" parking_lot = "0.12.0" -subxt-macro = { version = "0.22.0", path = "../macro" } -subxt-metadata = { version = "0.22.0", path = "../metadata" } +subxt-macro = { version = "0.23.0", path = "../macro" } +subxt-metadata = { version = "0.23.0", path = "../metadata" } sp-core = { version = "6.0.0", default-features = false } sp-runtime = "6.0.0" diff --git a/subxt/src/lib.rs b/subxt/src/lib.rs index 53b0a78c08..d7196e883f 100644 --- a/subxt/src/lib.rs +++ b/subxt/src/lib.rs @@ -34,10 +34,13 @@ //! //! # Generating runtime types //! -//! Subxt can generate types at compile time to help you interact with a node. The metadata can be downloaded using the -//! [subxt-cli](https://crates.io/crates/subxt-cli) tool. +//! Subxt can optionally generate types at compile time to help you interact with a node. These types are +//! generated using metadata which can be downloaded from a node using the [subxt-cli](https://crates.io/crates/subxt-cli) +//! tool. These generated types provide a degree of type safety when interacting with a node that is compatible with +//! the metadata that they were generated using. We also do runtime checks in case the node you're talking to has +//! deviated from the types you're using to communicate with it (see below). //! -//! To generate the types, use the `subxt` attribute which points at downloaded static metadata. +//! To generate the types, use the `subxt` macro and point it at the metadata you've downloaded, like so: //! //! ```ignore //! #[subxt::subxt(runtime_metadata_path = "metadata.scale")] @@ -47,9 +50,12 @@ //! For more information, please visit the [subxt-codegen](https://docs.rs/subxt-codegen/latest/subxt_codegen/) //! documentation. //! +//! You can opt to skip this step and use dynamic queries to talk to nodes instead, which can be useful in some cases, +//! but doesn't provide any type safety. +//! //! # Interacting with the API //! -//! Once instantiated, a client, exposes four functions: +//! Once instantiated, a client exposes four core functions: //! - `.tx()` for submitting extrinsics/transactions. See [`crate::tx::TxClient`] for more details, or see //! the [balance_transfer](../examples/examples/balance_transfer.rs) example. //! - `.storage()` for fetching and iterating over storage entries. See [`crate::storage::StorageClient`] for more details, or see @@ -86,13 +92,20 @@ //! } //! # } //! ``` +//! ## Opting out of static validation +//! +//! The static types that are used to query/access information are validated by default, to make sure that they are +//! compatible with the node being queried. You can generally call `.unvalidated()` on these static types to +//! disable this validation. //! //! # Runtime Updates //! -//! There are cases when the node would perform a runtime update, and the runtime node's metadata would be -//! out of sync with the subxt's metadata. +//! The node you're connected to may occasionally perform runtime updates while you're connected, which would ordinarily +//! leave the runtime state of the node out of sync with the information Subxt requires to do things like submit +//! transactions. //! -//! The `UpdateClient` API keeps the `RuntimeVersion` and `Metadata` of the client synced with the target node. +//! If this is a concern, you can use the `UpdateClient` API to keep the `RuntimeVersion` and `Metadata` of the client +//! synced with the target node. //! //! Please visit the [subscribe_runtime_updates](../examples/examples/subscribe_runtime_updates.rs) example for more details. diff --git a/testing/integration-tests/Cargo.toml b/testing/integration-tests/Cargo.toml index d12da76658..123dbd140e 100644 --- a/testing/integration-tests/Cargo.toml +++ b/testing/integration-tests/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "integration-tests" -version = "0.22.0" +version = "0.23.0" authors = ["Parity Technologies "] edition = "2021" @@ -26,8 +26,8 @@ sp-core = { version = "6.0.0", default-features = false } sp-keyring = "6.0.0" sp-runtime = "6.0.0" syn = "1.0.0" -subxt = { version = "0.22.0", path = "../../subxt" } -subxt-codegen = { version = "0.22.0", path = "../../codegen" } +subxt = { version = "0.23.0", path = "../../subxt" } +subxt-codegen = { version = "0.23.0", path = "../../codegen" } test-runtime = { path = "../test-runtime" } tokio = { version = "1.8", features = ["macros", "time"] } tracing = "0.1.34" diff --git a/testing/test-runtime/Cargo.toml b/testing/test-runtime/Cargo.toml index 63a9e71bc6..83e0808b24 100644 --- a/testing/test-runtime/Cargo.toml +++ b/testing/test-runtime/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "test-runtime" -version = "0.22.0" +version = "0.23.0" edition = "2021" [dependencies] diff --git a/testing/ui-tests/Cargo.toml b/testing/ui-tests/Cargo.toml index a2f9168d1b..b3d149e094 100644 --- a/testing/ui-tests/Cargo.toml +++ b/testing/ui-tests/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ui-tests" -version = "0.22.0" +version = "0.23.0" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html