mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-05-08 19:28:01 +00:00
More examples and get compiling with deny(missing_docs)
This commit is contained in:
@@ -83,7 +83,7 @@ impl RuntimeGenerator {
|
||||
|
||||
Ok(quote! {
|
||||
#( #item_mod_attrs )*
|
||||
#[allow(dead_code, unused_imports, non_camel_case_types, unreachable_patterns)]
|
||||
#[allow(dead_code, missing_docs, unused_imports, non_camel_case_types, unreachable_patterns)]
|
||||
#[allow(clippy::all)]
|
||||
#[allow(rustdoc::broken_intra_doc_links)]
|
||||
pub mod #mod_ident {
|
||||
@@ -247,7 +247,7 @@ impl RuntimeGenerator {
|
||||
|
||||
Ok(quote! {
|
||||
#( #item_mod_attrs )*
|
||||
#[allow(dead_code, unused_imports, non_camel_case_types, unreachable_patterns)]
|
||||
#[allow(dead_code, missing_docs, unused_imports, non_camel_case_types, unreachable_patterns)]
|
||||
#[allow(clippy::all)]
|
||||
#[allow(rustdoc::broken_intra_doc_links)]
|
||||
pub mod #mod_ident {
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
//! Subscribe to blocks.
|
||||
use subxt::dynamic::Value;
|
||||
use subxt::{Error, OnlineClient, PolkadotConfig};
|
||||
|
||||
#[subxt::subxt(runtime_metadata_path = "../artifacts/polkadot_metadata_small.scale")]
|
||||
mod polkadot {}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<(), Error> {
|
||||
// Create a new API client, configured to talk to Polkadot nodes.
|
||||
let config = PolkadotConfig::new();
|
||||
let api = OnlineClient::new(config).await?;
|
||||
|
||||
// Stream the finalized blocks. See the OnlineClient docs for how to
|
||||
// stream best blocks or all new blocks.
|
||||
let mut blocks = api.stream_blocks().await?;
|
||||
|
||||
while let Some(block) = blocks.next().await {
|
||||
let block = block?;
|
||||
|
||||
let block_number = block.number();
|
||||
let block_hash = block.hash();
|
||||
|
||||
println!("Block #{block_number}:");
|
||||
println!(" Hash: {block_hash}");
|
||||
println!(" Extrinsics:");
|
||||
|
||||
// Create a client to work at this block. From here you have the
|
||||
// same interface as `api.block(block.hash()).await`.
|
||||
let at_block = block.at().await?;
|
||||
|
||||
// Here we'll obtain and display the extrinsics:
|
||||
let extrinsics = at_block.extrinsics().fetch().await?;
|
||||
for ext in extrinsics.iter() {
|
||||
let ext = ext?;
|
||||
|
||||
let idx = ext.index();
|
||||
let pallet_name = ext.pallet_name();
|
||||
let call_name = ext.call_name();
|
||||
let bytes_hex = format!("0x{}", hex::encode(ext.bytes()));
|
||||
let events = ext.events().await?;
|
||||
|
||||
// See the API docs for more ways to decode extrinsics:
|
||||
let decoded_ext = ext.decode_call_data_as::<polkadot::Call>()?;
|
||||
|
||||
println!(" #{idx}: {pallet_name}.{call_name}:");
|
||||
println!(" Bytes: {bytes_hex}");
|
||||
println!(" Decoded: {decoded_ext:?}");
|
||||
|
||||
for evt in events.iter() {
|
||||
println!(" Events:");
|
||||
let evt = evt?;
|
||||
let event_idx = evt.event_index();
|
||||
let pallet_name = evt.pallet_name();
|
||||
let event_name = evt.event_name();
|
||||
let event_values = evt.decode_fields_unchecked_as::<Value>()?;
|
||||
|
||||
println!(" #{event_idx}: {pallet_name}.{event_name}");
|
||||
println!(" {event_values}");
|
||||
}
|
||||
|
||||
if let Some(transaction_extensions) = ext.transaction_extensions() {
|
||||
println!(" Transaction Extensions:");
|
||||
for transaction_extension in transaction_extensions.iter() {
|
||||
let name = transaction_extension.name();
|
||||
let value = transaction_extension.decode_unchecked_as::<Value>()?;
|
||||
println!(" {name}: {value}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
//! Working with historic blocks.
|
||||
use subxt::dynamic::Value;
|
||||
use subxt::{Error, OnlineClient, PolkadotConfig};
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<(), Error> {
|
||||
// Point at an archive node since we want to obtain old blocks.
|
||||
let config = PolkadotConfig::new();
|
||||
let api = OnlineClient::from_url(config, "wss://rpc.polkadot.io").await?;
|
||||
|
||||
for block_number in 1234567u32.. {
|
||||
let at_block = api.at_block(block_number).await?;
|
||||
|
||||
let block_number = at_block.block_number();
|
||||
let block_hash = at_block.block_hash();
|
||||
|
||||
println!("Block #{block_number}:");
|
||||
println!(" Hash: {block_hash}");
|
||||
println!(" Extrinsics:");
|
||||
|
||||
// Here we'll obtain and display the extrinsics:
|
||||
let extrinsics = at_block.extrinsics().fetch().await?;
|
||||
for ext in extrinsics.iter() {
|
||||
let ext = ext?;
|
||||
|
||||
let idx = ext.index();
|
||||
let pallet_name = ext.pallet_name();
|
||||
let call_name = ext.call_name();
|
||||
let bytes_hex = format!("0x{}", hex::encode(ext.bytes()));
|
||||
let events = ext.events().await?;
|
||||
|
||||
// See the API docs for more ways to decode extrinsics. Here, since we're
|
||||
// accessing a historic block, we don't use any generated types to help us.
|
||||
let decoded_ext = ext.decode_call_data_fields_unchecked_as::<Value>()?;
|
||||
|
||||
println!(" #{idx}: {pallet_name}.{call_name}:");
|
||||
println!(" Bytes: {bytes_hex}");
|
||||
println!(" Decoded: {decoded_ext}");
|
||||
|
||||
for evt in events.iter() {
|
||||
println!(" Events:");
|
||||
let evt = evt?;
|
||||
let event_idx = evt.event_index();
|
||||
let pallet_name = evt.pallet_name();
|
||||
let event_name = evt.event_name();
|
||||
let event_values = evt.decode_fields_unchecked_as::<Value>()?;
|
||||
|
||||
println!(" #{event_idx}: {pallet_name}.{event_name}");
|
||||
println!(" {event_values}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
//! Fetching and iterating over storage entries.
|
||||
use subxt::dynamic::Value;
|
||||
use subxt::utils::AccountId32;
|
||||
use subxt::{Error, OnlineClient, PolkadotConfig};
|
||||
|
||||
#[subxt::subxt(runtime_metadata_path = "../artifacts/polkadot_metadata_small.scale")]
|
||||
mod polkadot {}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<(), Error> {
|
||||
let config = PolkadotConfig::new();
|
||||
let api = OnlineClient::new(config).await?;
|
||||
let at_block = api.at_current_block().await?;
|
||||
|
||||
// Here we use a statically generated address to fetch the storage entry, which
|
||||
// gives us type information for future actions on it.
|
||||
let account_balances = at_block
|
||||
.storage()
|
||||
.entry(polkadot::storage().system().account())?;
|
||||
|
||||
// We can see the default value for this entry at this block, if one exists.
|
||||
if let Some(default_value) = account_balances.default_value() {
|
||||
let default_balance_info = default_value.decode_as::<Value>()?;
|
||||
println!("Default balance info: {default_balance_info}");
|
||||
}
|
||||
|
||||
// We can fetch a specific account balance by its key, like so (here I just picked a random key
|
||||
// I knew to exist from iterating over storage entries):
|
||||
let account_id = {
|
||||
let hex = "9a4d0faa2ba8c3cc5711852960940793acf55bf195b6eecf88fa78e961d0ce4a";
|
||||
let bytes: [u8; 32] = hex::decode(hex).unwrap().try_into().unwrap();
|
||||
AccountId32::from(bytes)
|
||||
};
|
||||
let entry = account_balances.fetch((account_id,)).await?;
|
||||
|
||||
// We can decode the value into our generic `Value` type, which can
|
||||
// represent any SCALE-encoded value, like so:
|
||||
let _balance_info = entry.decode_as::<Value>()?;
|
||||
|
||||
// Or we can decode into a known shape. Any type implementing DecodeAsType can
|
||||
// be used here to extract fields you're interested in, or we can use the generated
|
||||
// type which already implements this:
|
||||
type AccountInfo = polkadot::system::storage::account::output::Output;
|
||||
let balance_info = entry.decode_as::<AccountInfo>()?;
|
||||
|
||||
println!(
|
||||
"Single balance info from {account_id} => free: {} reserved: {} frozen: {} flags: {:?}",
|
||||
balance_info.data.free,
|
||||
balance_info.data.reserved,
|
||||
balance_info.data.frozen,
|
||||
balance_info.data.flags,
|
||||
);
|
||||
|
||||
// Or we can iterate over all of the account balances and print them out. Here we provide an
|
||||
// empty tuple, indicating that we want to iterate over everything and not only things under a certain key
|
||||
// (in the case of account balances, there is only one key anyway, but other storage entries may map from
|
||||
// several keys to a value, and for those we can choose which depth we iterate at by providing as many keys
|
||||
// as we want and leaving the rest).
|
||||
let mut all_balances = account_balances.iter(()).await?;
|
||||
while let Some(entry) = all_balances.next().await {
|
||||
let entry = entry?;
|
||||
let key = entry.key()?;
|
||||
|
||||
// Because we provided a statically typed Address when we originally obtained this
|
||||
// storage entry (ie `polkadot::storage().system().account()`), we can statically
|
||||
// decode the key into its well typed constituent parts:
|
||||
let key_parts = key.decode()?;
|
||||
println!("Account ID: {}", key_parts.0);
|
||||
|
||||
// Alternately, if we don't have type information available (or just want to decode
|
||||
// into some different type), we can do something like this instead:
|
||||
let account_id = key
|
||||
.part(0)
|
||||
.unwrap()
|
||||
.decode_as::<AccountId32>()?
|
||||
.expect("We expect this key to decode into a 32 byte AccountId");
|
||||
|
||||
// Decode these values into our generic scale_value::Value type. Less efficient than
|
||||
// defining a static type as above, but easier for the sake of the example.
|
||||
let balance_info = entry.value().decode_as::<scale_value::Value>()?;
|
||||
println!(" {account_id} => {balance_info}");
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -1,10 +1,10 @@
|
||||
#![allow(missing_docs)]
|
||||
//! Construct and submit a transaction.
|
||||
use subxt::{Error, OnlineClient, PolkadotConfig};
|
||||
use subxt_signer::sr25519::dev;
|
||||
|
||||
// Generate an interface that we can use from the node's metadata.
|
||||
#[subxt::subxt(runtime_metadata_path = "../artifacts/polkadot_metadata_small.scale")]
|
||||
pub mod polkadot {}
|
||||
mod polkadot {}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<(), Error> {
|
||||
@@ -18,6 +18,7 @@ use futures::StreamExt;
|
||||
use std::task::Poll;
|
||||
use subxt_rpcs::RpcClient;
|
||||
|
||||
/// A builder to configure and build a [`CombinedBackend`].
|
||||
pub struct CombinedBackendBuilder<T: Config> {
|
||||
archive: BackendChoice<ArchiveBackend<T>>,
|
||||
chainhead: BackendChoice<ChainHeadBackend<T>>,
|
||||
@@ -183,6 +184,8 @@ pub struct CombinedBackendDriver<T: Config> {
|
||||
}
|
||||
|
||||
impl<T: Config> CombinedBackendDriver<T> {
|
||||
/// this returns true if this [`CombinedBackendDriver`] needs polling in
|
||||
/// order to drive the [`CombinedBackend`], and false if it does not.
|
||||
pub fn needs_polling(&self) -> bool {
|
||||
self.chainhead_driver.is_some()
|
||||
}
|
||||
|
||||
+19
-4
@@ -1,3 +1,15 @@
|
||||
//! This module exposes the entrypoint to connect and interact with chains.
|
||||
//!
|
||||
//! - See [`OnlineClient`] for instantiating a standard client which is connected to
|
||||
//! a chain and capable of interacting with it.
|
||||
//! - See [`OfflineClient`] if you have no network connection but want to perform certain
|
||||
//! actions against some chain.
|
||||
//!
|
||||
//! After instantiating a client, you'll typically then select a block to work against
|
||||
//! via something like [`OnlineClient::at_block`] or [`OfflineClient::at_block`].
|
||||
//! These hand back [`OnlineClientAtBlock`] or [`OfflineClientAtBlock`], which expose
|
||||
//! various methods available online or offline at the given block.
|
||||
|
||||
mod offline_client;
|
||||
mod online_client;
|
||||
|
||||
@@ -19,10 +31,12 @@ pub use online_client::{
|
||||
BlockNumberOrRef, OnlineClient, OnlineClientAtBlockImpl, OnlineClientAtBlockT,
|
||||
};
|
||||
|
||||
/// This represents a client at a specific block number. This wraps a client impl
|
||||
/// which will either be [`OfflineClientAtBlockImpl`] or [`OnlineClientAtBlockImpl`].
|
||||
/// Prefer to use the type aliases [`OfflineClientAtBlock`] and [`OnlineClientAtBlock`]
|
||||
/// if you need to refer to the concrete instances of this.
|
||||
/// This represents a client at a specific block number, and is created by calling either
|
||||
/// [`OnlineClient::at_block`] or [`OfflineClient::at_block`].
|
||||
///
|
||||
/// This wraps a client implementation, which will either be [`OfflineClientAtBlockImpl`]
|
||||
/// or [`OnlineClientAtBlockImpl`]. Prefer to use the type aliases [`OfflineClientAtBlock`]
|
||||
/// and [`OnlineClientAtBlock`] if you need to refer to the concrete instances of this.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct ClientAtBlock<T, Client> {
|
||||
pub(crate) client: Client,
|
||||
@@ -85,6 +99,7 @@ where
|
||||
RuntimeApisClient::new(&self.client)
|
||||
}
|
||||
|
||||
/// Access Pallet View Functions at this block.
|
||||
pub fn view_functions(&self) -> ViewFunctionsClient<'_, T, Client> {
|
||||
ViewFunctionsClient::new(&self.client)
|
||||
}
|
||||
|
||||
@@ -3,6 +3,8 @@ use crate::config::{Config, HashFor, Hasher};
|
||||
use crate::error::OfflineClientAtBlockError;
|
||||
use crate::metadata::{ArcMetadata, Metadata};
|
||||
|
||||
/// A client which does not require a connection to a chain, and can perform certain
|
||||
/// actions which don't require a network connection.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct OfflineClient<T: Config> {
|
||||
/// The configuration for this client.
|
||||
|
||||
@@ -22,7 +22,7 @@ use crate::error::OnlineClientError;
|
||||
|
||||
pub use block_number_or_ref::BlockNumberOrRef;
|
||||
|
||||
/// A client which exposes the means to decode historic data on a chain online.
|
||||
/// A client which requires a connection to a chain, and allows interacting with it.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct OnlineClient<T: Config> {
|
||||
inner: Arc<OnlineClientInner<T>>,
|
||||
|
||||
@@ -22,6 +22,12 @@ impl<T: Config> From<u64> for BlockNumberOrRef<T> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Config> From<usize> for BlockNumberOrRef<T> {
|
||||
fn from(value: usize) -> Self {
|
||||
BlockNumberOrRef::Number(value as u64)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Config> From<BlockRef<HashFor<T>>> for BlockNumberOrRef<T> {
|
||||
fn from(block_ref: BlockRef<HashFor<T>>) -> Self {
|
||||
BlockNumberOrRef::BlockRef(block_ref)
|
||||
|
||||
@@ -19,6 +19,11 @@ impl<T: Config> Blocks<T> {
|
||||
) -> Self {
|
||||
Blocks { client, stream }
|
||||
}
|
||||
|
||||
/// Return the next block in the stream when it is produced.
|
||||
pub async fn next(&mut self) -> Option<Result<Block<T>, BlocksError>> {
|
||||
StreamExt::next(self).await
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Config> Stream for Blocks<T> {
|
||||
@@ -68,7 +73,7 @@ impl<T: Config> Block<T> {
|
||||
}
|
||||
|
||||
/// Instantiate a client at this block.
|
||||
pub async fn client(
|
||||
pub async fn at(
|
||||
&self,
|
||||
) -> Result<ClientAtBlock<T, OnlineClientAtBlockImpl<T>>, OnlineClientAtBlockError> {
|
||||
self.client.at_block(self.block_ref.clone()).await
|
||||
|
||||
+9
-5
@@ -2,11 +2,15 @@
|
||||
// This file is dual-licensed as Apache-2.0 or GPL-3.0.
|
||||
// see LICENSE for license details.
|
||||
|
||||
//! This module provides a [`Config`] type, which is used to define various
|
||||
//! types that are important in order to speak to a particular chain.
|
||||
//! [`SubstrateConfig`] provides a default set of these types suitable for the
|
||||
//! default Substrate node implementation, and [`PolkadotConfig`] for a
|
||||
//! Polkadot node.
|
||||
//! This module provides a [`Config`] type, which provides a way to configure Subxt to work with a
|
||||
//! specific chain.
|
||||
//!
|
||||
//! - A generic [`SubstrateConfig`] implementation is provided that will work against modern
|
||||
//! blocks with most Substrate based chains automatically, and can be configured to work with
|
||||
//! historic blocks.
|
||||
//! - A [`PolkadotConfig`] implementation is provided which is specialized towards the Polkadot
|
||||
//! Relay Chain, and comes pre-configured to work against historic Polkadot RC blocks.
|
||||
//!
|
||||
|
||||
mod default_extrinsic_params;
|
||||
|
||||
|
||||
@@ -15,7 +15,10 @@ pub use crate::utils::{AccountId32, MultiAddress, MultiSignature};
|
||||
pub use primitive_types::{H256, U256};
|
||||
|
||||
/// Construct a [`PolkadotConfig`] using this.
|
||||
pub struct PolkadotConfigBuilder(SubstrateConfigBuilder);
|
||||
pub struct PolkadotConfigBuilder {
|
||||
use_historic_types: bool,
|
||||
inner: SubstrateConfigBuilder,
|
||||
}
|
||||
|
||||
impl Default for PolkadotConfigBuilder {
|
||||
fn default() -> Self {
|
||||
@@ -26,10 +29,19 @@ impl Default for PolkadotConfigBuilder {
|
||||
impl PolkadotConfigBuilder {
|
||||
/// Create a new [`PolkadotConfigBuilder`].
|
||||
pub fn new() -> Self {
|
||||
let inner = SubstrateConfigBuilder::new()
|
||||
.set_legacy_types(frame_decode::legacy_types::polkadot::relay_chain());
|
||||
let inner = SubstrateConfigBuilder::new();
|
||||
PolkadotConfigBuilder {
|
||||
use_historic_types: true,
|
||||
inner,
|
||||
}
|
||||
}
|
||||
|
||||
PolkadotConfigBuilder(inner)
|
||||
/// Use historic types. These are enabled by default, but can be disabled to avoid
|
||||
/// loading them in if they are not needed (ie you do not need to access any block
|
||||
/// using a runtime which has V14 metadata).
|
||||
pub fn use_historic_types(mut self, b: bool) -> Self {
|
||||
self.use_historic_types = b;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the metadata to be used for decoding blocks at the given spec versions.
|
||||
@@ -37,7 +49,7 @@ impl PolkadotConfigBuilder {
|
||||
mut self,
|
||||
ranges: impl IntoIterator<Item = (u32, ArcMetadata)>,
|
||||
) -> Self {
|
||||
self = Self(self.0.set_metadata_for_spec_versions(ranges));
|
||||
self.inner = self.inner.set_metadata_for_spec_versions(ranges);
|
||||
self
|
||||
}
|
||||
|
||||
@@ -47,17 +59,25 @@ impl PolkadotConfigBuilder {
|
||||
mut self,
|
||||
ranges: impl IntoIterator<Item = SpecVersionForRange>,
|
||||
) -> Self {
|
||||
self = Self(self.0.set_spec_version_for_block_ranges(ranges));
|
||||
self.inner = self.inner.set_spec_version_for_block_ranges(ranges);
|
||||
self
|
||||
}
|
||||
|
||||
/// Construct the [`PolkadotConfig`] from this builder.
|
||||
pub fn build(self) -> PolkadotConfig {
|
||||
PolkadotConfig(self.0.build())
|
||||
pub fn build(mut self) -> PolkadotConfig {
|
||||
if self.use_historic_types {
|
||||
self.inner = self
|
||||
.inner
|
||||
.set_legacy_types(frame_decode::legacy_types::polkadot::relay_chain());
|
||||
}
|
||||
|
||||
PolkadotConfig(self.inner.build())
|
||||
}
|
||||
}
|
||||
|
||||
/// Configuration that's suitable for the Polkadot Relay Chain.
|
||||
/// Configuration for the Polkadot Relay Chain. This should not be used to connect
|
||||
/// to any other chain; instead use [`crate::config::SubstrateConfig`] and configure
|
||||
/// that as needed to support the chain you're connecting to.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct PolkadotConfig(SubstrateConfig);
|
||||
|
||||
@@ -69,7 +89,7 @@ impl PolkadotConfig {
|
||||
|
||||
/// Build a new [`PolkadotConfig`].
|
||||
pub fn builder() -> PolkadotConfigBuilder {
|
||||
PolkadotConfigBuilder(SubstrateConfig::builder())
|
||||
PolkadotConfigBuilder::new()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+13
-1
@@ -1,3 +1,15 @@
|
||||
//! This module exposes [`ConstantsClient`], which has methods for working with constants. It's
|
||||
//! created by calling [`crate::client::ClientAtBlock::constants()`].
|
||||
//!
|
||||
//! ```rust,no_run
|
||||
//! pub use subxt::{OnlineClient, PolkadotConfig};
|
||||
//!
|
||||
//! let client = OnlineClient::new().await?;
|
||||
//! let at_block = client.at_current_block().await?;
|
||||
//!
|
||||
//! let constants = at_block.constants();
|
||||
//! ```
|
||||
|
||||
mod address;
|
||||
|
||||
use crate::client::OfflineClientAtBlockT;
|
||||
@@ -9,7 +21,7 @@ use std::marker::PhantomData;
|
||||
|
||||
pub use address::{Address, DynamicAddress, StaticAddress, dynamic};
|
||||
|
||||
/// A client for working with storage entries.
|
||||
/// A client for working with constants. See [the module docs](crate::constants) for more.
|
||||
#[derive(Clone)]
|
||||
pub struct ConstantsClient<'atblock, T, Client> {
|
||||
client: &'atblock Client,
|
||||
|
||||
@@ -1,3 +1,15 @@
|
||||
//! This module exposes [`CustomValuesClient`], which has methods for working with custom values.
|
||||
//! It's created by calling [`crate::client::ClientAtBlock::custom_values()`].
|
||||
//!
|
||||
//! ```rust,no_run
|
||||
//! pub use subxt::{OnlineClient, PolkadotConfig};
|
||||
//!
|
||||
//! let client = OnlineClient::new().await?;
|
||||
//! let at_block = client.at_current_block().await?;
|
||||
//!
|
||||
//! let custom_values = at_block.custom_values();
|
||||
//! ```
|
||||
|
||||
mod address;
|
||||
|
||||
use crate::client::OfflineClientAtBlockT;
|
||||
@@ -10,7 +22,7 @@ use scale_decode::IntoVisitor;
|
||||
|
||||
pub use address::{Address, DynamicAddress, StaticAddress, dynamic};
|
||||
|
||||
/// A client for accessing custom values stored in the metadata.
|
||||
/// A client for working with custom values. See [the module docs](crate::custom_values) for more.
|
||||
#[derive_where(Clone; Client)]
|
||||
pub struct CustomValuesClient<'atblock, T, Client> {
|
||||
client: &'atblock Client,
|
||||
|
||||
+13
-1
@@ -1,3 +1,15 @@
|
||||
//! This module exposes [`EventsClient`], which has methods for working with eventts.
|
||||
//! It's created by calling [`crate::client::ClientAtBlock::events()`].
|
||||
//!
|
||||
//! ```rust,no_run
|
||||
//! pub use subxt::{OnlineClient, PolkadotConfig};
|
||||
//!
|
||||
//! let client = OnlineClient::new().await?;
|
||||
//! let at_block = client.at_current_block().await?;
|
||||
//!
|
||||
//! let events = at_block.events();
|
||||
//! ```
|
||||
|
||||
mod decode_as_event;
|
||||
|
||||
use crate::backend::BackendExt;
|
||||
@@ -12,7 +24,7 @@ use std::sync::Arc;
|
||||
|
||||
pub use decode_as_event::DecodeAsEvent;
|
||||
|
||||
/// A client for working with events.
|
||||
/// A client for working with events. See [the module docs](crate::events) for more.
|
||||
pub struct EventsClient<'atblock, T, Client> {
|
||||
client: &'atblock Client,
|
||||
marker: PhantomData<T>,
|
||||
|
||||
+13
-1
@@ -1,3 +1,15 @@
|
||||
//! This module exposes [`ExtrinsicsClient`], which has methods for working with extrinsics.
|
||||
//! It's created by calling [`crate::client::ClientAtBlock::extrinsics()`].
|
||||
//!
|
||||
//! ```rust,no_run
|
||||
//! pub use subxt::{OnlineClient, PolkadotConfig};
|
||||
//!
|
||||
//! let client = OnlineClient::new().await?;
|
||||
//! let at_block = client.at_current_block().await?;
|
||||
//!
|
||||
//! let extrinsics = at_block.extrinsics();
|
||||
//! ```
|
||||
|
||||
mod decode_as_extrinsic;
|
||||
mod extrinsic_transaction_extensions;
|
||||
|
||||
@@ -18,7 +30,7 @@ pub use extrinsic_transaction_extensions::{
|
||||
ExtrinsicTransactionExtension, ExtrinsicTransactionExtensions,
|
||||
};
|
||||
|
||||
/// A client for working with extrinsics.
|
||||
/// A client for working with extrinsics. See [the module docs](crate::extrinsics) for more.
|
||||
pub struct ExtrinsicsClient<'atblock, T, Client> {
|
||||
client: &'atblock Client,
|
||||
marker: PhantomData<T>,
|
||||
|
||||
+2
-5
@@ -2,13 +2,10 @@
|
||||
// This file is dual-licensed as Apache-2.0 or GPL-3.0.
|
||||
// see LICENSE for license details.
|
||||
|
||||
// TODO: REMOVE BEFORE MERGING.
|
||||
#![allow(missing_docs)]
|
||||
|
||||
//! Subxt is a library for interacting with Substrate based nodes. Using it looks something like this:
|
||||
//!
|
||||
//! ```rust,ignore
|
||||
#![doc = include_str!("../examples/transactions_basic.rs")]
|
||||
#![doc = include_str!("../examples/submit_transaction.rs")]
|
||||
//! ```
|
||||
//!
|
||||
//! Take a look at [the Subxt guide](book) to learn more about how to use Subxt.
|
||||
@@ -76,8 +73,8 @@ pub use subxt_lightclient as lightclient;
|
||||
/// Re-export external crates that are made use of in the subxt API.
|
||||
pub mod ext {
|
||||
pub use codec;
|
||||
pub use frame_decode;
|
||||
pub use frame_metadata;
|
||||
pub use futures;
|
||||
pub use scale_bits;
|
||||
pub use scale_decode;
|
||||
pub use scale_encode;
|
||||
|
||||
@@ -2,6 +2,18 @@
|
||||
// This file is dual-licensed as Apache-2.0 or GPL-3.0.
|
||||
// see LICENSE for license details.
|
||||
|
||||
//! This module exposes [`RuntimeApisClient`], which has methods for calling Runtime APIs.
|
||||
//! It's created by calling [`crate::client::ClientAtBlock::runtime_apis()`].
|
||||
//!
|
||||
//! ```rust,no_run
|
||||
//! pub use subxt::{OnlineClient, PolkadotConfig};
|
||||
//!
|
||||
//! let client = OnlineClient::new().await?;
|
||||
//! let at_block = client.at_current_block().await?;
|
||||
//!
|
||||
//! let runtime_apis = at_block.runtime_apis();
|
||||
//! ```
|
||||
|
||||
mod payload;
|
||||
|
||||
use crate::client::{OfflineClientAtBlockT, OnlineClientAtBlockT};
|
||||
@@ -13,7 +25,7 @@ use std::marker::PhantomData;
|
||||
|
||||
pub use payload::{DynamicPayload, Payload, StaticPayload, dynamic};
|
||||
|
||||
/// Execute runtime API calls.
|
||||
/// A client for working with Runtime APIs. See [the module docs](crate::runtime_apis) for more.
|
||||
#[derive_where(Clone; Client)]
|
||||
pub struct RuntimeApisClient<'atblock, T: Config, Client> {
|
||||
client: &'atblock Client,
|
||||
|
||||
+13
-1
@@ -1,3 +1,15 @@
|
||||
//! This module exposes [`StorageClient`], which has methods for fetching and iterating over
|
||||
//! storage entries. It's created by calling [`crate::client::ClientAtBlock::storage()`].
|
||||
//!
|
||||
//! ```rust,no_run
|
||||
//! pub use subxt::{OnlineClient, PolkadotConfig};
|
||||
//!
|
||||
//! let client = OnlineClient::new().await?;
|
||||
//! let at_block = client.at_current_block().await?;
|
||||
//!
|
||||
//! let storage = at_block.storage();
|
||||
//! ```
|
||||
|
||||
mod address;
|
||||
mod prefix_of;
|
||||
mod storage_entry;
|
||||
@@ -21,7 +33,7 @@ pub use storage_key::{StorageKey, StorageKeyPart};
|
||||
pub use storage_key_value::StorageKeyValue;
|
||||
pub use storage_value::StorageValue;
|
||||
|
||||
/// A client for working with storage entries.
|
||||
/// A client for working with storage entries. See [the module docs](crate::storage) for more.
|
||||
#[derive(Clone)]
|
||||
pub struct StorageClient<'atblock, T, Client> {
|
||||
client: &'atblock Client,
|
||||
|
||||
@@ -1,14 +1,17 @@
|
||||
use crate::backend::BackendExt;
|
||||
use crate::backend::{BackendExt, StorageResponse, StreamOf};
|
||||
use crate::client::{OfflineClientAtBlockT, OnlineClientAtBlockT};
|
||||
use crate::config::Config;
|
||||
use crate::error::StorageError;
|
||||
use crate::error::{BackendError, StorageError};
|
||||
use crate::storage::address::Address;
|
||||
use crate::storage::{PrefixOf, StorageKeyValue, StorageValue};
|
||||
use crate::utils::YesMaybe;
|
||||
use core::marker::PhantomData;
|
||||
use frame_decode::storage::{IntoEncodableValues, StorageInfo, StorageTypeInfo};
|
||||
use futures::StreamExt;
|
||||
use futures::{Stream, StreamExt};
|
||||
use scale_info::PortableRegistry;
|
||||
use std::pin::Pin;
|
||||
use std::sync::Arc;
|
||||
use std::task::Poll;
|
||||
|
||||
/// This represents a single storage entry (be it a plain value or map)
|
||||
/// and the operations that can be performed on it.
|
||||
@@ -99,6 +102,14 @@ where
|
||||
|
||||
/// This returns a full key to a single value in this storage entry.
|
||||
pub fn fetch_key(&self, key_parts: Addr::KeyParts) -> Result<Vec<u8>, StorageError> {
|
||||
let num_keys = self.inner.info.keys.len();
|
||||
if key_parts.num_encodable_values() != num_keys {
|
||||
return Err(StorageError::WrongNumberOfKeyPartsProvidedForFetching {
|
||||
expected: num_keys,
|
||||
got: key_parts.num_encodable_values(),
|
||||
});
|
||||
}
|
||||
|
||||
self.key_from_any_parts(key_parts)
|
||||
}
|
||||
|
||||
@@ -128,24 +139,14 @@ where
|
||||
&self,
|
||||
key_parts: impl IntoEncodableValues,
|
||||
) -> Result<Vec<u8>, StorageError> {
|
||||
let num_keys = self.inner.info.keys.len();
|
||||
if key_parts.num_encodable_values() != num_keys {
|
||||
return Err(StorageError::WrongNumberOfKeyPartsProvidedForFetching {
|
||||
expected: num_keys,
|
||||
got: key_parts.num_encodable_values(),
|
||||
});
|
||||
}
|
||||
|
||||
let key = frame_decode::storage::encode_storage_key_with_info(
|
||||
frame_decode::storage::encode_storage_key_with_info(
|
||||
self.pallet_name(),
|
||||
self.entry_name(),
|
||||
key_parts,
|
||||
&self.inner.info,
|
||||
self.inner.client.metadata_ref().types(),
|
||||
)
|
||||
.map_err(StorageError::StorageKeyEncodeError)?;
|
||||
|
||||
Ok(key)
|
||||
.map_err(StorageError::StorageKeyEncodeError)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -227,11 +228,15 @@ where
|
||||
pub async fn iter<KeyParts: PrefixOf<Addr::KeyParts>>(
|
||||
&self,
|
||||
key_parts: KeyParts,
|
||||
) -> Result<
|
||||
impl futures::Stream<Item = Result<StorageKeyValue<'atblock, Addr>, StorageError>>
|
||||
+ use<'atblock, Addr, Client, T, KeyParts>,
|
||||
StorageError,
|
||||
> {
|
||||
) -> Result<StorageEntries<'atblock, Addr>, StorageError> {
|
||||
let num_keys = self.inner.info.keys.len();
|
||||
if key_parts.num_encodable_values() >= num_keys {
|
||||
return Err(StorageError::WrongNumberOfKeyPartsProvidedForIterating {
|
||||
max_expected: num_keys - 1,
|
||||
got: key_parts.num_encodable_values(),
|
||||
});
|
||||
}
|
||||
|
||||
let info = self.inner.info.clone();
|
||||
let types = self.inner.client.metadata_ref().types();
|
||||
let key_bytes = self.key_from_any_parts(key_parts)?;
|
||||
@@ -243,20 +248,66 @@ where
|
||||
.backend()
|
||||
.storage_fetch_descendant_values(key_bytes, block_hash)
|
||||
.await
|
||||
.map_err(StorageError::CannotIterateValues)?
|
||||
.map(move |kv| {
|
||||
let kv = match kv {
|
||||
Ok(kv) => kv,
|
||||
Err(e) => return Err(StorageError::StreamFailure(e)),
|
||||
};
|
||||
Ok(StorageKeyValue::new(
|
||||
info.clone(),
|
||||
types,
|
||||
kv.key.into(),
|
||||
kv.value,
|
||||
))
|
||||
});
|
||||
.map_err(StorageError::CannotIterateValues)?;
|
||||
|
||||
Ok(Box::pin(stream))
|
||||
// .map(move |kv| {
|
||||
// let kv = match kv {
|
||||
// Ok(kv) => kv,
|
||||
// Err(e) => return Err(StorageError::StreamFailure(e)),
|
||||
// };
|
||||
// Ok(StorageKeyValue::new(
|
||||
// info.clone(),
|
||||
// types,
|
||||
// kv.key.into(),
|
||||
// kv.value,
|
||||
// ))
|
||||
// });
|
||||
|
||||
Ok(StorageEntries {
|
||||
info,
|
||||
stream,
|
||||
types,
|
||||
marker: PhantomData,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// A stream of storage entries.
|
||||
pub struct StorageEntries<'atblock, Addr> {
|
||||
// The raw underlying stream:
|
||||
stream: StreamOf<Result<StorageResponse, BackendError>>,
|
||||
// things we need to convert this into what we want:
|
||||
info: Arc<StorageInfo<'atblock, u32>>,
|
||||
types: &'atblock PortableRegistry,
|
||||
marker: PhantomData<Addr>,
|
||||
}
|
||||
|
||||
impl<'atblock, Addr: Address> StorageEntries<'atblock, Addr> {
|
||||
/// Get the next storage entry. This is an alias for `futures::StreamExt::next(self)`.
|
||||
pub async fn next(&mut self) -> Option<Result<StorageKeyValue<'atblock, Addr>, StorageError>> {
|
||||
StreamExt::next(self).await
|
||||
}
|
||||
}
|
||||
|
||||
impl<'atblock, Addr> std::marker::Unpin for StorageEntries<'atblock, Addr> {}
|
||||
impl<'atblock, Addr: Address> Stream for StorageEntries<'atblock, Addr> {
|
||||
type Item = Result<StorageKeyValue<'atblock, Addr>, StorageError>;
|
||||
|
||||
fn poll_next(
|
||||
mut self: Pin<&mut Self>,
|
||||
cx: &mut std::task::Context<'_>,
|
||||
) -> Poll<Option<Self::Item>> {
|
||||
let val = match futures::ready!(self.stream.poll_next_unpin(cx)) {
|
||||
Some(Ok(val)) => val,
|
||||
Some(Err(e)) => return Poll::Ready(Some(Err(StorageError::StreamFailure(e)))),
|
||||
None => return Poll::Ready(None),
|
||||
};
|
||||
|
||||
Poll::Ready(Some(Ok(StorageKeyValue::new(
|
||||
self.info.clone(),
|
||||
self.types,
|
||||
val.key.into(),
|
||||
val.value,
|
||||
))))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,16 @@
|
||||
//! This module exposes [`TransactionsClient`], which has methods for constructing and submitting
|
||||
//! transactions. It's created by calling [`crate::client::ClientAtBlock::transactions()`], or
|
||||
//! [`crate::client::ClientAtBlock::tx()`] for short.
|
||||
//!
|
||||
//! ```rust,no_run
|
||||
//! pub use subxt::{OnlineClient, PolkadotConfig};
|
||||
//!
|
||||
//! let client = OnlineClient::new().await?;
|
||||
//! let at_block = client.at_current_block().await?;
|
||||
//!
|
||||
//! let transactions = at_block.transactions();
|
||||
//! ```
|
||||
|
||||
mod account_nonce;
|
||||
mod default_params;
|
||||
mod payload;
|
||||
@@ -26,7 +39,7 @@ pub use validation_result::{
|
||||
TransactionInvalid, TransactionUnknown, TransactionValid, ValidationResult,
|
||||
};
|
||||
|
||||
/// A client for working with transactions.
|
||||
/// A client for working with transactions. See [the module docs](crate::transactions) for more.
|
||||
#[derive(Clone)]
|
||||
pub struct TransactionsClient<'atblock, T, Client> {
|
||||
client: &'atblock Client,
|
||||
@@ -257,7 +270,7 @@ impl<'atblock, T: Config, Client: OfflineClientAtBlockT<T>>
|
||||
}
|
||||
|
||||
// Create a V4 "signed" or a V5 "general" transaction.
|
||||
pub fn create_signable_at_version<Call>(
|
||||
fn create_signable_at_version<Call>(
|
||||
&self,
|
||||
call: &Call,
|
||||
params: <T::ExtrinsicParams as ExtrinsicParams<T>>::Params,
|
||||
|
||||
@@ -11,6 +11,11 @@ use futures::{Stream, StreamExt};
|
||||
use std::pin::Pin;
|
||||
use std::task::{Context, Poll};
|
||||
|
||||
/// A stream representing the progress of some transaction. Events can be
|
||||
/// streamed and acted on using [`TransactionProgress::next()`], or the helper
|
||||
/// functions [`TransactionProgress::wait_for_finalized`] and
|
||||
/// [`TransactionProgress::wait_for_finalized_success`] can be used to wait
|
||||
/// for completion.
|
||||
#[derive(Debug)]
|
||||
pub struct TransactionProgress<'atblock, T: Config, C> {
|
||||
sub: Option<StreamOfResults<BackendTransactionStatus<HashFor<T>>>>,
|
||||
|
||||
@@ -10,8 +10,8 @@ use serde::{Deserialize, Serialize};
|
||||
use thiserror::Error as DeriveError;
|
||||
|
||||
#[derive(
|
||||
Copy,
|
||||
Clone,
|
||||
Copy,
|
||||
Eq,
|
||||
PartialEq,
|
||||
Ord,
|
||||
|
||||
@@ -2,6 +2,18 @@
|
||||
// This file is dual-licensed as Apache-2.0 or GPL-3.0.
|
||||
// see LICENSE for license details.
|
||||
|
||||
//! This module exposes [`ViewFunctionsClient`], which has methods for calling View Functions.
|
||||
//! It's created by calling [`crate::client::ClientAtBlock::view_functions()`].
|
||||
//!
|
||||
//! ```rust,no_run
|
||||
//! pub use subxt::{OnlineClient, PolkadotConfig};
|
||||
//!
|
||||
//! let client = OnlineClient::new().await?;
|
||||
//! let at_block = client.at_current_block().await?;
|
||||
//!
|
||||
//! let view_functions = at_block.view_functions();
|
||||
//! ```
|
||||
|
||||
mod payload;
|
||||
|
||||
use crate::client::{OfflineClientAtBlockT, OnlineClientAtBlockT};
|
||||
@@ -16,7 +28,7 @@ pub use payload::{DynamicPayload, Payload, StaticPayload, dynamic};
|
||||
/// The name of the Runtime API call which can execute
|
||||
const CALL_NAME: &str = "RuntimeViewFunction_execute_view_function";
|
||||
|
||||
/// Execute View Function calls.
|
||||
/// A client for working with View Functions. See [the module docs](crate::view_functions) for more.
|
||||
#[derive_where(Clone; Client)]
|
||||
pub struct ViewFunctionsClient<'atblock, T: Config, Client> {
|
||||
client: &'atblock Client,
|
||||
|
||||
@@ -23,6 +23,7 @@ use thiserror::Error as DeriveError;
|
||||
/// that type.
|
||||
#[derive(
|
||||
Clone,
|
||||
Copy,
|
||||
Eq,
|
||||
PartialEq,
|
||||
Ord,
|
||||
|
||||
Reference in New Issue
Block a user