From e91d0c7b37da5deee10892712b55e7a65833f5f9 Mon Sep 17 00:00:00 2001 From: James Wilson Date: Mon, 2 Oct 2023 23:10:34 +0100 Subject: [PATCH] allow getting account nonce at arbitrary blocks, too (#1182) --- subxt/examples/runtime_apis_dynamic.rs | 3 -- subxt/src/blocks/block_types.rs | 38 +++++++++++++++++++++++++- subxt/src/blocks/mod.rs | 3 ++ subxt/src/tx/tx_client.rs | 21 +------------- 4 files changed, 41 insertions(+), 24 deletions(-) diff --git a/subxt/examples/runtime_apis_dynamic.rs b/subxt/examples/runtime_apis_dynamic.rs index f7e8a894d7..2a02118abd 100644 --- a/subxt/examples/runtime_apis_dynamic.rs +++ b/subxt/examples/runtime_apis_dynamic.rs @@ -2,9 +2,6 @@ use subxt::dynamic::Value; use subxt::{config::PolkadotConfig, OnlineClient}; use subxt_signer::sr25519::dev; -#[subxt::subxt(runtime_metadata_path = "../artifacts/polkadot_metadata_small.scale")] -pub mod polkadot {} - #[tokio::main] async fn main() -> Result<(), Box> { // Create a client to use: diff --git a/subxt/src/blocks/block_types.rs b/subxt/src/blocks/block_types.rs index 25e97d6457..2b160ea2d2 100644 --- a/subxt/src/blocks/block_types.rs +++ b/subxt/src/blocks/block_types.rs @@ -7,12 +7,13 @@ use crate::{ blocks::{extrinsic_types::ExtrinsicPartTypeIds, Extrinsics}, client::{OfflineClientT, OnlineClientT}, config::{Config, Header}, - error::{BlockError, Error}, + error::{BlockError, DecodeError, Error}, events, runtime_api::RuntimeApi, storage::Storage, }; +use codec::{Decode, Encode}; use futures::lock::Mutex as AsyncMutex; use std::sync::Arc; @@ -102,6 +103,11 @@ where pub async fn runtime_api(&self) -> Result, Error> { Ok(RuntimeApi::new(self.client.clone(), self.block_ref.clone())) } + + /// Get the account nonce for a given account ID at this block. + pub async fn account_nonce(&self, account_id: &T::AccountId) -> Result { + get_account_nonce(&self.client, account_id, self.hash()).await + } } // Return Events from the cache, or fetch from the node if needed. @@ -129,3 +135,33 @@ where Ok(events) } + +// Return the account nonce at some block hash for an account ID. +pub(crate) async fn get_account_nonce( + client: &C, + account_id: &T::AccountId, + block_hash: T::Hash, +) -> Result +where + C: OnlineClientT, + T: Config, +{ + let account_nonce_bytes = client + .backend() + .call( + "AccountNonceApi_account_nonce", + Some(&account_id.encode()), + block_hash, + ) + .await?; + + // custom decoding from a u16/u32/u64 into a u64, based on the number of bytes we got back. + let cursor = &mut &account_nonce_bytes[..]; + let account_nonce: u64 = match account_nonce_bytes.len() { + 2 => u16::decode(cursor)?.into(), + 4 => u32::decode(cursor)?.into(), + 8 => u64::decode(cursor)?, + _ => return Err(Error::Decode(DecodeError::custom_string(format!("state call AccountNonceApi_account_nonce returned an unexpected number of bytes: {} (expected 2, 4 or 8)", account_nonce_bytes.len())))) + }; + Ok(account_nonce) +} diff --git a/subxt/src/blocks/mod.rs b/subxt/src/blocks/mod.rs index da99fe22d5..fd06594e60 100644 --- a/subxt/src/blocks/mod.rs +++ b/subxt/src/blocks/mod.rs @@ -14,3 +14,6 @@ pub use crate::backend::BlockRef; pub use block_types::Block; pub use blocks_client::BlocksClient; pub use extrinsic_types::{ExtrinsicDetails, ExtrinsicEvents, Extrinsics, StaticExtrinsic}; + +// We get account nonce info in tx_client, too, so re-use the logic: +pub(crate) use block_types::get_account_nonce; diff --git a/subxt/src/tx/tx_client.rs b/subxt/src/tx/tx_client.rs index ff4e3416e8..5b5df91106 100644 --- a/subxt/src/tx/tx_client.rs +++ b/subxt/src/tx/tx_client.rs @@ -4,7 +4,6 @@ use std::borrow::Cow; -use crate::error::DecodeError; use crate::{ backend::{BackendExt, BlockRef, TransactionStatus}, client::{OfflineClientT, OnlineClientT}, @@ -170,25 +169,7 @@ where /// Get the account nonce for a given account ID. pub async fn account_nonce(&self, account_id: &T::AccountId) -> Result { let block_ref = self.client.backend().latest_finalized_block_ref().await?; - let account_nonce_bytes = self - .client - .backend() - .call( - "AccountNonceApi_account_nonce", - Some(&account_id.encode()), - block_ref.hash(), - ) - .await?; - - // custom decoding from a u16/u32/u64 into a u64, based on the number of bytes we got back. - let cursor = &mut &account_nonce_bytes[..]; - let account_nonce: u64 = match account_nonce_bytes.len() { - 2 => u16::decode(cursor)?.into(), - 4 => u32::decode(cursor)?.into(), - 8 => u64::decode(cursor)?, - _ => return Err(Error::Decode(DecodeError::custom_string(format!("state call AccountNonceApi_account_nonce returned an unexpected number of bytes: {} (expected 2, 4 or 8)", account_nonce_bytes.len())))) - }; - Ok(account_nonce) + crate::blocks::get_account_nonce(&self.client, account_id, block_ref.hash()).await } /// Creates a partial signed extrinsic, without submitting it.