Remove decoding bit from "extrinsics" and reference decoding in "blocks" (#951)

* Remove decoding bits from 'tx' and reference decoding in 'blocks' instead

* newline

* doc and fmt fixes
This commit is contained in:
James Wilson
2023-05-11 13:12:51 +01:00
committed by GitHub
parent 3f16bb8d52
commit ae093bda7d
15 changed files with 65 additions and 210 deletions
-99
View File
@@ -1,99 +0,0 @@
// Copyright 2019-2023 Parity Technologies (UK) Ltd.
// This file is dual-licensed as Apache-2.0 or GPL-3.0.
// see LICENSE for license details.
//! To run this example, a local polkadot node should be running. Example verified against polkadot v0.9.28-9ffe6e9e3da.
//!
//! E.g.
//! ```bash
//! curl "https://github.com/paritytech/polkadot/releases/download/v0.9.28/polkadot" --output /usr/local/bin/polkadot --location
//! polkadot --dev --tmp
//! ```
use futures::StreamExt;
use sp_keyring::AccountKeyring;
use std::time::Duration;
use subxt::{tx::PairSigner, OnlineClient, PolkadotConfig};
#[subxt::subxt(runtime_metadata_path = "../artifacts/polkadot_metadata.scale")]
pub mod polkadot {}
/// Subscribe to all events, and then manually look through them and
/// pluck out the events that we care about.
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Create a client to use:
let api = OnlineClient::<PolkadotConfig>::new().await?;
// Subscribe to (in this case, finalized) blocks.
let mut block_sub = api.blocks().subscribe_finalized().await?;
// While this subscription is active, balance transfers are made somewhere:
tokio::task::spawn({
let api = api.clone();
async move {
let signer = PairSigner::new(AccountKeyring::Alice.pair());
let mut transfer_amount = 1_000_000_000;
// Make small balance transfers from Alice to Bob in a loop:
loop {
let transfer_tx = polkadot::tx()
.balances()
.transfer(AccountKeyring::Bob.to_account_id().into(), transfer_amount);
api.tx()
.sign_and_submit_default(&transfer_tx, &signer)
.await
.unwrap();
tokio::time::sleep(Duration::from_secs(10)).await;
transfer_amount += 100_000_000;
}
}
});
// Get each finalized block as it arrives.
while let Some(block) = block_sub.next().await {
let block = block?;
let block_hash = block.hash();
println!(" Block {:?}", block_hash);
// Ask for the extrinsics for this block.
let extrinsics = block.body().await?.extrinsics();
let transfer_tx = extrinsics.find_first::<polkadot::balances::calls::types::Transfer>();
println!(" Transfer tx: {:?}", transfer_tx);
// Ask for the extrinsics for this block.
for extrinsic in extrinsics.iter() {
let extrinsic = extrinsic?;
println!(
" Extrinsic block index {:?}, pallet index {:?}, variant index {:?}",
extrinsic.index(),
extrinsic.pallet_index(),
extrinsic.variant_index()
);
let root_extrinsic = extrinsic.as_root_extrinsic::<polkadot::Call>();
println!(" As root extrinsic {:?}\n", root_extrinsic);
let pallet_extrinsic = extrinsic
.as_pallet_extrinsic::<polkadot::runtime_types::pallet_balances::pallet::Call>();
println!(
" Extrinsic as Balances Pallet call: {:?}\n",
pallet_extrinsic
);
let call = extrinsic.as_extrinsic::<polkadot::balances::calls::types::Transfer>()?;
println!(
" Extrinsic as polkadot::balances::calls::Transfer: {:?}\n\n",
call
);
}
println!("\n");
}
Ok(())
}
+4
View File
@@ -31,8 +31,12 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
let events = ext.events().await?; let events = ext.events().await?;
let bytes_hex = format!("0x{}", hex::encode(ext.bytes())); let bytes_hex = format!("0x{}", hex::encode(ext.bytes()));
// See the API docs for more ways to decode extrinsics:
let decoded_ext = ext.as_root_extrinsic::<polkadot::Call>();
println!(" Extrinsic #{idx}:"); println!(" Extrinsic #{idx}:");
println!(" Bytes: {bytes_hex}"); println!(" Bytes: {bytes_hex}");
println!(" Decoded: {decoded_ext:?}");
println!(" Events:"); println!(" Events:");
for evt in events.iter() { for evt in events.iter() {
+2 -2
View File
@@ -64,7 +64,7 @@
//! accounts, Alice to Bob: //! accounts, Alice to Bob:
//! //!
//! ```rust,ignore //! ```rust,ignore
#![doc = include_str!("../../../examples/examples/balance_transfer_basic.rs")] #![doc = include_str!("../../../examples/examples/tx_basic.rs")]
//! ``` //! ```
//! //!
//! This example assumes that a Polkadot node is running locally (Subxt endeavors to support all //! This example assumes that a Polkadot node is running locally (Subxt endeavors to support all
@@ -81,7 +81,7 @@
//! Once Subxt is configured, the next step is interacting with a node. Follow the links //! Once Subxt is configured, the next step is interacting with a node. Follow the links
//! below to learn more about how to use Subxt for each of the following things: //! below to learn more about how to use Subxt for each of the following things:
//! //!
//! - [Extrinsics](usage::extrinsics): Subxt can build and submit extrinsics, wait until they are in //! - [Transactions](usage::transactions): Subxt can build and submit transactions, wait until they are in
//! blocks, and retrieve the associated events. //! blocks, and retrieve the associated events.
//! - [Storage](usage::storage): Subxt can query the node storage. //! - [Storage](usage::storage): Subxt can query the node storage.
//! - [Events](usage::events): Subxt can read the events emitted for recent blocks. //! - [Events](usage::events): Subxt can read the events emitted for recent blocks.
+2 -3
View File
@@ -35,18 +35,17 @@
//! //!
//! Defining some custom config based off the default Substrate config: //! Defining some custom config based off the default Substrate config:
//! //!
//!
//! ```rust,ignore //! ```rust,ignore
#![doc = include_str!("../../../../examples/examples/setup_client_custom_config.rs")] #![doc = include_str!("../../../../examples/examples/setup_client_custom_config.rs")]
//! ``` //! ```
//! Writing a custom [`crate::rpc::RpcClientT`] implementation:
//! //!
//! Writing a custom [`crate::rpc::RpcClientT`] implementation:
//! //!
//! ```rust,ignore //! ```rust,ignore
#![doc = include_str!("../../../../examples/examples/setup_client_custom_rpc.rs")] #![doc = include_str!("../../../../examples/examples/setup_client_custom_rpc.rs")]
//! ``` //! ```
//! Creating an [`crate::OfflineClient`]:
//! //!
//! Creating an [`crate::OfflineClient`]:
//! //!
//! ```rust,ignore //! ```rust,ignore
#![doc = include_str!("../../../../examples/examples/setup_client_offline.rs")] #![doc = include_str!("../../../../examples/examples/setup_client_offline.rs")]
+5 -5
View File
@@ -24,14 +24,14 @@
//! - [events](crate::blocks::Block::events()) //! - [events](crate::blocks::Block::events())
//! - [runtime APIs](crate::blocks::Block::runtime_api()) //! - [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.
//!
//! ## Example //! ## Example
//! //!
//! Given a block, you can [download the block body](crate::blocks::Block::body()) and iterate over //! Given a block, you can [download the block body](crate::blocks::Block::body()) and iterate over
//! the extrinsics stored within it using [`crate::blocks::BlockBody::extrinsics()`]. //! the extrinsics stored within it using [`crate::blocks::BlockBody::extrinsics()`]. From there, you
//! //! can decode the extrinsics and access various details, including the associated events:
//! Here's an example in which we subscribe to blocks and print a bunch of information about each
//! one:
//!
//! //!
//! ```rust,ignore //! ```rust,ignore
#![doc = include_str!("../../../../examples/examples/blocks_subscribing.rs")] #![doc = include_str!("../../../../examples/examples/blocks_subscribing.rs")]
+1 -2
View File
@@ -48,12 +48,11 @@
//! //!
//! Here's an example using a static query: //! Here's an example using a static query:
//! //!
//!
//! ```rust,ignore //! ```rust,ignore
#![doc = include_str!("../../../../examples/examples/constants_static.rs")] #![doc = include_str!("../../../../examples/examples/constants_static.rs")]
//! ``` //! ```
//! And here's one using a dynamic query:
//! //!
//! And here's one using a dynamic query:
//! //!
//! ```rust,ignore //! ```rust,ignore
#![doc = include_str!("../../../../examples/examples/constants_dynamic.rs")] #![doc = include_str!("../../../../examples/examples/constants_dynamic.rs")]
+3 -4
View File
@@ -13,10 +13,10 @@
//! keep a snapshot of the state at a small number of previous blocks, so you can sometimes access //! 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. //! older events by using [`crate::events::EventsClient::at()`] and providing an older block hash.
//! //!
//! When we submit extrinsics using Subxt, methods like [`crate::tx::TxProgress::wait_for_finalized_success()`] //! 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 //! return [`crate::blocks::ExtrinsicEvents`], which can be used to iterate and inspect the events produced
//! for a specific extrinsic. We can also access _all_ of the events produced in a single block using one of these //! by that transaction being executed. We can also access _all_ of the events produced in a single block using one
//! two interfaces: //! of these two interfaces:
//! //!
//! ```rust,no_run //! ```rust,no_run
//! # #[tokio::main] //! # #[tokio::main]
@@ -43,7 +43,6 @@
//! //!
//! Here's an example which puts this all together: //! Here's an example which puts this all together:
//! //!
//!
//! ```rust,ignore //! ```rust,ignore
#![doc = include_str!("../../../../examples/examples/events.rs")] #![doc = include_str!("../../../../examples/examples/events.rs")]
//! ``` //! ```
+2 -2
View File
@@ -4,7 +4,7 @@
//! This modules contains examples of using Subxt; follow the links for more: //! This modules contains examples of using Subxt; follow the links for more:
//! //!
//! - [Extrinsics](extrinsics) //! - [Transactions](transactions)
//! - [Storage](storage) //! - [Storage](storage)
//! - [Events](events) //! - [Events](events)
//! - [Constants](constants) //! - [Constants](constants)
@@ -16,6 +16,6 @@
pub mod blocks; pub mod blocks;
pub mod constants; pub mod constants;
pub mod events; pub mod events;
pub mod extrinsics;
pub mod runtime_apis; pub mod runtime_apis;
pub mod storage; pub mod storage;
pub mod transactions;
+1 -1
View File
@@ -5,7 +5,7 @@
//! # Runtime API interface //! # Runtime API interface
//! //!
//! The Runtime API interface allows Subxt to call runtime APIs exposed by certain pallets in order //! 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::extrinsics`], Making a runtime //! 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: //! call to a node and getting the response back takes the following steps:
//! //!
//! 1. [Constructing a runtime call](#constructing-a-runtime-call) //! 1. [Constructing a runtime call](#constructing-a-runtime-call)
+7 -6
View File
@@ -4,8 +4,9 @@
//! # Storage //! # Storage
//! //!
//! A Substrate based chain has storage, whose values are determined by the extrinsics added to past //! A Substrate based chain can be seen as a key/value database which starts off at some initial
//! blocks. Subxt allows you to query the storage of a node, which consists of the following steps: //! 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). //! 1. [Constructing a storage query](#constructing-a-storage-query).
//! 2. [Submitting the query to get back the associated values](#submitting-it). //! 2. [Submitting the query to get back the associated values](#submitting-it).
@@ -73,33 +74,33 @@
//! [`crate::storage::Storage::fetch()`] or [`crate::storage::Storage::fetch_or_default()`] (the //! [`crate::storage::Storage::fetch()`] or [`crate::storage::Storage::fetch_or_default()`] (the
//! latter will only work for storage queries that have a default value when empty): //! latter will only work for storage queries that have a default value when empty):
//! //!
//!
//! ```rust,ignore //! ```rust,ignore
#![doc = include_str!("../../../../examples/examples/storage_fetch.rs")] #![doc = include_str!("../../../../examples/examples/storage_fetch.rs")]
//! ``` //! ```
//!
//! For completeness, below is an example using a dynamic query instead. The return type from a //! For completeness, below is an example using a dynamic query instead. The return type from a
//! dynamic query is a [`crate::dynamic::DecodedValueThunk`], which can be decoded into a //! dynamic query is a [`crate::dynamic::DecodedValueThunk`], which can be decoded into a
//! [`crate::dynamic::Value`], or else the raw bytes can be accessed instead. //! [`crate::dynamic::Value`], or else the raw bytes can be accessed instead.
//! //!
//!
//! ```rust,ignore //! ```rust,ignore
#![doc = include_str!("../../../../examples/examples/storage_fetch_dynamic.rs")] #![doc = include_str!("../../../../examples/examples/storage_fetch_dynamic.rs")]
//! ``` //! ```
//!
//! ### Iterating storage entries //! ### Iterating storage entries
//! //!
//! Many storage entries are maps of values; as well as fetching individual values, it's possible to //! 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: //! iterate over all of the values stored at that location:
//! //!
//!
//! ```rust,ignore //! ```rust,ignore
#![doc = include_str!("../../../../examples/examples/storage_iterating.rs")] #![doc = include_str!("../../../../examples/examples/storage_iterating.rs")]
//! ``` //! ```
//! Here's the same logic but using dynamically constructed values instead:
//! //!
//! Here's the same logic but using dynamically constructed values instead:
//! //!
//! ```rust,ignore //! ```rust,ignore
#![doc = include_str!("../../../../examples/examples/storage_iterating_dynamic.rs")] #![doc = include_str!("../../../../examples/examples/storage_iterating_dynamic.rs")]
//! ``` //! ```
//!
//! ### Advanced //! ### Advanced
//! //!
//! For more advanced use cases, have a look at [`crate::storage::Storage::fetch_raw`] and //! For more advanced use cases, have a look at [`crate::storage::Storage::fetch_raw`] and
@@ -2,35 +2,35 @@
// This file is dual-licensed as Apache-2.0 or GPL-3.0. // This file is dual-licensed as Apache-2.0 or GPL-3.0.
// see LICENSE for license details. // see LICENSE for license details.
//! # Extrinsics //! # Transactions
//! //!
//! Extrinsics define function calls and their parameters, and are the only way that you can change //! A transaction is an extrinsic that's signed (ie it originates from a given address). The purpose
//! the state of the blockchain. Submitting extrinsics to a node is one of the core features of //! of extrinsics is to modify the node storage in a deterministic way, and so being able to submit
//! Subxt, and generally consists of the following steps: //! transactions to a node is one of the core features of Subxt.
//! //!
//! 1. [Constructing an extrinsic payload to submit](#constructing-an-extrinsic-payload). //! > 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). //! 2. [Signing it](#signing-it).
//! 3. [Submitting it (optionally with some additional parameters)](#submitting-it). //! 3. [Submitting it (optionally with some additional parameters)](#submitting-it).
//! //!
//! We'll look at each of these steps in turn. //! We'll look at each of these steps in turn.
//! //!
//! > As a side note, an _extrinsic_ is anything that can be added to a block, and a _transaction_ //! ## Constructing a transaction payload
//! > is an extrinsic that is submitted from a particular user (and is therefore also signed). Subxt
//! > can construct unsigned extrinsics, but overwhelmingly you'll need to sign them, and so the
//! > documentation tends to use the terms _extrinsic_ and _transaction_ interchangeably.
//! //!
//! Furthermore, Subxt is capable of decoding extrinsics included in blocks. //! We can use the statically generated interface to build transaction payloads:
//!
//! ## Constructing an extrinsic payload
//!
//! We can use the statically generated interface to build extrinsic payloads:
//! //!
//! ```rust,no_run //! ```rust,no_run
//! #[subxt::subxt(runtime_metadata_path = "../artifacts/polkadot_metadata.scale")] //! #[subxt::subxt(runtime_metadata_path = "../artifacts/polkadot_metadata.scale")]
//! pub mod polkadot {} //! pub mod polkadot {}
//! //!
//! let remark = "Hello there".as_bytes().to_vec(); //! let remark = "Hello there".as_bytes().to_vec();
//! let extrinsic_payload = polkadot::tx().system().remark(remark); //! 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 //! > If you're not sure what types to import and use to build a given payload, you can use the
@@ -38,13 +38,13 @@
//! > interface.rs`, to see what types and things are available (or even just to use directly //! > interface.rs`, to see what types and things are available (or even just to use directly
//! > instead of the [`#[subxt]`](crate::subxt) macro). //! > instead of the [`#[subxt]`](crate::subxt) macro).
//! //!
//! Alternately, we can dynamically construct an extrinsic payload. This will not be type checked or //! Alternately, we can dynamically construct a transaction payload. This will not be type checked or
//! validated until it's submitted: //! validated until it's submitted:
//! //!
//! ```rust,no_run //! ```rust,no_run
//! use subxt::dynamic::Value; //! use subxt::dynamic::Value;
//! //!
//! let extrinsic_payload = subxt::dynamic::tx("System", "remark", vec![ //! let tx_payload = subxt::dynamic::tx("System", "remark", vec![
//! Value::from_bytes("Hello there") //! Value::from_bytes("Hello there")
//! ]); //! ]);
//! ``` //! ```
@@ -53,7 +53,7 @@
//! represents any type of data that can be SCALE encoded or decoded. It can be serialized, //! represents any type of data that can be SCALE encoded or decoded. It can be serialized,
//! deserialized and parsed from/to strings. //! deserialized and parsed from/to strings.
//! //!
//! A valid extrinsic payload is just something that implements the [`crate::tx::TxPayload`] trait; //! A valid transaction payload is just something that implements the [`crate::tx::TxPayload`] trait;
//! you can implement this trait on your own custom types if the built-in ones are not suitable for //! you can implement this trait on your own custom types if the built-in ones are not suitable for
//! your needs. //! your needs.
//! //!
@@ -96,21 +96,21 @@
//! // Create client: //! // Create client:
//! let client = OnlineClient::<PolkadotConfig>::new().await?; //! let client = OnlineClient::<PolkadotConfig>::new().await?;
//! //!
//! // Create a dummy extrinsic payload to sign: //! // Create a dummy tx payload to sign:
//! let payload = subxt::dynamic::tx("System", "remark", vec![ //! let payload = subxt::dynamic::tx("System", "remark", vec![
//! Value::from_bytes("Hello there") //! Value::from_bytes("Hello there")
//! ]); //! ]);
//! //!
//! // Construct the extrinsic but don't sign it. You need to provide the nonce //! // Construct the tx but don't sign it. You need to provide the nonce
//! // here, or can use `create_partial_signed` to fetch the correct nonce. //! // here, or can use `create_partial_signed` to fetch the correct nonce.
//! let partial_extrinsic = client.tx().create_partial_signed_with_nonce( //! let partial_tx = client.tx().create_partial_signed_with_nonce(
//! &payload, //! &payload,
//! 0, //! 0,
//! Default::default() //! Default::default()
//! )?; //! )?;
//! //!
//! // Fetch the payload that needs to be signed: //! // Fetch the payload that needs to be signed:
//! let signer_payload = partial_extrinsic.signer_payload(); //! let signer_payload = partial_tx.signer_payload();
//! //!
//! // ... At this point, we can hand off the `signer_payload` to be signed externally. //! // ... 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 //! // Ultimately we need to be given back a `signature` (or really, anything
@@ -123,9 +123,9 @@
//! # signature = signer.sign(&signer_payload); //! # signature = signer.sign(&signer_payload);
//! # address = signer.address(); //! # address = signer.address();
//! //!
//! // Now we can build an extrinsic, which one can call `submit` or `submit_and_watch` //! // 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. //! // on to submit to a node and optionally watch the status.
//! let extrinsic = partial_extrinsic.sign_with_address_and_signature( //! let tx = partial_tx.sign_with_address_and_signature(
//! &address, //! &address,
//! &signature //! &signature
//! ); //! );
@@ -135,7 +135,7 @@
//! //!
//! ## Submitting it //! ## Submitting it
//! //!
//! Once we are able to sign the extrinsic, we need to submit it. //! Once we have signed the transaction, we need to submit it.
//! //!
//! ### The high level API //! ### The high level API
//! //!
@@ -146,21 +146,20 @@
//! into a finalized block, check for an `ExtrinsicSuccess` event, and then hand back the events for //! into a finalized block, check for an `ExtrinsicSuccess` event, and then hand back the events for
//! inspection. This looks like: //! inspection. This looks like:
//! //!
//! ```rust,ignore
#![doc = include_str!("../../../../examples/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 //! ```rust,ignore
#![doc = include_str!("../../../../examples/examples/balance_transfer_basic.rs")] #![doc = include_str!("../../../../examples/examples/tx_with_params.rs")]
//! ``` //! ```
//! ### Providing extrinsic parameters
//! //!
//! If you'd like to provide extrinsic parameters (such as mortality), you can use //! This example doesn't wait for the transaction to be included in a block; it just submits it and
//! [`crate::tx::TxClient::sign_and_submit_then_watch`] instead, and provide parameters for your
//! chain:
//!
//!
//! ```rust,ignore
#![doc = include_str!("../../../../examples/examples/balance_transfer_with_params.rs")]
//! ```
//! This example doesn't wait for the extrinsic to be included in a block; it just submits it and
//! hopes for the best! //! hopes for the best!
//! //!
//! ### Custom handling of transaction status updates //! ### Custom handling of transaction status updates
@@ -168,57 +167,10 @@
//! If you'd like more control or visibility over exactly which status updates are being emitted for //! 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: //! the transaction, you can monitor them as they are emitted and react however you choose:
//! //!
//!
//! ```rust,ignore //! ```rust,ignore
#![doc = include_str!("../../../../examples/examples/balance_transfer_status_stream.rs")] #![doc = include_str!("../../../../examples/examples/tx_status_stream.rs")]
//! ``` //! ```
//!
//! Take a look at the API docs for [`crate::tx::TxProgress`], [`crate::tx::TxStatus`] and //! Take a look at the API docs for [`crate::tx::TxProgress`], [`crate::tx::TxStatus`] and
//! [`crate::tx::TxInBlock`] for more options. //! [`crate::tx::TxInBlock`] for more options.
//! //!
//! ## Decoding Extrinsics
//!
//! The block body is made up of extrinsics representing the generalization of the concept of transactions.
//! Extrinsics can contain any external data the underlying chain wishes to validate and track.
//!
//! The process of decoding extrinsics generally involves the following steps:
//!
//! 1. Retrieve a block from the chain: This can be done directly by providing a specific hash using [crate::blocks::BlocksClient::at()]
//! and [crate::blocks::BlocksClient::at_latest()], or indirectly by subscribing to the latest produced blocks of the chain using
//! [crate::blocks::BlocksClient::subscribe_finalized()].
//!
//! 2. Fetch the block's body using [crate::blocks::Block::body()].
//!
//! 3. Obtain the extrinsics from the block's body using [crate::blocks::BlockBody::extrinsics()].
//!
//! ```rust,no_run
//! # #[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 the lastest block (or use .at() to specify a block hash):
//! let block = client.blocks().at_latest().await?;
//!
//! // Get the block's body which contains the extrinsics.
//! let body = block.body().await?;
//!
//! // Fetch the extrinsics of the block's body.
//! let extrinsics = block.body().await?.extrinsics();
//! # Ok(())
//! # }
//! ```
//!
//! Once the extrinsics are loaded, similar to events, you can iterate through the extrinsics or search for specific extrinsics using methods
//! such as [crate::blocks::Extrinsics::iter()] and [crate::blocks::Extrinsics::find()]. For more information, refer to [crate::blocks::ExtrinsicDetails].
//!
//! ### Example
//!
//! Here's an example that demonstrates the usage of these concepts:
//!
//! ```rust,ignore
#![doc = include_str!("../../../../examples/examples/block_extrinsics.rs")]
//! ```
//!
+1 -1
View File
@@ -5,7 +5,7 @@
//! Subxt is a library for interacting with Substrate based nodes. Using it looks something like this: //! Subxt is a library for interacting with Substrate based nodes. Using it looks something like this:
//! //!
//! ```rust,ignore //! ```rust,ignore
#![doc = include_str!("../../examples/examples/balance_transfer_basic.rs")] #![doc = include_str!("../../examples/examples/tx_basic.rs")]
//! ``` //! ```
//! //!
//! Take a look at [the Subxt guide](book) to learn more about how to use Subxt. //! Take a look at [the Subxt guide](book) to learn more about how to use Subxt.