fix: Convert vendor/pezkuwi-subxt from submodule to regular directory
This commit is contained in:
+103
@@ -0,0 +1,103 @@
|
||||
// Copyright 2019-2025 Parity Technologies (UK) Ltd.
|
||||
// This file is dual-licensed as Apache-2.0 or GPL-3.0.
|
||||
// see LICENSE for license details.
|
||||
|
||||
//! # Blocks
|
||||
//!
|
||||
//! The [blocks API](crate::blocks::BlocksClient) in Subxt unifies many of the other interfaces, and
|
||||
//! allows you to:
|
||||
//!
|
||||
//! - Access information about specific blocks (see [`crate::blocks::BlocksClient::at()`] and
|
||||
//! [`crate::blocks::BlocksClient::at_latest()`]).
|
||||
//! - Subscribe to [all](crate::blocks::BlocksClient::subscribe_all()),
|
||||
//! [best](crate::blocks::BlocksClient::subscribe_best()) or
|
||||
//! [finalized](crate::blocks::BlocksClient::subscribe_finalized()) blocks as they are produced.
|
||||
//! **Prefer to subscribe to finalized blocks unless you know what you're doing.**
|
||||
//!
|
||||
//! In either case, you'll end up with [`crate::blocks::Block`]'s, from which you can access various
|
||||
//! information about the block, such a the [header](crate::blocks::Block::header()),
|
||||
//! [block number](crate::blocks::Block::number()) and [body (the extrinsics)](crate::blocks::Block::extrinsics()).
|
||||
//! [`crate::blocks::Block`]'s also provide shortcuts to other Subxt APIs that will operate at the
|
||||
//! given block:
|
||||
//!
|
||||
//! - [storage](crate::blocks::Block::storage()),
|
||||
//! - [events](crate::blocks::Block::events())
|
||||
//! - [runtime APIs](crate::blocks::Block::runtime_api())
|
||||
//!
|
||||
//! Aside from these links to other Subxt APIs, the main thing that we can do here is iterate over and
|
||||
//! decode the extrinsics in a block body.
|
||||
//!
|
||||
//! ## Decoding Extrinsics
|
||||
//!
|
||||
//! Given a block, you can [download the block body](crate::blocks::Block::extrinsics()) and
|
||||
//! [iterate over the extrinsics](crate::blocks::Extrinsics::iter) stored within it. The extrinsics yielded are of type
|
||||
//! [ExtrinsicDetails](crate::blocks::ExtrinsicDetails), which is just a blob of bytes that also stores which
|
||||
//! pallet and call in that pallet it belongs to. It also contains information about signed extensions that
|
||||
//! have been used for submitting this extrinsic.
|
||||
//!
|
||||
//! To use the extrinsic, you probably want to decode it into a concrete Rust type. These Rust types representing
|
||||
//! extrinsics from different pallets can be generated from metadata using the subxt macro or the CLI tool.
|
||||
//!
|
||||
//! When decoding the extrinsic into a static type you have two options:
|
||||
//!
|
||||
//! ### Statically decode the extrinsics into [the root extrinsic type](crate::blocks::ExtrinsicDetails::as_root_extrinsic())
|
||||
//!
|
||||
//! The root extrinsic type generated by subxt is a Rust enum with one variant for each pallet. Each of these
|
||||
//! variants has a field that is another enum whose variants cover all calls of the respective pallet.
|
||||
//! If the extrinsic bytes are valid and your metadata matches the chain's metadata, decoding the bytes of an extrinsic into
|
||||
//! this root extrinsic type should always succeed.
|
||||
//!
|
||||
//! This example shows how to subscribe to blocks and decode the extrinsics in each block into the root extrinsic type.
|
||||
//! Once we get hold of the [ExtrinsicDetails](crate::blocks::ExtrinsicDetails), we can decode it statically or dynamically.
|
||||
//! We can also access details about the extrinsic, including the associated events and transaction extensions.
|
||||
//!
|
||||
//! ```rust,ignore
|
||||
#![doc = include_str!("../../../examples/blocks_subscribing.rs")]
|
||||
//! ```
|
||||
//!
|
||||
//! ### Statically decode the extrinsic into [a specific pallet call](crate::blocks::ExtrinsicDetails::as_extrinsic())
|
||||
//!
|
||||
//! This is useful if you are expecting a specific extrinsic to be part of some block. If the extrinsic you try to decode
|
||||
//! is a different extrinsic, an `Ok(None)` value is returned from [`as_extrinsic::<T>()`](crate::blocks::ExtrinsicDetails::as_extrinsic());
|
||||
//!
|
||||
//! If you are only interested in finding specific extrinsics in a block, you can also [iterate over all of them](crate::blocks::Extrinsics::find),
|
||||
//! get only [the first one](crate::blocks::Extrinsics::find_first), or [the last one](crate::blocks::Extrinsics::find_last).
|
||||
//!
|
||||
//! The following example monitors `TransferKeepAlive` extrinsics on the Polkadot network.
|
||||
//! We statically decode them and access the [tip](crate::blocks::ExtrinsicTransactionExtensions::tip()) and
|
||||
//! [account nonce](crate::blocks::ExtrinsicTransactionExtensions::nonce()) transaction extensions.
|
||||
//!
|
||||
//! ```rust,ignore
|
||||
#![doc = include_str!("../../../examples/block_decoding_static.rs")]
|
||||
//! ```
|
||||
//!
|
||||
//! ### Dynamically decode the extrinsic
|
||||
//!
|
||||
//! Sometimes you might use subxt with metadata that is not known at compile time. In this case, you do not
|
||||
//! have access to a statically generated interface module that contains the relevant Rust types. You can
|
||||
//! [decode ExtrinsicDetails dynamically](crate::blocks::ExtrinsicDetails::decode_as_fields()), which gives
|
||||
//! you access to it's fields as a [scale value composite](scale_value::Composite). The following example
|
||||
//! looks for signed extrinsics on the Polkadot network and retrieves their pallet name, variant name, data
|
||||
//! fields and transaction extensions dynamically. Notice how we do not need to use code generation via the
|
||||
//! subxt macro. The only fixed component we provide is the [PolkadotConfig](crate::config::PolkadotConfig).
|
||||
//! Other than that it works in a chain-agnostic way:
|
||||
//!
|
||||
//! ```rust,ignore
|
||||
#![doc = include_str!("../../../examples/block_decoding_dynamic.rs")]
|
||||
//! ```
|
||||
//!
|
||||
//! ## Decoding transaction extensions
|
||||
//!
|
||||
//! Extrinsics can contain transaction extensions. The transaction extensions can be different across chains.
|
||||
//! The [Config](crate::Config) implementation for your chain defines which transaction extensions you expect.
|
||||
//! Once you get hold of the [ExtrinsicDetails](crate::blocks::ExtrinsicDetails) for an extrinsic you are interested in,
|
||||
//! you can try to [get its transaction extensions](crate::blocks::ExtrinsicDetails::transaction_extensions()).
|
||||
//! These are only available on V4 signed extrinsics or V5 general extrinsics. You can try to
|
||||
//! [find a specific transaction extension](crate::blocks::ExtrinsicTransactionExtensions::find), in the returned
|
||||
//! [transaction extensions](crate::blocks::ExtrinsicTransactionExtensions).
|
||||
//!
|
||||
//! Subxt also provides utility functions to get the [tip](crate::blocks::ExtrinsicTransactionExtensions::tip()) and
|
||||
//! the [account nonce](crate::blocks::ExtrinsicTransactionExtensions::nonce()) associated with an extrinsic, given
|
||||
//! its transaction extensions. If you prefer to do things dynamically you can get the data of the transaction extension
|
||||
//! as a [scale value](crate::blocks::ExtrinsicTransactionExtension::value()).
|
||||
//!
|
||||
@@ -0,0 +1,55 @@
|
||||
// Copyright 2019-2025 Parity Technologies (UK) Ltd.
|
||||
// This file is dual-licensed as Apache-2.0 or GPL-3.0.
|
||||
// see LICENSE for license details.
|
||||
|
||||
//! # Constants
|
||||
//!
|
||||
//! There are various constants stored in a node; the types and values of these are defined in a
|
||||
//! runtime, and can only change when the runtime is updated. Much like [`super::storage`], we can
|
||||
//! query these using Subxt by taking the following steps:
|
||||
//!
|
||||
//! 1. [Constructing a constant query](#constructing-a-query).
|
||||
//! 2. [Submitting the query to get back the associated value](#submitting-it).
|
||||
//!
|
||||
//! ## Constructing a constant query
|
||||
//!
|
||||
//! We can use the statically generated interface to build constant queries:
|
||||
//!
|
||||
//! ```rust,no_run,standalone_crate
|
||||
//! #[subxt::subxt(runtime_metadata_path = "../artifacts/polkadot_metadata_full.scale")]
|
||||
//! pub mod polkadot {}
|
||||
//!
|
||||
//! let constant_query = polkadot::constants().system().block_length();
|
||||
//! ```
|
||||
//!
|
||||
//! Alternately, we can dynamically construct a constant query. A dynamic query needs the return
|
||||
//! type to be specified, where we can use [`crate::dynamic::Value`] if unsure:
|
||||
//!
|
||||
//! ```rust,no_run,standalone_crate
|
||||
//! use subxt::dynamic::Value;
|
||||
//!
|
||||
//! let storage_query = subxt::dynamic::constant::<Value>("System", "BlockLength");
|
||||
//! ```
|
||||
//!
|
||||
//! ## Submitting it
|
||||
//!
|
||||
//! Call [`crate::constants::ConstantsClient::at()`] to return and decode the constant into the
|
||||
//! type given by the address, or [`crate::constants::ConstantsClient::bytes_at()`] to return the
|
||||
//! raw bytes for some constant.
|
||||
//!
|
||||
//! Constant values are pulled directly out of the node metadata which Subxt has
|
||||
//! already acquired, and so this function requires no network access and is available from a
|
||||
//! [`crate::OfflineClient`].
|
||||
//!
|
||||
//! Here's an example using a static query:
|
||||
//!
|
||||
//! ```rust,ignore
|
||||
#![doc = include_str!("../../../examples/constants_static.rs")]
|
||||
//! ```
|
||||
//!
|
||||
//! And here's one using a dynamic query:
|
||||
//!
|
||||
//! ```rust,ignore
|
||||
#![doc = include_str!("../../../examples/constants_dynamic.rs")]
|
||||
//! ```
|
||||
//!
|
||||
@@ -0,0 +1,69 @@
|
||||
// Copyright 2019-2025 Parity Technologies (UK) Ltd.
|
||||
// This file is dual-licensed as Apache-2.0 or GPL-3.0.
|
||||
// see LICENSE for license details.
|
||||
|
||||
//! # Custom Values
|
||||
//!
|
||||
//! Substrate-based chains can expose custom values in their metadata.
|
||||
//! Each of these values:
|
||||
//!
|
||||
//! - can be accessed by a unique __name__.
|
||||
//! - refers to a concrete __type__ stored in the metadata.
|
||||
//! - contains a scale encoded __value__ of that type.
|
||||
//!
|
||||
//! ## Getting a custom value
|
||||
//!
|
||||
//! First, you must construct an address to access a custom value. This can be either:
|
||||
//! - a raw [`str`] which assumes the return type to be the dynamic [`crate::dynamic::Value`] type,
|
||||
//! - created via [`dynamic`](crate::custom_values::dynamic) function whereby you set the return type
|
||||
//! that you want back,
|
||||
//! - created via statically generated addresses as part of the `#[subxt]` macro which define the return type.
|
||||
//!
|
||||
//! With an address, use [`at`](crate::custom_values::CustomValuesClient::at) to access and decode specific values, and
|
||||
//! [`bytes_at`](crate::custom_values::CustomValuesClient::bytes_at) to access the raw bytes.
|
||||
//!
|
||||
//! ## Examples
|
||||
//!
|
||||
//! Dynamically accessing a custom value using a [`str`] to select which one:
|
||||
//!
|
||||
//! ```rust,ignore
|
||||
//! use subxt::{OnlineClient, PolkadotConfig, ext::scale_decode::DecodeAsType};
|
||||
//! use subxt::dynamic::Value;
|
||||
//!
|
||||
//! let api = OnlineClient::<PolkadotConfig>::new().await?;
|
||||
//! let custom_value_client = api.custom_values();
|
||||
//! let foo: Value = custom_value_client.at("foo")?;
|
||||
//! ```
|
||||
//!
|
||||
//! Use the [`dynamic`](crate::custom_values::dynamic) function to select the return type:
|
||||
//!
|
||||
//! ```rust,ignore
|
||||
//! use subxt::{OnlineClient, PolkadotConfig, ext::scale_decode::DecodeAsType};
|
||||
//!
|
||||
//! #[derive(Decode, DecodeAsType, Debug)]
|
||||
//! struct Foo {
|
||||
//! n: u8,
|
||||
//! b: bool,
|
||||
//! }
|
||||
//!
|
||||
//! let api = OnlineClient::<PolkadotConfig>::new().await?;
|
||||
//! let custom_value_client = api.custom_values();
|
||||
//! let custom_value_addr = subxt::custom_values::dynamic::<Foo>("foo");
|
||||
//! let foo: Foo = custom_value_client.at(&custom_value_addr)?;
|
||||
//! ```
|
||||
//!
|
||||
//! Alternatively we also provide a statically generated api for custom values:
|
||||
//!
|
||||
//! ```rust,ignore
|
||||
//! #[subxt::subxt(runtime_metadata_path = "some_metadata.scale")]
|
||||
//! pub mod interface {}
|
||||
//!
|
||||
//! let static_address = interface::custom().foo();
|
||||
//!
|
||||
//! let api = OnlineClient::<PolkadotConfig>::new().await?;
|
||||
//! let custom_value_client = api.custom_values();
|
||||
//!
|
||||
//! // Now the `at()` function already decodes the value into the Foo type:
|
||||
//! let foo = custom_value_client.at(&static_address)?;
|
||||
//! ```
|
||||
//!
|
||||
@@ -0,0 +1,49 @@
|
||||
// Copyright 2019-2025 Parity Technologies (UK) Ltd.
|
||||
// This file is dual-licensed as Apache-2.0 or GPL-3.0.
|
||||
// see LICENSE for license details.
|
||||
|
||||
//! # Events
|
||||
//!
|
||||
//! In the process of adding extrinsics to a block, they are executed. When extrinsics are executed,
|
||||
//! they normally produce events describing what's happening (at the very least, an event dictating whether
|
||||
//! the extrinsic has succeeded or failed). The node may also emit some events of its own as the block is
|
||||
//! processed.
|
||||
//!
|
||||
//! Events live in a single location in node storage which is overwritten at each block. Normal nodes tend to
|
||||
//! keep a snapshot of the state at a small number of previous blocks, so you can sometimes access
|
||||
//! older events by using [`crate::events::EventsClient::at()`] and providing an older block hash.
|
||||
//!
|
||||
//! When we submit transactions using Subxt, methods like [`crate::tx::TxProgress::wait_for_finalized_success()`]
|
||||
//! return [`crate::blocks::ExtrinsicEvents`], which can be used to iterate and inspect the events produced
|
||||
//! by that transaction being executed. We can also access _all_ of the events produced in a single block using one
|
||||
//! of these two interfaces:
|
||||
//!
|
||||
//! ```rust,no_run,standalone_crate
|
||||
//! # #[tokio::main]
|
||||
//! # async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
//! use subxt::client::OnlineClient;
|
||||
//! use subxt::config::PolkadotConfig;
|
||||
//!
|
||||
//! // Create client:
|
||||
//! let client = OnlineClient::<PolkadotConfig>::new().await?;
|
||||
//!
|
||||
//! // Get events from the latest block (use .at() to specify a block hash):
|
||||
//! let events = client.blocks().at_latest().await?.events().await?;
|
||||
//! // We can use this shorthand too:
|
||||
//! let events = client.events().at_latest().await?;
|
||||
//! # Ok(())
|
||||
//! # }
|
||||
//! ```
|
||||
//!
|
||||
//! Once we've loaded our events, we can iterate all events or search for specific events via
|
||||
//! methods like [`crate::events::Events::iter()`] and [`crate::events::Events::find()`]. See
|
||||
//! [`crate::events::Events`] and [`crate::events::EventDetails`] for more information.
|
||||
//!
|
||||
//! ## Example
|
||||
//!
|
||||
//! Here's an example which puts this all together:
|
||||
//!
|
||||
//! ```rust,ignore
|
||||
#![doc = include_str!("../../../examples/events.rs")]
|
||||
//! ```
|
||||
//!
|
||||
@@ -0,0 +1,51 @@
|
||||
// Copyright 2019-2025 Parity Technologies (UK) Ltd.
|
||||
// This file is dual-licensed as Apache-2.0 or GPL-3.0.
|
||||
// see LICENSE for license details.
|
||||
|
||||
//! # Light Client
|
||||
//!
|
||||
//! The light client based interface uses _Smoldot_ to connect to a _chain_, rather than an individual
|
||||
//! node. This means that you don't have to trust a specific node when interacting with some chain.
|
||||
//!
|
||||
//! This feature is currently unstable. Use the `unstable-light-client` feature flag to enable it.
|
||||
//! To use this in WASM environments, enable the `web` feature flag and disable the "native" one.
|
||||
//!
|
||||
//! To connect to a blockchain network, the Light Client requires a trusted sync state of the network,
|
||||
//! known as a _chain spec_. One way to obtain this is by making a `sync_state_genSyncSpec` RPC call to a
|
||||
//! trusted node belonging to the chain that you wish to interact with.
|
||||
//!
|
||||
//! Subxt exposes a utility method to obtain the chain spec: [`crate::utils::fetch_chainspec_from_rpc_node()`].
|
||||
//! Alternately, you can manually make an RPC call to `sync_state_genSyncSpec` like do (assuming a node running
|
||||
//! locally on port 9933):
|
||||
//!
|
||||
//! ```bash
|
||||
//! curl -H "Content-Type: application/json" -d '{"id":1, "jsonrpc":"2.0", "method": "sync_state_genSyncSpec", "params":[true]}' http://localhost:9933/ | jq .result > chain_spec.json
|
||||
//! ```
|
||||
//!
|
||||
//! ## Examples
|
||||
//!
|
||||
//! ### Basic Example
|
||||
//!
|
||||
//! This basic example uses some already-known chain specs to connect to a relay chain and parachain
|
||||
//! and stream information about their finalized blocks:
|
||||
//!
|
||||
//! ```rust,ignore
|
||||
#![doc = include_str!("../../../examples/light_client_basic.rs")]
|
||||
//! ```
|
||||
//!
|
||||
//! ### Connecting to a local node
|
||||
//!
|
||||
//! This example connects to a local chain and submits a transaction. To run this, you first need
|
||||
//! to have a local polkadot node running using the following command:
|
||||
//!
|
||||
//! ```text
|
||||
//! polkadot --dev --node-key 0000000000000000000000000000000000000000000000000000000000000001
|
||||
//! ```
|
||||
//!
|
||||
//! Then, the following code will download a chain spec from this local node, alter the bootnodes
|
||||
//! to point only to the local node, and then submit a transaction through it.
|
||||
//!
|
||||
//! ```rust,ignore
|
||||
#![doc = include_str!("../../../examples/light_client_local_node.rs")]
|
||||
//! ```
|
||||
//!
|
||||
@@ -0,0 +1,27 @@
|
||||
// Copyright 2019-2025 Parity Technologies (UK) Ltd.
|
||||
// This file is dual-licensed as Apache-2.0 or GPL-3.0.
|
||||
// see LICENSE for license details.
|
||||
|
||||
//! This modules contains examples of using Subxt; follow the links for more:
|
||||
//!
|
||||
//! - [Transactions](transactions)
|
||||
//! - [Storage](storage)
|
||||
//! - [Events](events)
|
||||
//! - [Constants](constants)
|
||||
//! - [Blocks](blocks)
|
||||
//! - [Runtime APIs](runtime_apis)
|
||||
//! - [Unstable Light Client](light_client)
|
||||
//! - [Custom Values](custom_values)
|
||||
//! - [RPC calls](rpc)
|
||||
//!
|
||||
//! Alternately, [go back](super).
|
||||
|
||||
pub mod blocks;
|
||||
pub mod constants;
|
||||
pub mod custom_values;
|
||||
pub mod events;
|
||||
pub mod light_client;
|
||||
pub mod rpc;
|
||||
pub mod runtime_apis;
|
||||
pub mod storage;
|
||||
pub mod transactions;
|
||||
@@ -0,0 +1,22 @@
|
||||
// Copyright 2019-2025 Parity Technologies (UK) Ltd.
|
||||
// This file is dual-licensed as Apache-2.0 or GPL-3.0.
|
||||
// see LICENSE for license details.
|
||||
|
||||
//! # RPC calls
|
||||
//!
|
||||
//! The RPC interface is provided by the [`pezkuwi_subxt_rpcs`] crate but re-exposed here. We have:
|
||||
//!
|
||||
//! - [`crate::backend::rpc::RpcClient`] and [`crate::backend::rpc::RpcClientT`]: the underlying type and trait
|
||||
//! which provides a basic RPC client.
|
||||
//! - [`crate::backend::legacy::rpc_methods`] and [`crate::backend::chain_head::rpc_methods`]: RPc methods that
|
||||
//! can be instantiated with an RPC client.
|
||||
//!
|
||||
//! See [`pezkuwi_subxt_rpcs`] or [`crate::ext::pezkuwi_subxt_rpcs`] for more.
|
||||
//!
|
||||
//! # Example
|
||||
//!
|
||||
//! Here's an example which calls some legacy JSON-RPC methods, and reuses the same connection to run a full Subxt client
|
||||
//!
|
||||
//! ```rust,ignore
|
||||
#![doc = include_str!("../../../examples/rpc_legacy.rs")]
|
||||
//! ```
|
||||
@@ -0,0 +1,80 @@
|
||||
// Copyright 2019-2025 Parity Technologies (UK) Ltd.
|
||||
// This file is dual-licensed as Apache-2.0 or GPL-3.0.
|
||||
// see LICENSE for license details.
|
||||
|
||||
//! # Runtime API interface
|
||||
//!
|
||||
//! The Runtime API interface allows Subxt to call runtime APIs exposed by certain pallets in order
|
||||
//! to obtain information. Much like [`super::storage`] and [`super::transactions`], Making a runtime
|
||||
//! call to a node and getting the response back takes the following steps:
|
||||
//!
|
||||
//! 1. [Constructing a runtime call](#constructing-a-runtime-call)
|
||||
//! 2. [Submitting it to get back the response](#submitting-it)
|
||||
//!
|
||||
//! **Note:** Runtime APIs are only available when using V15 metadata, which is currently unstable.
|
||||
//! You'll need to use `subxt metadata --version unstable` command to download the unstable V15 metadata,
|
||||
//! and activate the `unstable-metadata` feature in Subxt for it to also use this metadata from a node. The
|
||||
//! metadata format is unstable because it may change and break compatibility with Subxt at any moment, so
|
||||
//! use at your own risk.
|
||||
//!
|
||||
//! ## Constructing a runtime call
|
||||
//!
|
||||
//! We can use the statically generated interface to build runtime calls:
|
||||
//!
|
||||
//! ```rust,no_run,standalone_crate
|
||||
//! #[subxt::subxt(runtime_metadata_path = "../artifacts/polkadot_metadata_small.scale")]
|
||||
//! pub mod polkadot {}
|
||||
//!
|
||||
//! let runtime_call = polkadot::apis().metadata().metadata_versions();
|
||||
//! ```
|
||||
//!
|
||||
//! Alternately, we can dynamically construct a runtime call. The input type can be a tuple or
|
||||
//! vec or valid types implementing [`scale_encode::EncodeAsType`], and the output can be anything
|
||||
//! implementing [`scale_decode::DecodeAsType`]:
|
||||
//!
|
||||
//! ```rust,no_run
|
||||
//! use subxt::dynamic::Value;
|
||||
//!
|
||||
//! let runtime_call = subxt::dynamic::runtime_api_call::<(), Vec<u32>>(
|
||||
//! "Metadata",
|
||||
//! "metadata_versions",
|
||||
//! ()
|
||||
//! );
|
||||
//! ```
|
||||
//!
|
||||
//! All valid runtime calls implement [`crate::runtime_api::Payload`], a trait which
|
||||
//! describes how to encode the runtime call arguments and what return type to decode from the
|
||||
//! response.
|
||||
//!
|
||||
//! ## Submitting it
|
||||
//!
|
||||
//! Runtime calls can be handed to [`crate::runtime_api::RuntimeApi::call()`], which will submit
|
||||
//! them and hand back the associated response.
|
||||
//!
|
||||
//! ### Making a static Runtime API call
|
||||
//!
|
||||
//! The easiest way to make a runtime API call is to use the statically generated interface.
|
||||
//!
|
||||
//! ```rust,ignore
|
||||
#![doc = include_str!("../../../examples/runtime_apis_static.rs")]
|
||||
//! ```
|
||||
//!
|
||||
//! ### Making a dynamic Runtime API call
|
||||
//!
|
||||
//! If you'd prefer to construct the call at runtime, you can do this using the
|
||||
//! [`crate::dynamic::runtime_api_call`] method.
|
||||
//!
|
||||
//! ```rust,ignore
|
||||
#![doc = include_str!("../../../examples/runtime_apis_dynamic.rs")]
|
||||
//! ```
|
||||
//!
|
||||
//! ### Making a raw call
|
||||
//!
|
||||
//! This is generally discouraged in favour of one of the above, but may be necessary (especially if
|
||||
//! the node you're talking to does not yet serve V15 metadata). Here, you must manually encode
|
||||
//! the argument bytes and manually provide a type for the response bytes to be decoded into.
|
||||
//!
|
||||
//! ```rust,ignore
|
||||
#![doc = include_str!("../../../examples/runtime_apis_raw.rs")]
|
||||
//! ```
|
||||
//!
|
||||
@@ -0,0 +1,82 @@
|
||||
// Copyright 2019-2025 Parity Technologies (UK) Ltd.
|
||||
// This file is dual-licensed as Apache-2.0 or GPL-3.0.
|
||||
// see LICENSE for license details.
|
||||
|
||||
//! # Storage
|
||||
//!
|
||||
//! A Substrate based chain can be seen as a key/value database which starts off at some initial
|
||||
//! state, and is modified by the extrinsics in each block. This database is referred to as the
|
||||
//! node storage. With Subxt, you can query this key/value storage with the following steps:
|
||||
//!
|
||||
//! 1. [Constructing a storage query](#constructing-a-storage-query).
|
||||
//! 2. [Submitting the query to get back the associated entry](#submitting-it).
|
||||
//! 3. [Fetching](#fetching-storage-entries) or [iterating](#iterating-storage-entries) over that
|
||||
//! entry to retrieve the value or values within it.
|
||||
//!
|
||||
//! ## Constructing a storage query
|
||||
//!
|
||||
//! We can use the statically generated interface to build storage queries:
|
||||
//!
|
||||
//! ```rust,no_run,standalone_crate
|
||||
//! #[subxt::subxt(runtime_metadata_path = "../artifacts/polkadot_metadata_small.scale")]
|
||||
//! pub mod polkadot {}
|
||||
//!
|
||||
//! let storage_query = polkadot::storage().system().account();
|
||||
//! ```
|
||||
//!
|
||||
//! Alternately, we can dynamically construct a storage query. A dynamic query needs the input
|
||||
//! and return value types to be specified, where we can use [`crate::dynamic::Value`] if unsure.
|
||||
//!
|
||||
//! ```rust,no_run,standalone_crate
|
||||
//! use subxt::dynamic::Value;
|
||||
//!
|
||||
//! let storage_query = subxt::dynamic::storage::<(Value,), Value>("System", "Account");
|
||||
//! ```
|
||||
//!
|
||||
//! ## Submitting it
|
||||
//!
|
||||
//! Storage queries can be handed to various functions in [`crate::storage::StorageClientAt`] in order to
|
||||
//! obtain the associated values (also referred to as storage entries) back.
|
||||
//!
|
||||
//! The core API here is [`crate::storage::StorageClientAt::entry()`], which takes a query and looks up the
|
||||
//! corresponding storage entry, from which you can then fetch or iterate over the values contained within.
|
||||
//! [`crate::storage::StorageClientAt::fetch()`] and [`crate::storage::StorageClientAt::iter()`] are shorthand
|
||||
//! for this.
|
||||
//!
|
||||
//! When you wish to manually query some entry, [`crate::storage::StorageClientAt::fetch_raw()`] exists to take
|
||||
//! in raw bytes pointing at some storage value, and return the value bytes if possible. [`crate::storage::StorageClientAt::storage_version()`]
|
||||
//! and [`crate::storage::StorageClientAt::runtime_wasm_code()`] use this to retrieve the version of some storage API
|
||||
//! and the current Runtime WASM blob respectively.
|
||||
//!
|
||||
//! ### Fetching storage entries
|
||||
//!
|
||||
//! The simplest way to access storage entries is to construct a query and then call either
|
||||
//! [`crate::storage::StorageClientAt::fetch()`]:
|
||||
//!
|
||||
//! ```rust,ignore
|
||||
#![doc = include_str!("../../../examples/storage_fetch.rs")]
|
||||
//! ```
|
||||
//!
|
||||
//! For completeness, below is an example using a dynamic query instead. Dynamic queries can define the types that
|
||||
//! they wish to accept inputs and decode the return value into ([`crate::dynamic::Value`] can be used here anywhere we
|
||||
//! are not sure of the specific types).
|
||||
//!
|
||||
//! ```rust,ignore
|
||||
#![doc = include_str!("../../../examples/storage_fetch_dynamic.rs")]
|
||||
//! ```
|
||||
//!
|
||||
//! ### Iterating storage entries
|
||||
//!
|
||||
//! Many storage entries are maps of values; as well as fetching individual values, it's possible to
|
||||
//! iterate over all of the values stored at that location:
|
||||
//!
|
||||
//! ```rust,ignore
|
||||
#![doc = include_str!("../../../examples/storage_iterating.rs")]
|
||||
//! ```
|
||||
//!
|
||||
//! Here's the same logic but using dynamically constructed values instead:
|
||||
//!
|
||||
//! ```rust,ignore
|
||||
#![doc = include_str!("../../../examples/storage_iterating_dynamic.rs")]
|
||||
//! ```
|
||||
//!
|
||||
@@ -0,0 +1,202 @@
|
||||
// Copyright 2019-2025 Parity Technologies (UK) Ltd.
|
||||
// This file is dual-licensed as Apache-2.0 or GPL-3.0.
|
||||
// see LICENSE for license details.
|
||||
|
||||
//! # Transactions
|
||||
//!
|
||||
//! A transaction is an extrinsic that's signed (ie it originates from a given address). The purpose
|
||||
//! of extrinsics is to modify the node storage in a deterministic way, and so being able to submit
|
||||
//! transactions to a node is one of the core features of Subxt.
|
||||
//!
|
||||
//! > Note: the documentation tends to use the terms _extrinsic_ and _transaction_ interchangeably;
|
||||
//! > An extrinsic is some data that can be added to a block, and is either signed (a _transaction_)
|
||||
//! > or unsigned (an _inherent_). Subxt can construct either, but overwhelmingly you'll need to
|
||||
//! > sign the payload you'd like to submit.
|
||||
//!
|
||||
//! Submitting a transaction to a node consists of the following steps:
|
||||
//!
|
||||
//! 1. [Constructing a transaction payload to submit](#constructing-a-transaction-payload).
|
||||
//! 2. [Signing it](#signing-it).
|
||||
//! 3. [Submitting it (optionally with some additional parameters)](#submitting-it).
|
||||
//!
|
||||
//! We'll look at each of these steps in turn.
|
||||
//!
|
||||
//! ## Constructing a transaction payload
|
||||
//!
|
||||
//! We can use the statically generated interface to build transaction payloads:
|
||||
//!
|
||||
//! ```rust,no_run,standalone_crate
|
||||
//! #[subxt::subxt(runtime_metadata_path = "../artifacts/polkadot_metadata_small.scale")]
|
||||
//! pub mod polkadot {}
|
||||
//!
|
||||
//! let remark = "Hello there".as_bytes().to_vec();
|
||||
//! let tx_payload = polkadot::tx().system().remark(remark);
|
||||
//! ```
|
||||
//!
|
||||
//! > If you're not sure what types to import and use to build a given payload, you can use the
|
||||
//! > `subxt` CLI tool to generate the interface by using something like `subxt codegen | rustfmt >
|
||||
//! > interface.rs`, to see what types and things are available (or even just to use directly
|
||||
//! > instead of the [`#[subxt]`](crate::subxt) macro).
|
||||
//!
|
||||
//! Alternately, we can dynamically construct a transaction payload. This will not be type checked or
|
||||
//! validated until it's submitted:
|
||||
//!
|
||||
//! ```rust,no_run,standalone_crate
|
||||
//! use subxt::dynamic::Value;
|
||||
//!
|
||||
//! let tx_payload = subxt::dynamic::tx("System", "remark", vec![
|
||||
//! Value::from_bytes("Hello there")
|
||||
//! ]);
|
||||
//! ```
|
||||
//!
|
||||
//! The [`crate::dynamic::Value`] type is a dynamic type much like a `serde_json::Value` but instead
|
||||
//! represents any type of data that can be SCALE encoded or decoded. It can be serialized,
|
||||
//! deserialized and parsed from/to strings.
|
||||
//!
|
||||
//! A valid transaction payload is just something that implements the [`crate::tx::Payload`] trait;
|
||||
//! you can implement this trait on your own custom types if the built-in ones are not suitable for
|
||||
//! your needs.
|
||||
//!
|
||||
//! ## Signing it
|
||||
//!
|
||||
//! You'll normally need to sign an extrinsic to prove that it originated from an account that you
|
||||
//! control. To do this, you will typically first create a [`crate::tx::Signer`] instance, which tells
|
||||
//! Subxt who the extrinsic is from, and takes care of signing the relevant details to prove this.
|
||||
//!
|
||||
//! There are two main ways to create a compatible signer instance:
|
||||
//! 1. The `pezkuwi_subxt_signer` crate provides a WASM compatible implementation of [`crate::tx::Signer`]
|
||||
//! for chains which require sr25519 or ecdsa signatures (requires the `subxt` feature to be enabled).
|
||||
//! 2. Alternately, implement your own [`crate::tx::Signer`] instance by wrapping it in a new type pattern.
|
||||
//!
|
||||
//! Going for 1 leads to fewer dependencies being imported and WASM compatibility out of the box via
|
||||
//! the `web` feature flag. Going for 2 is useful if you're already using the Substrate dependencies or
|
||||
//! need additional signing algorithms that `pezkuwi_subxt_signer` doesn't support, and don't care about WASM
|
||||
//! compatibility.
|
||||
//!
|
||||
//! Because 2 is more complex and require more code, we'll focus on 1 here.
|
||||
//! For 2, see the example in `subxt/examples/substrate_compat_signer.rs` how
|
||||
//! you can integrate things like sp_core's signer in subxt.
|
||||
//!
|
||||
//! Let's go through how to create a signer using the `pezkuwi_subxt_signer` crate:
|
||||
//!
|
||||
//! ```rust,standalone_crate
|
||||
//! use subxt::config::PolkadotConfig;
|
||||
//! use std::str::FromStr;
|
||||
//!
|
||||
//! use pezkuwi_subxt_signer::{SecretUri, sr25519};
|
||||
//!
|
||||
//! // Get hold of a `Signer` for a test account:
|
||||
//! let alice = sr25519::dev::alice();
|
||||
//!
|
||||
//! // Or generate a keypair, here from an SURI:
|
||||
//! let uri = SecretUri::from_str("vessel ladder alter error federal sibling chat ability sun glass valve picture/0/1///Password")
|
||||
//! .expect("valid URI");
|
||||
//! let keypair = sr25519::Keypair::from_uri(&uri)
|
||||
//! .expect("valid keypair");
|
||||
//!```
|
||||
//!
|
||||
//! After initializing the signer, let's also go through how to create a transaction and sign it:
|
||||
//!
|
||||
//! ```rust,no_run,standalone_crate
|
||||
//! # #[tokio::main]
|
||||
//! # async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
//! use subxt::client::OnlineClient;
|
||||
//! use subxt::config::PolkadotConfig;
|
||||
//! use subxt::dynamic::Value;
|
||||
//!
|
||||
//! // Create client:
|
||||
//! let client = OnlineClient::<PolkadotConfig>::new().await?;
|
||||
//!
|
||||
//! // Create a dummy tx payload to sign:
|
||||
//! let payload = subxt::dynamic::tx("System", "remark", vec![
|
||||
//! Value::from_bytes("Hello there")
|
||||
//! ]);
|
||||
//!
|
||||
//! // Construct the tx but don't sign it. The account nonce here defaults to 0.
|
||||
//! // You can use `create_partial` to fetch the correct nonce.
|
||||
//! let mut partial_tx = client.tx().create_partial_offline(
|
||||
//! &payload,
|
||||
//! Default::default()
|
||||
//! )?;
|
||||
//!
|
||||
//! // Fetch the payload that needs to be signed:
|
||||
//! let signer_payload = partial_tx.signer_payload();
|
||||
//!
|
||||
//! // ... At this point, we can hand off the `signer_payload` to be signed externally.
|
||||
//! // Ultimately we need to be given back a `signature` (or really, anything
|
||||
//! // that can be SCALE encoded) and an `address`:
|
||||
//! let signature;
|
||||
//! let account_id;
|
||||
//! # use subxt::tx::Signer;
|
||||
//! # let signer = pezkuwi_subxt_signer::sr25519::dev::alice();
|
||||
//! # signature = signer.sign(&signer_payload).into();
|
||||
//! # account_id = signer.public_key().to_account_id();
|
||||
//!
|
||||
//! // Now we can build an tx, which one can call `submit` or `submit_and_watch`
|
||||
//! // on to submit to a node and optionally watch the status.
|
||||
//! let tx = partial_tx.sign_with_account_and_signature(
|
||||
//! &account_id,
|
||||
//! &signature
|
||||
//! );
|
||||
//! # Ok(())
|
||||
//! # }
|
||||
//! ```
|
||||
//!
|
||||
//! ## Submitting it
|
||||
//!
|
||||
//! Once we have signed the transaction, we need to submit it.
|
||||
//!
|
||||
//! ### The high level API
|
||||
//!
|
||||
//! The highest level approach to doing this is to call
|
||||
//! [`crate::tx::TxClient::sign_and_submit_then_watch_default`]. This hands back a
|
||||
//! [`crate::tx::TxProgress`] struct which will monitor the transaction status. We can then call
|
||||
//! [`crate::tx::TxProgress::wait_for_finalized_success()`] to wait for this transaction to make it
|
||||
//! into a finalized block, check for an `ExtrinsicSuccess` event, and then hand back the events for
|
||||
//! inspection. This looks like:
|
||||
//!
|
||||
//! ```rust,ignore
|
||||
#![doc = include_str!("../../../examples/tx_basic.rs")]
|
||||
//! ```
|
||||
//!
|
||||
//! ### Providing transaction parameters
|
||||
//!
|
||||
//! If you'd like to provide parameters (such as mortality) to the transaction, you can use
|
||||
//! [`crate::tx::TxClient::sign_and_submit_then_watch`] instead:
|
||||
//!
|
||||
//! ```rust,ignore
|
||||
#![doc = include_str!("../../../examples/tx_with_params.rs")]
|
||||
//! ```
|
||||
//!
|
||||
//! This example doesn't wait for the transaction to be included in a block; it just submits it and
|
||||
//! hopes for the best!
|
||||
//!
|
||||
//! ### Boxing transaction payloads
|
||||
//!
|
||||
//! Transaction payloads can be boxed so that they all share a common type and can be stored together.
|
||||
//!
|
||||
//! ```rust,ignore
|
||||
#![doc = include_str!("../../../examples/tx_boxed.rs")]
|
||||
//! ```
|
||||
//!
|
||||
//! ### Custom handling of transaction status updates
|
||||
//!
|
||||
//! If you'd like more control or visibility over exactly which status updates are being emitted for
|
||||
//! the transaction, you can monitor them as they are emitted and react however you choose:
|
||||
//!
|
||||
//! ```rust,ignore
|
||||
#![doc = include_str!("../../../examples/tx_status_stream.rs")]
|
||||
//! ```
|
||||
//!
|
||||
//! ### Signing transactions externally
|
||||
//!
|
||||
//! Subxt also allows you to get hold of the signer payload and hand that off to something else to be
|
||||
//! signed. The signature can then be provided back to Subxt to build the final transaction to submit:
|
||||
//!
|
||||
//! ```rust,ignore
|
||||
#![doc = include_str!("../../../examples/tx_partial.rs")]
|
||||
//! ```
|
||||
//!
|
||||
//! Take a look at the API docs for [`crate::tx::TxProgress`], [`crate::tx::TxStatus`] and
|
||||
//! [`crate::tx::TxInBlock`] for more options.
|
||||
//!
|
||||
Reference in New Issue
Block a user