mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-12 20:31:13 +00:00
Add subxt documentation (#546)
* Documentation for cli crate Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * codegen: Add documentation and simplify calls generation Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * codegen: Add documentation and simplify events generation Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * codegen: Add documentation and simplify constants generation Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * codegen: Add documentation and simplify storage generation Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * codegen: Add lib documentation Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * macro: Remove `-f bytes` as this is the default Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * subxt/client: Add examples Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * lib_doc: Add documentation to dedicated file Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * Link documentation from file Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * subxt: Add more documentation Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * subxt: Add Storage example Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * Add rpc documentation Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * metadata: Add documentation for errors Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * Add documentation for the `extrinsic` module Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * Add documentation for `events` module Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * subxt: Add `Static Metadata Validation` section Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * subxt: Add `Runtime Updates` section Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * Fix link to documentation Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * readme: Remove hardcoded versions Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * Move documentation to dedicated folder Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * Spaces between examples Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * More details for `types_mod_ident` Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * Add note for RuntimeGenerator Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * Address feedback Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * Update codegen/src/api/constants.rs Co-authored-by: James Wilson <james@jsdw.me> * Update subxt/src/lib.rs Co-authored-by: James Wilson <james@jsdw.me> * Update subxt/src/metadata/metadata_type.rs Co-authored-by: James Wilson <james@jsdw.me> * Update subxt/src/storage.rs Co-authored-by: James Wilson <james@jsdw.me> * Address feedback Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * Fix cargo clippy Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * Update call example Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * Add example for fetching constants Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * Link to examples in subxt.md Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * Update codegen/src/api/calls.rs Co-authored-by: Tarik Gul <47201679+TarikGul@users.noreply.github.com> * Update codegen/src/api/calls.rs Co-authored-by: Tarik Gul <47201679+TarikGul@users.noreply.github.com> * Update codegen/src/api/calls.rs Co-authored-by: Tarik Gul <47201679+TarikGul@users.noreply.github.com> * Update codegen/src/api/constants.rs Co-authored-by: Tarik Gul <47201679+TarikGul@users.noreply.github.com> * Update codegen/src/api/constants.rs Co-authored-by: Tarik Gul <47201679+TarikGul@users.noreply.github.com> * Update codegen/src/api/storage.rs Co-authored-by: Tarik Gul <47201679+TarikGul@users.noreply.github.com> * Update codegen/src/api/storage.rs Co-authored-by: Tarik Gul <47201679+TarikGul@users.noreply.github.com> * Update codegen/src/api/storage.rs Co-authored-by: Tarik Gul <47201679+TarikGul@users.noreply.github.com> * Update docs/subxt.md Co-authored-by: Tarik Gul <47201679+TarikGul@users.noreply.github.com> * Update docs/subxt.md Co-authored-by: Tarik Gul <47201679+TarikGul@users.noreply.github.com> * Update docs/subxt.md Co-authored-by: Tarik Gul <47201679+TarikGul@users.noreply.github.com> * Update docs/subxt.md Co-authored-by: Tarik Gul <47201679+TarikGul@users.noreply.github.com> * Update docs/subxt.md Co-authored-by: Tarik Gul <47201679+TarikGul@users.noreply.github.com> * Update subxt/src/extrinsic/mod.rs Co-authored-by: Tarik Gul <47201679+TarikGul@users.noreply.github.com> * Update subxt/src/storage.rs Co-authored-by: Tarik Gul <47201679+TarikGul@users.noreply.github.com> * Update documentation Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * Update examples/examples/balance_transfer.rs Co-authored-by: James Wilson <james@jsdw.me> * Update subxt/src/extrinsic/mod.rs Co-authored-by: James Wilson <james@jsdw.me> * Update subxt/src/rpc.rs Co-authored-by: James Wilson <james@jsdw.me> * Update subxt/src/updates.rs Co-authored-by: James Wilson <james@jsdw.me> * Update docs example with `PolkadotExtrinsicParams` Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * subxt: Remove extrinsic extra documentation Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * examples: Remove similar transfer example Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * Apply cargo fmt Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> Co-authored-by: James Wilson <james@jsdw.me> Co-authored-by: Tarik Gul <47201679+TarikGul@users.noreply.github.com>
This commit is contained in:
@@ -22,81 +22,19 @@ subxt metadata -f bytes > metadata.scale
|
||||
This defaults to querying the metadata of a locally running node on the default `http://localhost:9933/`. If querying
|
||||
a different node then the `metadata` command accepts a `--url` argument.
|
||||
|
||||
### Generating the runtime API from the downloaded metadata
|
||||
## Subxt Documentation
|
||||
|
||||
Declare a module and decorate it with the `subxt` attribute which points at the downloaded metadata for the
|
||||
target runtime:
|
||||
|
||||
```rust
|
||||
#[subxt::subxt(runtime_metadata_path = "metadata.scale")]
|
||||
pub mod node_runtime { }
|
||||
```
|
||||
|
||||
**Important:** `runtime_metadata_path` resolves to a path relative to the directory where your crate's `Cargo.toml`
|
||||
resides ([`CARGO_MANIFEST_DIR`](https://doc.rust-lang.org/cargo/reference/environment-variables.html)), *not* relative to the source file.
|
||||
|
||||
### Initializing the API client
|
||||
|
||||
```rust
|
||||
use subxt::{ClientBuilder, DefaultConfig, SubstrateExtrinsicParams};
|
||||
|
||||
let api = ClientBuilder::new()
|
||||
.set_url("wss://rpc.polkadot.io:443")
|
||||
.build()
|
||||
.await?
|
||||
.to_runtime_api::<node_runtime::RuntimeApi<DefaultConfig, SubstrateExtrinsicParams<DefaultConfig>>>();
|
||||
```
|
||||
|
||||
The `RuntimeApi` type is generated by the `subxt` macro from the supplied metadata. This can be parameterized with user
|
||||
supplied implementations for the `Config` and `Extra` types, if the default implementations differ from the target
|
||||
chain.
|
||||
|
||||
### Querying Storage
|
||||
|
||||
Call the generated `RuntimeApi::storage()` method, followed by the `pallet_name()` and then the `storage_item_name()`.
|
||||
|
||||
So in order to query `Balances::TotalIssuance`:
|
||||
|
||||
```rust
|
||||
let total_issuance = api
|
||||
.storage()
|
||||
.balances()
|
||||
.total_issuance(None)
|
||||
.await
|
||||
.unwrap()
|
||||
```
|
||||
|
||||
### Submitting Extrinsics
|
||||
|
||||
Submit an extrinsic, returning success once the transaction is validated and accepted into the pool:
|
||||
|
||||
```rust
|
||||
use sp_keyring::AccountKeyring;
|
||||
use subxt::PairSigner;
|
||||
|
||||
let signer = PairSigner::new(AccountKeyring::Alice.pair());
|
||||
let dest = AccountKeyring::Bob.to_account_id().into();
|
||||
|
||||
let tx_hash = api
|
||||
.tx()
|
||||
.balances()
|
||||
.transfer(dest, 10_000)
|
||||
.sign_and_submit(&signer)
|
||||
.await?;
|
||||
```
|
||||
|
||||
For more advanced usage, which can wait for block inclusion and return any events triggered by the extrinsic, see the
|
||||
[balance transfer example](./examples/examples/balance_transfer.rs).
|
||||
For more details regarding utilizing subxt, please visit the [documentation](docs/subxt.md).
|
||||
|
||||
## Integration Testing
|
||||
|
||||
Most tests require a running substrate node to communicate with. This is done by spawning an instance of the
|
||||
substrate node per test. It requires an executable binary `substrate` at [`polkadot-v0.9.10`](https://github.com/paritytech/substrate/releases/tag/polkadot-v0.9.10) on your path.
|
||||
substrate node per test. It requires an up-to-date `substrate` executable on your path.
|
||||
|
||||
This can be installed from source via cargo:
|
||||
|
||||
```bash
|
||||
cargo install --git https://github.com/paritytech/substrate node-cli --tag=polkadot-v0.9.10 --force
|
||||
cargo install --git https://github.com/paritytech/substrate node-cli --force
|
||||
```
|
||||
|
||||
## Real world usage
|
||||
|
||||
+4
-4
@@ -63,7 +63,7 @@ enum Command {
|
||||
/// Download metadata from a substrate node, for use with `subxt` codegen.
|
||||
#[structopt(name = "metadata")]
|
||||
Metadata {
|
||||
/// the url of the substrate node to query for metadata
|
||||
/// The url of the substrate node to query for metadata.
|
||||
#[structopt(
|
||||
name = "url",
|
||||
long,
|
||||
@@ -71,7 +71,7 @@ enum Command {
|
||||
default_value = "http://localhost:9933"
|
||||
)]
|
||||
url: url::Url,
|
||||
/// the format of the metadata to display: `json`, `hex` or `bytes`
|
||||
/// The format of the metadata to display: `json`, `hex` or `bytes`.
|
||||
#[structopt(long, short, default_value = "bytes")]
|
||||
format: String,
|
||||
},
|
||||
@@ -81,10 +81,10 @@ enum Command {
|
||||
///
|
||||
/// `subxt codegen | rustfmt --edition=2018 --emit=stdout`
|
||||
Codegen {
|
||||
/// the url of the substrate node to query for metadata for codegen.
|
||||
/// The url of the substrate node to query for metadata for codegen.
|
||||
#[structopt(name = "url", long, parse(try_from_str))]
|
||||
url: Option<url::Url>,
|
||||
/// the path to the encoded metadata file.
|
||||
/// The path to the encoded metadata file.
|
||||
#[structopt(short, long, parse(from_os_str))]
|
||||
file: Option<PathBuf>,
|
||||
/// Additional derives
|
||||
|
||||
@@ -20,7 +20,6 @@ use crate::types::{
|
||||
};
|
||||
use frame_metadata::{
|
||||
v14::RuntimeMetadataV14,
|
||||
PalletCallMetadata,
|
||||
PalletMetadata,
|
||||
};
|
||||
use heck::{
|
||||
@@ -35,13 +34,51 @@ use quote::{
|
||||
};
|
||||
use scale_info::form::PortableForm;
|
||||
|
||||
/// Generate calls from the provided pallet's metadata.
|
||||
///
|
||||
/// The function creates a new module named `calls` under the pallet's module.
|
||||
/// ```ignore
|
||||
/// pub mod PalletName {
|
||||
/// pub mod calls {
|
||||
/// ...
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// The function generates the calls as rust structs that implement the `subxt::Call` trait
|
||||
/// to uniquely identify the call's identity when creating the extrinsic.
|
||||
///
|
||||
/// ```ignore
|
||||
/// pub struct CallName {
|
||||
/// pub call_param: type,
|
||||
/// }
|
||||
/// impl ::subxt::Call for CallName {
|
||||
/// ...
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// Calls are extracted from the API and wrapped into the generated `TransactionApi` of
|
||||
/// each module.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// - `metadata` - Runtime metadata from which the calls are generated.
|
||||
/// - `type_gen` - The type generator containing all types defined by metadata.
|
||||
/// - `pallet` - Pallet metadata from which the calls are generated.
|
||||
/// - `types_mod_ident` - The ident of the base module that we can use to access the generated types from.
|
||||
pub fn generate_calls(
|
||||
metadata: &RuntimeMetadataV14,
|
||||
type_gen: &TypeGenerator,
|
||||
pallet: &PalletMetadata<PortableForm>,
|
||||
call: &PalletCallMetadata<PortableForm>,
|
||||
types_mod_ident: &syn::Ident,
|
||||
) -> TokenStream2 {
|
||||
// Early return if the pallet has no calls.
|
||||
let call = if let Some(ref calls) = pallet.calls {
|
||||
calls
|
||||
} else {
|
||||
return quote!()
|
||||
};
|
||||
|
||||
let mut struct_defs = super::generate_structs_from_variants(
|
||||
type_gen,
|
||||
call.ty.id(),
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
use crate::types::TypeGenerator;
|
||||
use frame_metadata::{
|
||||
v14::RuntimeMetadataV14,
|
||||
PalletConstantMetadata,
|
||||
PalletMetadata,
|
||||
};
|
||||
use heck::ToSnakeCase as _;
|
||||
@@ -29,13 +28,41 @@ use quote::{
|
||||
};
|
||||
use scale_info::form::PortableForm;
|
||||
|
||||
/// Generate constants from the provided pallet's metadata.
|
||||
///
|
||||
/// The function creates a new module named `constants` under the pallet's module.
|
||||
/// ```ignore
|
||||
/// pub mod PalletName {
|
||||
/// pub mod constants {
|
||||
/// ...
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// The constants are exposed via the `ConstantsApi` wrapper.
|
||||
///
|
||||
/// Although the constants are defined in the provided static metadata, the API
|
||||
/// ensures that the constants are returned from the runtime metadata of the node.
|
||||
/// This ensures that if the node's constants change value, we'll always see the latest values.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// - `metadata` - Runtime metadata from which the calls are generated.
|
||||
/// - `type_gen` - The type generator containing all types defined by metadata
|
||||
/// - `pallet` - Pallet metadata from which the calls are generated.
|
||||
/// - `types_mod_ident` - The ident of the base module that we can use to access the generated types from.
|
||||
pub fn generate_constants(
|
||||
metadata: &RuntimeMetadataV14,
|
||||
type_gen: &TypeGenerator,
|
||||
pallet: &PalletMetadata<PortableForm>,
|
||||
constants: &[PalletConstantMetadata<PortableForm>],
|
||||
types_mod_ident: &syn::Ident,
|
||||
) -> TokenStream2 {
|
||||
// Early return if the pallet has no constants.
|
||||
if pallet.constants.is_empty() {
|
||||
return quote!()
|
||||
}
|
||||
let constants = &pallet.constants;
|
||||
|
||||
let constant_fns = constants.iter().map(|constant| {
|
||||
let fn_name = format_ident!("{}", constant.name.to_snake_case());
|
||||
let pallet_name = &pallet.name;
|
||||
|
||||
@@ -15,20 +15,51 @@
|
||||
// along with subxt. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use crate::types::TypeGenerator;
|
||||
use frame_metadata::{
|
||||
PalletEventMetadata,
|
||||
PalletMetadata,
|
||||
};
|
||||
use frame_metadata::PalletMetadata;
|
||||
use proc_macro2::TokenStream as TokenStream2;
|
||||
use quote::quote;
|
||||
use scale_info::form::PortableForm;
|
||||
|
||||
/// Generate events from the provided pallet metadata.
|
||||
///
|
||||
/// The function creates a new module named `events` under the pallet's module.
|
||||
/// ```ignore
|
||||
/// pub mod PalletName {
|
||||
/// pub mod events {
|
||||
/// ...
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// The function generates the events as rust structs that implement the `subxt::Event` trait
|
||||
/// to uniquely identify the event's identity when creating the extrinsic.
|
||||
///
|
||||
/// ```ignore
|
||||
/// pub struct EventName {
|
||||
/// pub event_param: type,
|
||||
/// }
|
||||
/// impl ::subxt::Event for EventName {
|
||||
/// ...
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// - `type_gen` - The type generator containing all types defined by metadata.
|
||||
/// - `pallet` - Pallet metadata from which the events are generated.
|
||||
/// - `types_mod_ident` - The ident of the base module that we can use to access the generated types from.
|
||||
pub fn generate_events(
|
||||
type_gen: &TypeGenerator,
|
||||
pallet: &PalletMetadata<PortableForm>,
|
||||
event: &PalletEventMetadata<PortableForm>,
|
||||
types_mod_ident: &syn::Ident,
|
||||
) -> TokenStream2 {
|
||||
// Early return if the pallet has no events.
|
||||
let event = if let Some(ref event) = pallet.event {
|
||||
event
|
||||
} else {
|
||||
return quote!()
|
||||
};
|
||||
|
||||
let struct_defs = super::generate_structs_from_variants(
|
||||
type_gen,
|
||||
event.ty.id(),
|
||||
|
||||
+36
-39
@@ -55,6 +55,15 @@ use std::{
|
||||
};
|
||||
use syn::parse_quote;
|
||||
|
||||
/// Generates the API for interacting with a Substrate runtime.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `item_mod` - The module declaration for which the API is implemented.
|
||||
/// * `path` - The path to the scale encoded metadata of the runtime node.
|
||||
/// * `derives` - Provide custom derives for the generated types.
|
||||
///
|
||||
/// **Note:** This is a wrapper over [RuntimeGenerator] for static metadata use-cases.
|
||||
pub fn generate_runtime_api<P>(
|
||||
item_mod: syn::ItemMod,
|
||||
path: P,
|
||||
@@ -78,11 +87,16 @@ where
|
||||
generator.generate_runtime(item_mod, derives)
|
||||
}
|
||||
|
||||
/// Create the API for interacting with a Substrate runtime.
|
||||
pub struct RuntimeGenerator {
|
||||
metadata: RuntimeMetadataV14,
|
||||
}
|
||||
|
||||
impl RuntimeGenerator {
|
||||
/// Create a new runtime generator from the provided metadata.
|
||||
///
|
||||
/// **Note:** If you have a path to the metadata, prefer to use [generate_runtime_api]
|
||||
/// for generating the runtime API.
|
||||
pub fn new(metadata: RuntimeMetadataPrefixed) -> Self {
|
||||
match metadata.1 {
|
||||
RuntimeMetadata::V14(v14) => Self { metadata: v14 },
|
||||
@@ -90,6 +104,12 @@ impl RuntimeGenerator {
|
||||
}
|
||||
}
|
||||
|
||||
/// Generate the API for interacting with a Substrate runtime.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `item_mod` - The module declaration for which the API is implemented.
|
||||
/// * `derives` - Provide custom derives for the generated types.
|
||||
pub fn generate_runtime(
|
||||
&self,
|
||||
item_mod: syn::ItemMod,
|
||||
@@ -98,7 +118,7 @@ impl RuntimeGenerator {
|
||||
let item_mod_ir = ir::ItemMod::from(item_mod);
|
||||
let default_derives = derives.default_derives();
|
||||
|
||||
// some hardcoded default type substitutes, can be overridden by user
|
||||
// Some hardcoded default type substitutes, can be overridden by user
|
||||
let mut type_substitutes = [
|
||||
(
|
||||
"bitvec::order::Lsb0",
|
||||
@@ -175,47 +195,24 @@ impl RuntimeGenerator {
|
||||
let metadata_hash = get_metadata_per_pallet_hash(&self.metadata, &pallet_names);
|
||||
|
||||
let modules = pallets_with_mod_names.iter().map(|(pallet, mod_name)| {
|
||||
let calls = if let Some(ref calls) = pallet.calls {
|
||||
calls::generate_calls(
|
||||
&self.metadata,
|
||||
&type_gen,
|
||||
pallet,
|
||||
calls,
|
||||
types_mod_ident,
|
||||
)
|
||||
} else {
|
||||
quote!()
|
||||
};
|
||||
let calls =
|
||||
calls::generate_calls(&self.metadata, &type_gen, pallet, types_mod_ident);
|
||||
|
||||
let event = if let Some(ref event) = pallet.event {
|
||||
events::generate_events(&type_gen, pallet, event, types_mod_ident)
|
||||
} else {
|
||||
quote!()
|
||||
};
|
||||
let event = events::generate_events(&type_gen, pallet, types_mod_ident);
|
||||
|
||||
let storage_mod = if let Some(ref storage) = pallet.storage {
|
||||
storage::generate_storage(
|
||||
&self.metadata,
|
||||
&type_gen,
|
||||
pallet,
|
||||
storage,
|
||||
types_mod_ident,
|
||||
)
|
||||
} else {
|
||||
quote!()
|
||||
};
|
||||
let storage_mod = storage::generate_storage(
|
||||
&self.metadata,
|
||||
&type_gen,
|
||||
pallet,
|
||||
types_mod_ident,
|
||||
);
|
||||
|
||||
let constants_mod = if !pallet.constants.is_empty() {
|
||||
constants::generate_constants(
|
||||
&self.metadata,
|
||||
&type_gen,
|
||||
pallet,
|
||||
&pallet.constants,
|
||||
types_mod_ident,
|
||||
)
|
||||
} else {
|
||||
quote!()
|
||||
};
|
||||
let constants_mod = constants::generate_constants(
|
||||
&self.metadata,
|
||||
&type_gen,
|
||||
pallet,
|
||||
types_mod_ident,
|
||||
);
|
||||
|
||||
quote! {
|
||||
pub mod #mod_name {
|
||||
|
||||
@@ -18,7 +18,6 @@ use crate::types::TypeGenerator;
|
||||
use frame_metadata::{
|
||||
v14::RuntimeMetadataV14,
|
||||
PalletMetadata,
|
||||
PalletStorageMetadata,
|
||||
StorageEntryMetadata,
|
||||
StorageEntryModifier,
|
||||
StorageEntryType,
|
||||
@@ -36,13 +35,51 @@ use scale_info::{
|
||||
TypeDef,
|
||||
};
|
||||
|
||||
/// Generate storage from the provided pallet's metadata.
|
||||
///
|
||||
/// The function creates a new module named `storage` under the pallet's module.
|
||||
///
|
||||
/// ```ignore
|
||||
/// pub mod PalletName {
|
||||
/// pub mod storage {
|
||||
/// ...
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// The function generates the storage as rust structs that implement the `subxt::StorageEntry`
|
||||
/// trait to uniquely identify the storage's identity when creating the extrinsic.
|
||||
///
|
||||
/// ```ignore
|
||||
/// pub struct StorageName {
|
||||
/// pub storage_param: type,
|
||||
/// }
|
||||
/// impl ::subxt::StorageEntry for StorageName {
|
||||
/// ...
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// Storages are extracted from the API and wrapped into the generated `StorageApi` of
|
||||
/// each module.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// - `metadata` - Runtime metadata from which the storages are generated.
|
||||
/// - `type_gen` - The type generator containing all types defined by metadata.
|
||||
/// - `pallet` - Pallet metadata from which the storages are generated.
|
||||
/// - `types_mod_ident` - The ident of the base module that we can use to access the generated types from.
|
||||
pub fn generate_storage(
|
||||
metadata: &RuntimeMetadataV14,
|
||||
type_gen: &TypeGenerator,
|
||||
pallet: &PalletMetadata<PortableForm>,
|
||||
storage: &PalletStorageMetadata<PortableForm>,
|
||||
types_mod_ident: &syn::Ident,
|
||||
) -> TokenStream2 {
|
||||
let storage = if let Some(ref storage) = pallet.storage {
|
||||
storage
|
||||
} else {
|
||||
return quote!()
|
||||
};
|
||||
|
||||
let (storage_structs, storage_fns): (Vec<_>, Vec<_>) = storage
|
||||
.entries
|
||||
.iter()
|
||||
|
||||
@@ -15,6 +15,38 @@
|
||||
// along with subxt. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Library to generate an API for a Substrate runtime from its metadata.
|
||||
//!
|
||||
//! ## Generated Structure
|
||||
//!
|
||||
//! The API generator logic:
|
||||
//! - At the root there is the `item_mod` provided (ie `pub mod api {}`)
|
||||
//! - Pallets are represented by a child module (ie `pub mod PalletName {}`) of the root
|
||||
//! - Each pallet exposes as child modules (if applicable):
|
||||
//! - Calls (`pub mod calls {}`)
|
||||
//! - Events (`pub mod events {}`)
|
||||
//! - Storage (`pub mod storage {}`)
|
||||
//! - Constants (`pub mod constants {}`)
|
||||
//!
|
||||
//! ## Example
|
||||
//!
|
||||
//! ```rust
|
||||
//! use codec::Decode;
|
||||
//! use frame_metadata::RuntimeMetadataPrefixed;
|
||||
//! use subxt_codegen::DerivesRegistry;
|
||||
//!
|
||||
//! // Runtime metadata obtained from a node.
|
||||
//! let metadata = <RuntimeMetadataPrefixed as Decode>::decode(encoded)?;
|
||||
//! // Module under which the API is generated.
|
||||
//! let item_mod = syn::parse_quote!(
|
||||
//! pub mod api {}
|
||||
//! );
|
||||
//! // Default module derivatives.
|
||||
//! let mut derives = DerivesRegistry::default();
|
||||
//! // Generate the Runtime API.
|
||||
//! let generator = subxt_codegen::RuntimeGenerator::new(metadata);
|
||||
//! let runtime_api = generator.generate_runtime(item_mod, derives);
|
||||
//! println!("{}", runtime_api);
|
||||
//! ```
|
||||
|
||||
#![deny(unused_crate_dependencies)]
|
||||
|
||||
|
||||
+144
@@ -0,0 +1,144 @@
|
||||
Subxt is a library to **sub**mit e**xt**rinsics to a [substrate](https://github.com/paritytech/substrate) node via RPC.
|
||||
|
||||
The generated Subxt API exposes the ability to:
|
||||
- [Submit extrinsics](https://docs.substrate.io/v3/concepts/extrinsics/) (Calls)
|
||||
- [Query storage](https://docs.substrate.io/v3/runtime/storage/) (Storage)
|
||||
- [Query constants](https://docs.substrate.io/how-to-guides/v3/basics/configurable-constants/) (Constants)
|
||||
- [Subscribe to events](https://docs.substrate.io/v3/runtime/events-and-errors/) (Events)
|
||||
|
||||
|
||||
### Generate the runtime API
|
||||
|
||||
Subxt generates a runtime API from downloaded static metadata. The metadata can be downloaded using the
|
||||
[subxt-cli](https://crates.io/crates/subxt-cli) tool.
|
||||
|
||||
To generate the runtime API, use the `subxt` attribute which points at downloaded static metadata.
|
||||
|
||||
```rust
|
||||
#[subxt::subxt(runtime_metadata_path = "metadata.scale")]
|
||||
pub mod node_runtime { }
|
||||
```
|
||||
|
||||
The `node_runtime` has the following hierarchy:
|
||||
|
||||
```rust
|
||||
pub mod node_runtime {
|
||||
pub mod PalletName {
|
||||
pub mod calls { }
|
||||
pub mod storage { }
|
||||
pub mod constants { }
|
||||
pub mod events { }
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
For more information regarding the `node_runtime` hierarchy, please visit the
|
||||
[subxt-codegen](https://docs.rs/subxt-codegen/latest/subxt_codegen/) documentation.
|
||||
|
||||
|
||||
### Initializing the API client
|
||||
|
||||
```rust
|
||||
use subxt::{ClientBuilder, DefaultConfig, PolkadotExtrinsicParams};
|
||||
|
||||
let api = ClientBuilder::new()
|
||||
.set_url("wss://rpc.polkadot.io:443")
|
||||
.build()
|
||||
.await?
|
||||
.to_runtime_api::<node_runtime::RuntimeApi<DefaultConfig, PolkadotExtrinsicParams<DefaultConfig>>>();
|
||||
```
|
||||
|
||||
The `RuntimeApi` type is generated by the `subxt` macro from the supplied metadata. This can be parameterized with user
|
||||
supplied implementations for the `Config` and `Extra` types, if the default implementation differs from the target
|
||||
chain.
|
||||
|
||||
To ensure that extrinsics are properly submitted, during the build phase of the Client the
|
||||
runtime metadata of the node is downloaded. If the URL is not specified (`set_url`), the local host is used instead.
|
||||
|
||||
|
||||
### Submit Extrinsics
|
||||
|
||||
Extrinsics are obtained using the API's `RuntimeApi::tx()` method, followed by `pallet_name()` and then the
|
||||
`call_item_name()`.
|
||||
|
||||
Submit an extrinsic, returning success once the transaction is validated and accepted into the pool:
|
||||
|
||||
Please visit the [balance_transfer](../examples/examples/balance_transfer.rs) example for more details.
|
||||
|
||||
|
||||
### Querying Storage
|
||||
|
||||
The runtime storage is queried via the generated `RuntimeApi::storage()` method, followed by the `pallet_name()` and
|
||||
then the `storage_item_name()`.
|
||||
|
||||
Please visit the [fetch_staking_details](../examples/examples/fetch_staking_details.rs) example for more details.
|
||||
|
||||
### Query Constants
|
||||
|
||||
Constants are embedded into the node's metadata.
|
||||
|
||||
The subxt offers the ability to query constants from the runtime metadata (metadata downloaded when constructing
|
||||
the client, *not* the one provided for API generation).
|
||||
|
||||
To query constants use the generated `RuntimeApi::constants()` method, followed by the `pallet_name()` and then the
|
||||
`constant_item_name()`.
|
||||
|
||||
Please visit the [fetch_constants](../examples/examples/fetch_constants.rs) example for more details.
|
||||
|
||||
### Subscribe to Events
|
||||
|
||||
To subscribe to events, use the generated `RuntimeApi::events()` method which exposes:
|
||||
- `subscribe()` - Subscribe to events emitted from blocks. These blocks haven't necessarily been finalised.
|
||||
- `subscribe_finalized()` - Subscribe to events from finalized blocks.
|
||||
- `at()` - Obtain events at a given block hash.
|
||||
|
||||
|
||||
*Examples*
|
||||
- [subscribe_all_events](../examples/examples/subscribe_all_events.rs): Subscribe to events emitted from blocks.
|
||||
- [subscribe_one_event](../examples/examples/subscribe_one_event.rs): Subscribe and filter by one event.
|
||||
- [subscribe_some_events](../examples/examples/subscribe_some_events.rs): Subscribe and filter event.
|
||||
|
||||
### Static Metadata Validation
|
||||
|
||||
There are two types of metadata that the subxt is aware of:
|
||||
- static metadata: Metadata used for generating the API.
|
||||
- runtime metadata: Metadata downloaded from the target node when a subxt client is created.
|
||||
|
||||
There are cases when the static metadata is different from the runtime metadata of a node.
|
||||
Such is the case when the node performs a runtime update.
|
||||
|
||||
To ensure that subxt can properly communicate with the target node the static metadata is validated
|
||||
against the runtime metadata of the node.
|
||||
|
||||
This validation is performed at the Call, Constant, and Storage levels, as well for the entire metadata.
|
||||
The level of granularity ensures that the users can still submit a given call, even if another
|
||||
call suffered changes.
|
||||
|
||||
Full metadata validation:
|
||||
|
||||
```rust
|
||||
// To make sure that all of our statically generated pallets are compatible with the
|
||||
// runtime node, we can run this check:
|
||||
api.validate_metadata()?;
|
||||
```
|
||||
|
||||
Call level validation:
|
||||
|
||||
```rust
|
||||
let extrinsic = api
|
||||
.tx()
|
||||
.balances()
|
||||
// Constructing an extrinsic will fail if the metadata
|
||||
// is not in sync with the generated API.
|
||||
.transfer(dest, 123_456_789_012_345)?;
|
||||
```
|
||||
|
||||
### 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 `UpdateClient` API keeps 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.
|
||||
@@ -38,20 +38,23 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
tracing_subscriber::fmt::init();
|
||||
|
||||
let signer = PairSigner::new(AccountKeyring::Alice.pair());
|
||||
let dest = AccountKeyring::Bob.to_account_id().into();
|
||||
|
||||
let api = ClientBuilder::new()
|
||||
.build()
|
||||
.await?
|
||||
.to_runtime_api::<polkadot::RuntimeApi<DefaultConfig, PolkadotExtrinsicParams<DefaultConfig>>>();
|
||||
let hash = api
|
||||
.tx()
|
||||
.balances()
|
||||
.transfer(dest, 123_456_789_012_345)?
|
||||
.sign_and_submit_default(&signer)
|
||||
.await?;
|
||||
|
||||
println!("Balance transfer extrinsic submitted: {}", hash);
|
||||
// Submit the `transfer` extrinsic from Alice's account to Bob's.
|
||||
let dest = AccountKeyring::Bob.to_account_id().into();
|
||||
|
||||
// Obtain an extrinsic, calling the "transfer" function in
|
||||
// the "balances" pallet.
|
||||
let extrinsic = api.tx().balances().transfer(dest, 123_456_789_012_345)?;
|
||||
|
||||
// Sign and submit the extrinsic, returning its hash.
|
||||
let tx_hash = extrinsic.sign_and_submit_default(&signer).await?;
|
||||
|
||||
println!("Balance transfer extrinsic submitted: {}", tx_hash);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
// Copyright 2019-2022 Parity Technologies (UK) Ltd.
|
||||
// This file is part of subxt.
|
||||
//
|
||||
// subxt is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// subxt is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with subxt. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! To run this example, a local polkadot node should be running. Example verified against polkadot 0.9.18-4542a603cc-aarch64-macos.
|
||||
//!
|
||||
//! E.g.
|
||||
//! ```bash
|
||||
//! curl "https://github.com/paritytech/polkadot/releases/download/v0.9.18/polkadot" --output /usr/local/bin/polkadot --location
|
||||
//! polkadot --dev --tmp
|
||||
//! ```
|
||||
|
||||
use subxt::{
|
||||
ClientBuilder,
|
||||
DefaultConfig,
|
||||
PolkadotExtrinsicParams,
|
||||
};
|
||||
|
||||
// Generate the API from a static metadata path.
|
||||
#[subxt::subxt(runtime_metadata_path = "../artifacts/polkadot_metadata.scale")]
|
||||
pub mod polkadot {}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
tracing_subscriber::fmt::init();
|
||||
|
||||
// Upon connecting to the target polkadot node, the node's metadata is downloaded (referred to
|
||||
// as the runtime metadata).
|
||||
let api = ClientBuilder::new()
|
||||
.build()
|
||||
.await?
|
||||
.to_runtime_api::<polkadot::RuntimeApi<DefaultConfig, PolkadotExtrinsicParams<DefaultConfig>>>();
|
||||
|
||||
// Constants are queried from the node's runtime metadata.
|
||||
// Query the `ExistentialDeposit` constant from the `Balances` pallet.
|
||||
let existential_deposit = api
|
||||
// This is the constants query.
|
||||
.constants()
|
||||
// Constant from the `Balances` pallet.
|
||||
.balances()
|
||||
// Constant name.
|
||||
.existential_deposit()?;
|
||||
|
||||
println!("Existential Deposit: {}", existential_deposit);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
+1
-1
@@ -21,7 +21,7 @@
|
||||
//! Download metadata from a running Substrate node using `subxt-cli`:
|
||||
//!
|
||||
//! ```bash
|
||||
//! subxt metadata -f bytes > polkadot_metadata.scale
|
||||
//! subxt metadata > polkadot_metadata.scale
|
||||
//! ```
|
||||
//!
|
||||
//! Annotate a Rust module with the `subxt` attribute referencing the aforementioned metadata file.
|
||||
|
||||
@@ -98,6 +98,17 @@ impl ClientBuilder {
|
||||
}
|
||||
|
||||
/// Creates a new Client.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// use subxt::{ClientBuilder, DefaultConfig};
|
||||
///
|
||||
/// let client = ClientBuilder::new()
|
||||
/// .set_url("wss://rpc.polkadot.io:443")
|
||||
/// .build::<DefaultConfig>()
|
||||
/// .await?;
|
||||
/// ```
|
||||
pub async fn build<T: Config>(self) -> Result<Client<T>, BasicError> {
|
||||
let client = if let Some(client) = self.client {
|
||||
client
|
||||
@@ -190,6 +201,22 @@ impl<T: Config> Client<T> {
|
||||
}
|
||||
|
||||
/// Create a wrapper for performing runtime updates on this client.
|
||||
///
|
||||
/// # Note
|
||||
///
|
||||
/// The update client is intended to be used in the background for
|
||||
/// performing runtime updates, while the API is still in use.
|
||||
/// Without performing runtime updates the submitted extrinsics may fail.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// let update_client = client.updates();
|
||||
/// tokio::spawn(async move {
|
||||
/// let result = update_client.perform_runtime_updates().await;
|
||||
/// println!("Runtime update finished with result={:?}", result);
|
||||
/// });
|
||||
/// ```
|
||||
pub fn updates(&self) -> UpdateClient<T> {
|
||||
UpdateClient::new(
|
||||
self.rpc.clone(),
|
||||
|
||||
+52
-1
@@ -14,7 +14,58 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with subxt. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! For working with events.
|
||||
//! This module exposes the ability to work with events generated by a given block.
|
||||
//! Subxt can either attempt to statically decode events into known types, or it
|
||||
//! can hand back details of the raw event without knowing what shape its contents
|
||||
//! are (this may be useful if we don't know what exactly we're looking for).
|
||||
//!
|
||||
//! This module is wrapped by the generated API in `RuntimeAPI::EventsApi`.
|
||||
//!
|
||||
//! # Example
|
||||
//!
|
||||
//! ## Subscribe to all events
|
||||
//!
|
||||
//! Users can subscribe to all emitted events from blocks using `subscribe()`.
|
||||
//!
|
||||
//! To subscribe to all events from just the finalized blocks use `subscribe_finalized()`.
|
||||
//!
|
||||
//! To obtain the events from a given block use `at()`.
|
||||
//!
|
||||
//! ```rust
|
||||
//! let mut events = api.events().subscribe().await?;
|
||||
//!
|
||||
//! while let Some(ev) = events.next().await {
|
||||
//! // Obtain all events from this block.
|
||||
//! let ev: subxt::Events<_, _> = ev?;
|
||||
//! // Print block hash.
|
||||
//! println!("Event at block hash {:?}", ev.block_hash());
|
||||
//! // Iterate over all events.
|
||||
//! let mut iter = ev.iter();
|
||||
//! while let Some(event_details) = iter.next() {
|
||||
//! println!("Event details {:?}", event_details);
|
||||
//! }
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! ## Filter events
|
||||
//!
|
||||
//! The subxt exposes the ability to filter events via the `filter_events()` function.
|
||||
//!
|
||||
//! The function filters events from the provided tuple. If 1-tuple is provided, the events are
|
||||
//! returned directly. Otherwise, we'll be given a corresponding tuple of `Option`'s, with exactly
|
||||
//! one variant populated each time.
|
||||
//!
|
||||
//! ```rust
|
||||
//! let mut events = api
|
||||
//! .events()
|
||||
//! .subscribe()
|
||||
//! .await?
|
||||
//! .filter_events::<(polkadot::balances::events::Transfer,)>();
|
||||
//!
|
||||
//! while let Some(transfer_event) = transfer_events.next().await {
|
||||
//! println!("Balance transfer event: {transfer_event:?}");
|
||||
//! }
|
||||
//! ```
|
||||
|
||||
mod decoding;
|
||||
mod event_subscription;
|
||||
|
||||
@@ -15,6 +15,20 @@
|
||||
// along with subxt. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Create signed or unsigned extrinsics.
|
||||
//!
|
||||
//! This modules exposes the extrinsic's parameters and the ability to sign an extrinsic.
|
||||
//!
|
||||
//!
|
||||
//! An extrinsic is submitted with an "signed extra" and "additional" parameters, which can be
|
||||
//! different for each chain. The trait [ExtrinsicParams] determines exactly which
|
||||
//! additional and signed extra parameters are used when constructing an extrinsic.
|
||||
//!
|
||||
//!
|
||||
//! The structure [BaseExtrinsicParams] is a base implementation of the trait which
|
||||
//! configures most of the "signed extra" and "additional" parameters as needed for
|
||||
//! Polkadot and Substrate nodes. Only the shape of the tip payments differs, leading to
|
||||
//! [SubstrateExtrinsicParams] and [PolkadotExtrinsicParams] structs which pick an
|
||||
//! appropriate shape for Substrate/Polkadot chains respectively.
|
||||
|
||||
mod params;
|
||||
mod signer;
|
||||
|
||||
+14
-5
@@ -14,9 +14,7 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with subxt. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! A library to **sub**mit e**xt**rinsics to a
|
||||
//! [substrate](https://github.com/paritytech/substrate) node via RPC.
|
||||
|
||||
#![doc = include_str!("../../docs/subxt.md")]
|
||||
#![deny(
|
||||
bad_style,
|
||||
const_err,
|
||||
@@ -126,7 +124,13 @@ pub use crate::{
|
||||
},
|
||||
};
|
||||
|
||||
/// Call trait.
|
||||
/// Trait to uniquely identify the call (extrinsic)'s identity from the runtime metadata.
|
||||
///
|
||||
/// Generated API structures that represent each of the different possible
|
||||
/// calls to a node each implement this trait.
|
||||
///
|
||||
/// When encoding an extrinsic, we use this information to know how to map
|
||||
/// the call to the specific pallet and call index needed by a particular node.
|
||||
pub trait Call: Encode {
|
||||
/// Pallet name.
|
||||
const PALLET: &'static str;
|
||||
@@ -139,7 +143,12 @@ pub trait Call: Encode {
|
||||
}
|
||||
}
|
||||
|
||||
/// Event trait.
|
||||
/// Trait to uniquely identify the events's identity from the runtime metadata.
|
||||
///
|
||||
/// Generated API structures that represent an event implement this trait.
|
||||
///
|
||||
/// The trait is utilized to decode emitted events from a block, via obtaining the
|
||||
/// form of the `Event` from the metadata.
|
||||
pub trait Event: Decode {
|
||||
/// Pallet name.
|
||||
const PALLET: &'static str;
|
||||
|
||||
@@ -37,7 +37,7 @@ use std::{
|
||||
sync::Arc,
|
||||
};
|
||||
|
||||
/// Metadata error.
|
||||
/// Metadata error originated from inspecting the internal representation of the runtime metadata.
|
||||
#[derive(Debug, thiserror::Error, PartialEq)]
|
||||
pub enum MetadataError {
|
||||
/// Module is not in metadata.
|
||||
@@ -97,7 +97,7 @@ struct MetadataInner {
|
||||
cached_storage_hashes: HashCache,
|
||||
}
|
||||
|
||||
/// Runtime metadata.
|
||||
/// A representation of the runtime metadata received from a node.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Metadata {
|
||||
inner: Arc<MetadataInner>,
|
||||
@@ -307,7 +307,10 @@ impl EventMetadata {
|
||||
}
|
||||
}
|
||||
|
||||
/// Metadata for specific errors.
|
||||
/// Metadata for specific errors obtained from the pallet's `PalletErrorMetadata`.
|
||||
///
|
||||
/// This holds in memory information regarding the Pallet's name, Error's name, and the underlying
|
||||
/// metadata representation.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct ErrorMetadata {
|
||||
pallet: String,
|
||||
@@ -332,6 +335,10 @@ impl ErrorMetadata {
|
||||
}
|
||||
}
|
||||
|
||||
/// Error originated from converting a runtime metadata [RuntimeMetadataPrefixed] to
|
||||
/// the internal [Metadata] representation.
|
||||
///
|
||||
/// The runtime metadata is converted when building the [crate::client::Client].
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub enum InvalidMetadataError {
|
||||
#[error("Invalid prefix")]
|
||||
|
||||
@@ -15,6 +15,49 @@
|
||||
// along with subxt. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! RPC types and client for interacting with a substrate node.
|
||||
//!
|
||||
//! This is used behind the scenes by various `subxt` APIs, but can
|
||||
//! also be used directly.
|
||||
//!
|
||||
//! # Examples
|
||||
//!
|
||||
//! ## Fetch Storage
|
||||
//!
|
||||
//! ```rust
|
||||
//! use subxt::rpc::Rpc;
|
||||
//! use subxt::storage::StorageKeyPrefix;
|
||||
//!
|
||||
//! // Storage prefix is `twox_128("System") ++ twox_128("ExtrinsicCount")`.
|
||||
//! let key = StorageKeyPrefix::new::<node_runtime::system::storage::ExtrinsicCount>()
|
||||
//! .to_storage_key();
|
||||
//!
|
||||
//! // Obtain the RPC from a generated API
|
||||
//! let rpc: &Rpc<_> = api
|
||||
//! .client
|
||||
//! .rpc();
|
||||
//!
|
||||
//! let result = rpc.storage(&key, None)?;
|
||||
//! println!("Storage result: {:?}", result);
|
||||
//! ```
|
||||
//!
|
||||
//! ## Fetch Keys
|
||||
//!
|
||||
//! ```rust
|
||||
//! use subxt::rpc::Rpc;
|
||||
//! use subxt::storage::StorageKeyPrefix;
|
||||
//! let key = StorageKeyPrefix::new::<polkadot::xcm_pallet::storage::VersionNotifiers>();
|
||||
//!
|
||||
//! // Obtain the RPC from a generated API
|
||||
//! let rpc: &Rpc<_> = api
|
||||
//! .client
|
||||
//! .rpc();
|
||||
//! // Fetch up to 10 keys.
|
||||
//! let keys = rpc
|
||||
//! .storage_keys_paged(Some(key), 10, None, None);
|
||||
//! for key in keys.iter() {
|
||||
//! println!("Key: 0x{}", hex::encode(&key));
|
||||
//! }
|
||||
//! ```
|
||||
|
||||
// jsonrpsee subscriptions are interminable.
|
||||
// Allows `while let status = subscription.next().await {}`
|
||||
|
||||
+41
-1
@@ -14,7 +14,47 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with subxt. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! For querying runtime storage.
|
||||
//! Query the runtime storage using [StorageClient].
|
||||
//!
|
||||
//! This module is the core of performing runtime storage queries. While you can
|
||||
//! work with it directly, it's prefer to use the generated `storage()` interface where
|
||||
//! possible.
|
||||
//!
|
||||
//! The exposed API is performing RPC calls to `state_getStorage` and `state_getKeysPaged`.
|
||||
//!
|
||||
//! A runtime storage entry can be of type:
|
||||
//! - [StorageEntryKey::Plain] for keys constructed just from the prefix
|
||||
//! `twox_128(pallet) ++ twox_128(storage_item)`
|
||||
//! - [StorageEntryKey::Map] for mapped keys constructed from the prefix,
|
||||
//! plus other arguments `twox_128(pallet) ++ twox_128(storage_item) ++ hash(arg1) ++ arg1`
|
||||
//!
|
||||
//! # Examples
|
||||
//!
|
||||
//! ## Fetch Storage Keys
|
||||
//!
|
||||
//! ```rust
|
||||
//! // Fetch just the keys, returning up to 10 keys.
|
||||
//! let keys = storage
|
||||
//! .fetch_keys::<node_runtime::xcm_pallet::storage::VersionNotifiers>(10, None, None)
|
||||
//! .await?;
|
||||
//! // Iterate over each key
|
||||
//! for key in keys.iter() {
|
||||
//! println!("Key: 0x{}", hex::encode(&key));
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! ## Iterate over Storage
|
||||
//!
|
||||
//! ```rust
|
||||
//! // Iterate over keys and values.
|
||||
//! let mut iter = storage
|
||||
//! .iter::<polkadot::xcm_pallet::storage::VersionNotifiers>(None)
|
||||
//! .await?;
|
||||
//! while let Some((key, value)) = iter.next().await? {
|
||||
//! println!("Key: 0x{}", hex::encode(&key));
|
||||
//! println!("Value: {}", value);
|
||||
//! }
|
||||
//! ```
|
||||
|
||||
use codec::{
|
||||
Decode,
|
||||
|
||||
+21
-1
@@ -14,7 +14,27 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with subxt. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! For performing runtime updates.
|
||||
//! Perform runtime updates in the background using [UpdateClient].
|
||||
//!
|
||||
//! There are cases when the node would perform a runtime update. As a result, the subxt's metadata
|
||||
//! would be out of sync and the API would not be able to submit valid extrinsics.
|
||||
//! This API keeps the `RuntimeVersion` and `Metadata` of the client synced with the target node.
|
||||
//!
|
||||
//! The runtime update is recommended for long-running clients, or for cases where manually
|
||||
//! restarting subxt would not be feasible. Even with this, extrinsics submitted during a node
|
||||
//! runtime update are at risk or failing, as it will take `subxt` a moment to catch up.
|
||||
//!
|
||||
//! ## Note
|
||||
//!
|
||||
//! Here we use tokio to check for updates in the background, but any runtime can be used.
|
||||
//!
|
||||
//! ```rust
|
||||
//! let update_client = client.updates();
|
||||
//! tokio::spawn(async move {
|
||||
//! let result = update_client.perform_runtime_updates().await;
|
||||
//! println!("Runtime update finished with result={:?}", result);
|
||||
//! });
|
||||
//! ```
|
||||
|
||||
use crate::{
|
||||
rpc::{
|
||||
|
||||
Reference in New Issue
Block a user