diff --git a/core/src/blocks/extrinsics.rs b/core/src/blocks/extrinsics.rs index 0f02e0409b..3111477e63 100644 --- a/core/src/blocks/extrinsics.rs +++ b/core/src/blocks/extrinsics.rs @@ -5,7 +5,7 @@ use super::BlockError; use crate::blocks::extrinsic_transaction_extensions::ExtrinsicTransactionExtensions; use crate::{ - config::{Config, Hasher}, + config::{Config, HashFor, Hasher}, error::{Error, MetadataError}, Metadata, }; @@ -22,6 +22,7 @@ pub use crate::blocks::StaticExtrinsic; pub struct Extrinsics { extrinsics: Vec, Vec)>>, metadata: Metadata, + hasher: T::Hasher, _marker: core::marker::PhantomData, } @@ -30,6 +31,7 @@ impl Extrinsics { /// each extrinsic hash (in the form of bytes) and some metadata that /// we'll use to decode them. pub fn decode_from(extrinsics: Vec>, metadata: Metadata) -> Result { + let hasher = T::Hasher::new(&metadata); let extrinsics = extrinsics .into_iter() .enumerate() @@ -63,6 +65,7 @@ impl Extrinsics { Ok(Self { extrinsics, + hasher, metadata, _marker: core::marker::PhantomData, }) @@ -85,10 +88,16 @@ impl Extrinsics { pub fn iter(&self) -> impl Iterator> + Send + Sync + 'static { let extrinsics = self.extrinsics.clone(); let num_extrinsics = self.extrinsics.len(); + let hasher = self.hasher; let metadata = self.metadata.clone(); (0..num_extrinsics).map(move |index| { - ExtrinsicDetails::new(index as u32, extrinsics[index].clone(), metadata.clone()) + ExtrinsicDetails::new( + index as u32, + extrinsics[index].clone(), + hasher, + metadata.clone(), + ) }) } @@ -133,6 +142,8 @@ pub struct ExtrinsicDetails { index: u32, /// Extrinsic bytes and decode info. ext: Arc<(Extrinsic<'static, u32>, Vec)>, + /// Hash the extrinsic if we want. + hasher: T::Hasher, /// Subxt metadata to fetch the extrinsic metadata. metadata: Metadata, _marker: core::marker::PhantomData, @@ -147,20 +158,22 @@ where pub fn new( index: u32, ext: Arc<(Extrinsic<'static, u32>, Vec)>, + hasher: T::Hasher, metadata: Metadata, ) -> ExtrinsicDetails { ExtrinsicDetails { index, ext, + hasher, metadata, _marker: core::marker::PhantomData, } } /// Calculate and return the hash of the extrinsic, based on the configured hasher. - pub fn hash(&self) -> T::Hash { + pub fn hash(&self) -> HashFor { // Use hash(), not hash_of(), because we don't want to double encode the bytes. - T::Hasher::hash(self.bytes()) + self.hasher.hash(self.bytes()) } /// Is the extrinsic signed? @@ -532,6 +545,7 @@ mod tests { #[test] fn tx_hashes_line_up() { let metadata = metadata(); + let hasher = ::Hasher::new(&metadata); let tx = crate::dynamic::tx( "Test", @@ -559,7 +573,11 @@ mod tests { // Both of these types should produce the same bytes. assert_eq!(tx_encoded.encoded(), extrinsic.bytes(), "bytes should eq"); // Both of these types should produce the same hash. - assert_eq!(tx_encoded.hash(), extrinsic.hash(), "hashes should eq"); + assert_eq!( + tx_encoded.hash_with(hasher), + extrinsic.hash(), + "hashes should eq" + ); } #[test] diff --git a/core/src/client.rs b/core/src/client.rs index db5e4fbebd..e7396c883a 100644 --- a/core/src/client.rs +++ b/core/src/client.rs @@ -4,7 +4,10 @@ //! A couple of client types that we use elsewhere. -use crate::{config::Config, metadata::Metadata}; +use crate::{ + config::{Config, HashFor}, + metadata::Metadata, +}; use derive_where::derive_where; /// This provides access to some relevant client state in transaction extensions, @@ -12,7 +15,7 @@ use derive_where::derive_where; #[derive_where(Clone, Debug)] pub struct ClientState { /// Genesis hash. - pub genesis_hash: C::Hash, + pub genesis_hash: HashFor, /// Runtime version. pub runtime_version: RuntimeVersion, /// Metadata. diff --git a/core/src/config/extrinsic_params.rs b/core/src/config/extrinsic_params.rs index 45f1c17489..bd3168631c 100644 --- a/core/src/config/extrinsic_params.rs +++ b/core/src/config/extrinsic_params.rs @@ -7,7 +7,11 @@ //! [`crate::config::DefaultExtrinsicParams`] provides a general-purpose //! implementation of this that will work in many cases. -use crate::{client::ClientState, error::ExtrinsicParamsError, Config}; +use crate::{ + client::ClientState, + config::{Config, HashFor}, + error::ExtrinsicParamsError, +}; use alloc::vec::Vec; use core::any::Any; @@ -74,7 +78,7 @@ pub trait Params { /// Set the account nonce. fn inject_account_nonce(&mut self, _nonce: u64) {} /// Set the current block. - fn inject_block(&mut self, _number: u64, _hash: T::Hash) {} + fn inject_block(&mut self, _number: u64, _hash: HashFor) {} } impl Params for () {} @@ -85,7 +89,8 @@ macro_rules! impl_tuples { fn inject_account_nonce(&mut self, nonce: u64) { $(self.$index.inject_account_nonce(nonce);)+ } - fn inject_block(&mut self, number: u64, hash: Conf::Hash) { + + fn inject_block(&mut self, number: u64, hash: HashFor) { $(self.$index.inject_block(number, hash);)+ } } diff --git a/core/src/config/mod.rs b/core/src/config/mod.rs index 2c0187365e..4a13a4b855 100644 --- a/core/src/config/mod.rs +++ b/core/src/config/mod.rs @@ -20,6 +20,7 @@ use core::fmt::Debug; use scale_decode::DecodeAsType; use scale_encode::EncodeAsType; use serde::{de::DeserializeOwned, Serialize}; +use subxt_metadata::Metadata; pub use default_extrinsic_params::{DefaultExtrinsicParams, DefaultExtrinsicParamsBuilder}; pub use extrinsic_params::{ExtrinsicParams, ExtrinsicParamsEncoder}; @@ -33,9 +34,6 @@ pub use transaction_extensions::TransactionExtension; // And we want the compiler to infer `Send` and `Sync` OK for things which have `T: Config` // rather than having to `unsafe impl` them ourselves. pub trait Config: Sized + Send + Sync + 'static { - /// The output of the `Hasher` function. - type Hash: BlockHash; - /// The account ID type. type AccountId: Debug + Clone + Encode + Decode + Serialize + Send; @@ -46,7 +44,7 @@ pub trait Config: Sized + Send + Sync + 'static { type Signature: Debug + Clone + Encode + Decode + Send; /// The hashing system (algorithm) being used in the runtime (e.g. Blake2). - type Hasher: Debug + Hasher; + type Hasher: Debug + Clone + Copy + Hasher + Send + Sync; /// The block header. type Header: Debug + Header + Sync + Send + DeserializeOwned; @@ -58,11 +56,14 @@ pub trait Config: Sized + Send + Sync + 'static { type AssetId: Debug + Clone + Encode + DecodeAsType + EncodeAsType + Send; } +/// Given some [`Config`], this returns the type of hash used. +pub type HashFor = <::Hasher as Hasher>::Output; + /// given some [`Config`], this return the other params needed for its `ExtrinsicParams`. pub type ParamsFor = <::ExtrinsicParams as ExtrinsicParams>::Params; /// Block hashes must conform to a bunch of things to be used in Subxt. -pub trait BlockHash: +pub trait Hash: Debug + Copy + Send @@ -77,7 +78,7 @@ pub trait BlockHash: + core::hash::Hash { } -impl BlockHash for T where +impl Hash for T where T: Debug + Copy + Send @@ -97,15 +98,18 @@ impl BlockHash for T where /// and extrinsics. pub trait Hasher { /// The type given back from the hash operation - type Output; + type Output: Hash; + + /// Construct a new hasher. + fn new(metadata: &Metadata) -> Self; /// Hash some bytes to the given output type. - fn hash(s: &[u8]) -> Self::Output; + fn hash(&self, s: &[u8]) -> Self::Output; /// Hash some SCALE encodable type to the given output type. - fn hash_of(s: &S) -> Self::Output { + fn hash_of(&self, s: &S) -> Self::Output { let out = s.encode(); - Self::hash(&out) + self.hash(&out) } } @@ -120,7 +124,7 @@ pub trait Header: Sized + Encode + Decode { fn number(&self) -> Self::Number; /// Hash this header. - fn hash(&self) -> ::Output { - Self::Hasher::hash_of(self) + fn hash_with(&self, hasher: Self::Hasher) -> ::Output { + hasher.hash_of(self) } } diff --git a/core/src/config/polkadot.rs b/core/src/config/polkadot.rs index 9875c233f7..1996d9b756 100644 --- a/core/src/config/polkadot.rs +++ b/core/src/config/polkadot.rs @@ -17,7 +17,6 @@ pub use primitive_types::{H256, U256}; pub enum PolkadotConfig {} impl Config for PolkadotConfig { - type Hash = ::Hash; type AccountId = ::AccountId; type Signature = ::Signature; type Hasher = ::Hasher; diff --git a/core/src/config/substrate.rs b/core/src/config/substrate.rs index 1d3a904eba..4695e97303 100644 --- a/core/src/config/substrate.rs +++ b/core/src/config/substrate.rs @@ -11,6 +11,7 @@ use alloc::vec::Vec; use codec::{Decode, Encode}; pub use primitive_types::{H256, U256}; use serde::{Deserialize, Serialize}; +use subxt_metadata::Metadata; /// Default set of commonly used types by Substrate runtimes. // Note: We only use this at the type level, so it should be impossible to @@ -21,12 +22,11 @@ use serde::{Deserialize, Serialize}; pub enum SubstrateConfig {} impl Config for SubstrateConfig { - type Hash = H256; type AccountId = AccountId32; type Address = MultiAddress; type Signature = MultiSignature; - type Hasher = BlakeTwo256; - type Header = SubstrateHeader; + type Hasher = DynamicHasher256; + type Header = SubstrateHeader; type ExtrinsicParams = SubstrateExtrinsicParams; type AssetId = u32; } @@ -39,17 +39,73 @@ pub type SubstrateExtrinsicParams = DefaultExtrinsicParams; /// This is what you provide to methods like `sign_and_submit()`. pub type SubstrateExtrinsicParamsBuilder = DefaultExtrinsicParamsBuilder; -/// A type that can hash values using the blaks2_256 algorithm. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Encode)] +/// A hasher (ie implements [`Hasher`]) which hashes values using the blaks2_256 algorithm. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct BlakeTwo256; impl Hasher for BlakeTwo256 { type Output = H256; - fn hash(s: &[u8]) -> Self::Output { + + fn new(_metadata: &Metadata) -> Self { + Self + } + + fn hash(&self, s: &[u8]) -> Self::Output { sp_crypto_hashing::blake2_256(s).into() } } +/// A hasher (ie implements [`Hasher`]) which inspects the runtime metadata to decide how to +/// hash types, falling back to blake2_256 if the hasher information is not available. +/// +/// Currently this hasher supports only `BlakeTwo256` and `Keccak256` hashing methods. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct DynamicHasher256(HashType); + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +enum HashType { + // Most chains use this: + BlakeTwo256, + // Chains like Hyperbridge use this (tends to be eth compatible chains) + Keccak256, + // If we don't have V16 metadata, we'll emit this and default to BlakeTwo256. + Unknown, +} + +impl Hasher for DynamicHasher256 { + type Output = H256; + + fn new(metadata: &Metadata) -> Self { + // Determine the Hash associated type used for the current chain, if possible. + let Some(system_pallet) = metadata.pallet_by_name("System") else { + return Self(HashType::Unknown); + }; + let Some(hash_ty_id) = system_pallet.associated_type_id("Hashing") else { + return Self(HashType::Unknown); + }; + + let ty = metadata + .types() + .resolve(hash_ty_id) + .expect("Type information for 'Hashing' associated type should be in metadata"); + + let hash_type = match ty.path.ident().as_deref().unwrap_or("") { + "BlakeTwo256" => HashType::BlakeTwo256, + "Keccak256" => HashType::Keccak256, + _ => HashType::Unknown, + }; + + Self(hash_type) + } + + fn hash(&self, s: &[u8]) -> Self::Output { + match self.0 { + HashType::BlakeTwo256 | HashType::Unknown => sp_crypto_hashing::blake2_256(s).into(), + HashType::Keccak256 => sp_crypto_hashing::keccak_256(s).into(), + } + } +} + /// A generic Substrate header type, adapted from `sp_runtime::generic::Header`. /// The block number and hasher can be configured to adapt this for other nodes. #[derive(Encode, Decode, Debug, PartialEq, Eq, Clone, Serialize, Deserialize)] @@ -75,11 +131,12 @@ pub struct SubstrateHeader + TryFrom, H: Hasher> { impl Header for SubstrateHeader where N: Copy + Into + Into + TryFrom + Encode, - H: Hasher + Encode, + H: Hasher, SubstrateHeader: Encode + Decode, { type Number = N; type Hasher = H; + fn number(&self) -> Self::Number { self.number } diff --git a/core/src/config/transaction_extensions.rs b/core/src/config/transaction_extensions.rs index 9c73fbe633..1c0bded5dd 100644 --- a/core/src/config/transaction_extensions.rs +++ b/core/src/config/transaction_extensions.rs @@ -9,10 +9,10 @@ use super::extrinsic_params::ExtrinsicParams; use crate::client::ClientState; -use crate::config::{ExtrinsicParamsEncoder, Header}; +use crate::config::ExtrinsicParamsEncoder; +use crate::config::{Config, HashFor}; use crate::error::ExtrinsicParamsError; use crate::utils::{Era, Static}; -use crate::Config; use alloc::borrow::ToOwned; use alloc::boxed::Box; use alloc::vec::Vec; @@ -262,7 +262,7 @@ impl TransactionExtension for CheckTxVersion { } /// The [`CheckGenesis`] transaction extension. -pub struct CheckGenesis(T::Hash); +pub struct CheckGenesis(HashFor); impl ExtrinsicParams for CheckGenesis { type Params = (); @@ -288,7 +288,7 @@ impl TransactionExtension for CheckGenesis { /// The [`CheckMortality`] transaction extension. pub struct CheckMortality { params: CheckMortalityParamsInner, - genesis_hash: T::Hash, + genesis_hash: HashFor, } impl ExtrinsicParams for CheckMortality { @@ -352,7 +352,7 @@ enum CheckMortalityParamsInner { MortalFromBlock { for_n_blocks: u64, from_block_n: u64, - from_block_hash: T::Hash, + from_block_hash: HashFor, }, } @@ -368,23 +368,14 @@ impl CheckMortalityParams { pub fn mortal(for_n_blocks: u64) -> Self { Self(CheckMortalityParamsInner::MortalForBlocks(for_n_blocks)) } - /// Configure a transaction that will be mortal for the number of blocks given, - /// and from the block header provided. - pub fn mortal_from(for_n_blocks: u64, from_block: T::Header) -> Self { - Self(CheckMortalityParamsInner::MortalFromBlock { - for_n_blocks, - from_block_n: from_block.number().into(), - from_block_hash: from_block.hash(), - }) - } + /// Configure a transaction that will be mortal for the number of blocks given, /// and from the block details provided. Prefer to use [`CheckMortalityParams::mortal()`] - /// or [`CheckMortalityParams::mortal_from()`] which both avoid the block number and hash - /// from being misaligned. + /// where possible, which prevents the block number and hash from being misaligned. pub fn mortal_from_unchecked( for_n_blocks: u64, from_block_n: u64, - from_block_hash: T::Hash, + from_block_hash: HashFor, ) -> Self { Self(CheckMortalityParamsInner::MortalFromBlock { for_n_blocks, @@ -399,7 +390,7 @@ impl CheckMortalityParams { } impl Params for CheckMortalityParams { - fn inject_block(&mut self, from_block_n: u64, from_block_hash: ::Hash) { + fn inject_block(&mut self, from_block_n: u64, from_block_hash: HashFor) { match &self.0 { CheckMortalityParamsInner::MortalForBlocks(n) => { self.0 = CheckMortalityParamsInner::MortalFromBlock { diff --git a/core/src/events.rs b/core/src/events.rs index 8ca7913558..dea5c4e3dd 100644 --- a/core/src/events.rs +++ b/core/src/events.rs @@ -45,7 +45,11 @@ use derive_where::derive_where; use scale_decode::{DecodeAsFields, DecodeAsType}; use subxt_metadata::PalletMetadata; -use crate::{error::MetadataError, Config, Error, Metadata}; +use crate::{ + config::{Config, HashFor}, + error::MetadataError, + Error, Metadata, +}; /// Create a new [`Events`] instance from the given bytes. /// @@ -232,7 +236,7 @@ pub struct EventDetails { // end of everything (fields + topics) end_idx: usize, metadata: Metadata, - topics: Vec, + topics: Vec>, } impl EventDetails { @@ -281,7 +285,7 @@ impl EventDetails { let event_fields_end_idx = all_bytes.len() - input.len(); // topics come after the event data in EventRecord. - let topics = Vec::::decode(input)?; + let topics = Vec::>::decode(input)?; // what bytes did we skip over in total, including topics. let end_idx = all_bytes.len() - input.len(); @@ -413,7 +417,7 @@ impl EventDetails { } /// Return the topics associated with this event. - pub fn topics(&self) -> &[T::Hash] { + pub fn topics(&self) -> &[HashFor] { &self.topics } } @@ -430,7 +434,7 @@ pub struct EventMetadataDetails<'a> { #[cfg(test)] pub(crate) mod test_utils { use super::*; - use crate::config::{Config, SubstrateConfig}; + use crate::config::{HashFor, SubstrateConfig}; use codec::Encode; use frame_metadata::{ v15::{ @@ -463,12 +467,12 @@ pub(crate) mod test_utils { pub struct EventRecord { phase: Phase, event: AllEvents, - topics: Vec<::Hash>, + topics: Vec>, } impl EventRecord { /// Create a new event record with the given phase, event, and topics. - pub fn new(phase: Phase, event: E, topics: Vec<::Hash>) -> Self { + pub fn new(phase: Phase, event: E, topics: Vec>) -> Self { Self { phase, event: AllEvents::Test(event), diff --git a/core/src/tx/mod.rs b/core/src/tx/mod.rs index ec0b23925a..5a1c590deb 100644 --- a/core/src/tx/mod.rs +++ b/core/src/tx/mod.rs @@ -9,7 +9,7 @@ //! ```rust //! use subxt_signer::sr25519::dev; //! use subxt_macro::subxt; -//! use subxt_core::config::PolkadotConfig; +//! use subxt_core::config::{PolkadotConfig, HashFor}; //! use subxt_core::config::DefaultExtrinsicParamsBuilder as Params; //! use subxt_core::tx; //! use subxt_core::utils::H256; @@ -59,7 +59,7 @@ pub mod payload; pub mod signer; -use crate::config::{Config, ExtrinsicParams, ExtrinsicParamsEncoder, Hasher}; +use crate::config::{Config, ExtrinsicParams, ExtrinsicParamsEncoder, HashFor, Hasher}; use crate::error::{Error, ExtrinsicError, MetadataError}; use crate::metadata::Metadata; use crate::utils::Encoded; @@ -406,7 +406,8 @@ impl PartialTransactionV5 { /// This represents a signed transaction that's ready to be submitted. /// Use [`Transaction::encoded()`] or [`Transaction::into_encoded()`] to -/// get the bytes for it, or [`Transaction::hash()`] to get the hash. +/// get the bytes for it, or [`Transaction::hash_with()`] to hash the transaction +/// given an instance of [`Config::Hasher`]. pub struct Transaction { encoded: Encoded, marker: core::marker::PhantomData, @@ -422,9 +423,12 @@ impl Transaction { } } - /// Calculate and return the hash of the extrinsic, based on the configured hasher. - pub fn hash(&self) -> T::Hash { - T::Hasher::hash_of(&self.encoded) + /// Calculate and return the hash of the extrinsic, based on the provided hasher. + /// If you don't have a hasher to hand, you can construct one using the metadata + /// with `T::Hasher::new(&metadata)`. This will create a hasher suitable for the + /// current chain where possible. + pub fn hash_with(&self, hasher: T::Hasher) -> HashFor { + hasher.hash_of(&self.encoded) } /// Returns the SCALE encoded extrinsic bytes. diff --git a/rpcs/src/lib.rs b/rpcs/src/lib.rs index 27fe49d594..dea37552f1 100644 --- a/rpcs/src/lib.rs +++ b/rpcs/src/lib.rs @@ -45,7 +45,7 @@ pub trait RpcConfig { /// The block header type. type Header: Header; /// The block hash type. - type Hash: BlockHash; + type Hash: Hash; /// The Account ID type. type AccountId: AccountId; } @@ -55,8 +55,8 @@ pub trait Header: std::fmt::Debug + codec::Decode + serde::de::DeserializeOwned impl Header for T where T: std::fmt::Debug + codec::Decode + serde::de::DeserializeOwned {} /// A trait which is applied to any type that is a valid block hash. -pub trait BlockHash: serde::de::DeserializeOwned + serde::Serialize {} -impl BlockHash for T where T: serde::de::DeserializeOwned + serde::Serialize {} +pub trait Hash: serde::de::DeserializeOwned + serde::Serialize {} +impl Hash for T where T: serde::de::DeserializeOwned + serde::Serialize {} /// A trait which is applied to any type that is a valid Account ID. pub trait AccountId: serde::Serialize {} @@ -67,12 +67,14 @@ impl AccountId for T where T: serde::Serialize {} #[cfg(feature = "subxt")] mod impl_config { use super::*; + use subxt_core::config::HashFor; + impl RpcConfig for T where T: subxt_core::Config, { type Header = T::Header; - type Hash = T::Hash; + type Hash = HashFor; type AccountId = T::AccountId; } } diff --git a/rpcs/src/methods/chain_head.rs b/rpcs/src/methods/chain_head.rs index 7fddf702e3..02ffd23eca 100644 --- a/rpcs/src/methods/chain_head.rs +++ b/rpcs/src/methods/chain_head.rs @@ -7,7 +7,7 @@ //! methods exposed here. use crate::client::{rpc_params, RpcClient, RpcSubscription}; -use crate::BlockHash; +use crate::Hash; use crate::{Error, RpcConfig}; use derive_where::derive_where; use futures::{Stream, StreamExt}; @@ -871,7 +871,7 @@ pub struct FollowSubscription { done: bool, } -impl FollowSubscription { +impl FollowSubscription { /// Fetch the next item in the stream. pub async fn next(&mut self) -> Option<::Item> { ::next(self).await @@ -882,8 +882,8 @@ impl FollowSubscription { } } -impl Stream for FollowSubscription { - type Item = > as Stream>::Item; +impl Stream for FollowSubscription { + type Item = > as Stream>::Item; fn poll_next( mut self: std::pin::Pin<&mut Self>, cx: &mut std::task::Context<'_>, @@ -910,15 +910,15 @@ pub struct TransactionSubscription { done: bool, } -impl TransactionSubscription { +impl TransactionSubscription { /// Fetch the next item in the stream. pub async fn next(&mut self) -> Option<::Item> { ::next(self).await } } -impl Stream for TransactionSubscription { - type Item = > as Stream>::Item; +impl Stream for TransactionSubscription { + type Item = > as Stream>::Item; fn poll_next( mut self: std::pin::Pin<&mut Self>, cx: &mut std::task::Context<'_>, @@ -1031,7 +1031,7 @@ pub struct ArchiveStorageSubscription { done: bool, } -impl ArchiveStorageSubscription { +impl ArchiveStorageSubscription { /// Fetch the next item in the stream. pub async fn next(&mut self) -> Option<::Item> { ::next(self).await @@ -1042,8 +1042,8 @@ impl ArchiveStorageSubscription { } } -impl Stream for ArchiveStorageSubscription { - type Item = > as Stream>::Item; +impl Stream for ArchiveStorageSubscription { + type Item = > as Stream>::Item; fn poll_next( mut self: std::pin::Pin<&mut Self>, cx: &mut std::task::Context<'_>, diff --git a/signer/src/eth.rs b/signer/src/eth.rs index ff7d51365e..b802d540b5 100644 --- a/signer/src/eth.rs +++ b/signer/src/eth.rs @@ -310,14 +310,13 @@ mod test { use secp256k1::Secp256k1; use subxt_core::utils::AccountId20; - use subxt_core::{config::*, tx::signer::Signer as SignerT, utils::H256}; + use subxt_core::{config::*, tx::signer::Signer as SignerT}; use super::*; enum StubEthRuntimeConfig {} impl Config for StubEthRuntimeConfig { - type Hash = H256; type AccountId = AccountId20; type Address = AccountId20; type Signature = Signature; diff --git a/subxt/examples/setup_config_assethub.rs b/subxt/examples/setup_config_assethub.rs index c7ed6e09d3..4624819e12 100644 --- a/subxt/examples/setup_config_assethub.rs +++ b/subxt/examples/setup_config_assethub.rs @@ -20,7 +20,6 @@ use runtime::runtime_types::xcm::v3::junctions::Junctions; pub enum AssetHubConfig {} impl Config for AssetHubConfig { - type Hash = ::Hash; type AccountId = ::AccountId; type Address = ::Address; type Signature = ::Signature; diff --git a/subxt/examples/setup_config_custom.rs b/subxt/examples/setup_config_custom.rs index d146c406f5..ea1157d322 100644 --- a/subxt/examples/setup_config_custom.rs +++ b/subxt/examples/setup_config_custom.rs @@ -3,7 +3,7 @@ use codec::Encode; use subxt::client::ClientState; use subxt::config::{ transaction_extensions::Params, Config, ExtrinsicParams, ExtrinsicParamsEncoder, - ExtrinsicParamsError, + ExtrinsicParamsError, HashFor, }; use subxt_signer::sr25519::dev; @@ -15,7 +15,6 @@ pub mod runtime {} pub enum CustomConfig {} impl Config for CustomConfig { - type Hash = subxt::utils::H256; type AccountId = subxt::utils::AccountId32; type Address = subxt::utils::MultiAddress; type Signature = subxt::utils::MultiSignature; @@ -28,7 +27,7 @@ impl Config for CustomConfig { // This represents some arbitrary (and nonsensical) custom parameters that // will be attached to transaction extra and additional payloads: pub struct CustomExtrinsicParams { - genesis_hash: T::Hash, + genesis_hash: HashFor, tip: u128, foo: bool, } diff --git a/subxt/examples/setup_config_transaction_extension.rs b/subxt/examples/setup_config_transaction_extension.rs index 9c3cfa3d41..f0fcc58894 100644 --- a/subxt/examples/setup_config_transaction_extension.rs +++ b/subxt/examples/setup_config_transaction_extension.rs @@ -19,7 +19,6 @@ pub mod runtime {} pub enum CustomConfig {} impl Config for CustomConfig { - type Hash = subxt::utils::H256; type AccountId = subxt::utils::AccountId32; type Address = subxt::utils::MultiAddress; type Signature = subxt::utils::MultiSignature; diff --git a/subxt/examples/tx_basic_frontier.rs b/subxt/examples/tx_basic_frontier.rs index 4749eed47b..0a8fec8d94 100644 --- a/subxt/examples/tx_basic_frontier.rs +++ b/subxt/examples/tx_basic_frontier.rs @@ -15,7 +15,6 @@ mod eth_runtime {} enum EthRuntimeConfig {} impl subxt::Config for EthRuntimeConfig { - type Hash = subxt::utils::H256; type AccountId = AccountId20; type Address = AccountId20; type Signature = Signature; diff --git a/subxt/src/backend/chain_head/follow_stream.rs b/subxt/src/backend/chain_head/follow_stream.rs index ab2ecefd37..4f0e35b839 100644 --- a/subxt/src/backend/chain_head/follow_stream.rs +++ b/subxt/src/backend/chain_head/follow_stream.rs @@ -2,7 +2,7 @@ // This file is dual-licensed as Apache-2.0 or GPL-3.0. // see LICENSE for license details. -use crate::config::Config; +use crate::config::{Config, HashFor}; use crate::error::Error; use futures::{FutureExt, Stream, StreamExt, TryStreamExt}; use std::future::Future; @@ -99,7 +99,7 @@ impl FollowStream { } /// Create a new [`FollowStream`] given the RPC methods. - pub fn from_methods(methods: ChainHeadRpcMethods) -> FollowStream { + pub fn from_methods(methods: ChainHeadRpcMethods) -> FollowStream> { FollowStream { stream_getter: Box::new(move || { let methods = methods.clone(); @@ -115,7 +115,7 @@ impl FollowStream { }; // Map stream errors into the higher level subxt one: let stream = stream.map_err(|e| e.into()); - let stream: FollowEventStream = Box::pin(stream); + let stream: FollowEventStream> = Box::pin(stream); // Return both: Ok((stream, sub_id)) }) diff --git a/subxt/src/backend/chain_head/follow_stream_driver.rs b/subxt/src/backend/chain_head/follow_stream_driver.rs index d1ed5c4db9..3fd2d1af41 100644 --- a/subxt/src/backend/chain_head/follow_stream_driver.rs +++ b/subxt/src/backend/chain_head/follow_stream_driver.rs @@ -3,7 +3,7 @@ // see LICENSE for license details. use super::follow_stream_unpin::{BlockRef, FollowStreamMsg, FollowStreamUnpin}; -use crate::config::BlockHash; +use crate::config::Hash; use crate::error::{Error, RpcError}; use futures::stream::{Stream, StreamExt}; use std::collections::{HashMap, HashSet, VecDeque}; @@ -18,15 +18,15 @@ use subxt_rpcs::methods::chain_head::{FollowEvent, Initialized, RuntimeEvent}; /// blocks since then, as if they were each creating a unique `chainHead_follow` subscription). This /// is the "top" layer of our follow stream subscriptions, and the one that's interacted with elsewhere. #[derive(Debug)] -pub struct FollowStreamDriver { - inner: FollowStreamUnpin, - shared: Shared, +pub struct FollowStreamDriver { + inner: FollowStreamUnpin, + shared: Shared, } -impl FollowStreamDriver { +impl FollowStreamDriver { /// Create a new [`FollowStreamDriver`]. This must be polled by some executor /// in order for any progress to be made. Things can subscribe to events. - pub fn new(follow_unpin: FollowStreamUnpin) -> Self { + pub fn new(follow_unpin: FollowStreamUnpin) -> Self { Self { inner: follow_unpin, shared: Shared::default(), @@ -34,14 +34,14 @@ impl FollowStreamDriver { } /// Return a handle from which we can create new subscriptions to follow events. - pub fn handle(&self) -> FollowStreamDriverHandle { + pub fn handle(&self) -> FollowStreamDriverHandle { FollowStreamDriverHandle { shared: self.shared.clone(), } } } -impl Stream for FollowStreamDriver { +impl Stream for FollowStreamDriver { type Item = Result<(), Error>; fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { @@ -65,13 +65,13 @@ impl Stream for FollowStreamDriver { /// A handle that can be used to create subscribers, but that doesn't /// itself subscribe to events. #[derive(Debug, Clone)] -pub struct FollowStreamDriverHandle { - shared: Shared, +pub struct FollowStreamDriverHandle { + shared: Shared, } -impl FollowStreamDriverHandle { +impl FollowStreamDriverHandle { /// Subscribe to follow events. - pub fn subscribe(&self) -> FollowStreamDriverSubscription { + pub fn subscribe(&self) -> FollowStreamDriverSubscription { self.shared.subscribe() } } @@ -82,15 +82,15 @@ impl FollowStreamDriverHandle { /// runtime information, and then any new/best block events and so on received since /// the latest finalized block. #[derive(Debug)] -pub struct FollowStreamDriverSubscription { +pub struct FollowStreamDriverSubscription { id: usize, done: bool, - shared: Shared, - local_items: VecDeque>>, + shared: Shared, + local_items: VecDeque>>, } -impl Stream for FollowStreamDriverSubscription { - type Item = FollowStreamMsg>; +impl Stream for FollowStreamDriverSubscription { + type Item = FollowStreamMsg>; fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { if self.done { @@ -122,7 +122,7 @@ impl Stream for FollowStreamDriverSubscription { } } -impl FollowStreamDriverSubscription { +impl FollowStreamDriverSubscription { /// Return the current subscription ID. If the subscription has stopped, then this will /// wait until a new subscription has started with a new ID. pub async fn subscription_id(self) -> Option { @@ -138,18 +138,18 @@ impl FollowStreamDriverSubscription { } /// Subscribe to the follow events, ignoring any other messages. - pub fn events(self) -> impl Stream>> + Send + Sync { + pub fn events(self) -> impl Stream>> + Send + Sync { self.filter_map(|ev| std::future::ready(ev.into_event())) } } -impl Clone for FollowStreamDriverSubscription { +impl Clone for FollowStreamDriverSubscription { fn clone(&self) -> Self { self.shared.subscribe() } } -impl Drop for FollowStreamDriverSubscription { +impl Drop for FollowStreamDriverSubscription { fn drop(&mut self) { self.shared.remove_sub(self.id); } @@ -159,25 +159,25 @@ impl Drop for FollowStreamDriverSubscription { /// events to any subscribers, and subscribers will access it to pull the /// events destined for themselves. #[derive(Debug, Clone)] -struct Shared(Arc>>); +struct Shared(Arc>>); #[derive(Debug)] -struct SharedState { +struct SharedState { done: bool, next_id: usize, - subscribers: HashMap>, + subscribers: HashMap>, /// Keep a buffer of all events that should be handed to a new subscription. - block_events_for_new_subscriptions: VecDeque>>, + block_events_for_new_subscriptions: VecDeque>>, // Keep track of the subscription ID we send out on new subs. current_subscription_id: Option, // Keep track of the init message we send out on new subs. - current_init_message: Option>>, + current_init_message: Option>>, // Runtime events by block hash; we need to track these to know // whether the runtime has changed when we see a finalized block notification. - seen_runtime_events: HashMap, + seen_runtime_events: HashMap, } -impl Default for Shared { +impl Default for Shared { fn default() -> Self { Shared(Arc::new(Mutex::new(SharedState { next_id: 1, @@ -191,7 +191,7 @@ impl Default for Shared { } } -impl Shared { +impl Shared { /// Set the shared state to "done"; no more items will be handed to it. pub fn done(&self) { let mut shared = self.0.lock().unwrap(); @@ -216,7 +216,7 @@ impl Shared { &self, sub_id: usize, waker: &Waker, - ) -> Option>>> { + ) -> Option>>> { let mut shared = self.0.lock().unwrap(); let is_done = shared.done; @@ -236,7 +236,7 @@ impl Shared { } /// Push a new item out to subscribers. - pub fn push_item(&self, item: FollowStreamMsg>) { + pub fn push_item(&self, item: FollowStreamMsg>) { let mut shared = self.0.lock().unwrap(); let shared = shared.deref_mut(); @@ -289,7 +289,7 @@ impl Shared { // the state at the head of the chain, therefore it is correct to remove those as well. // Idem for the pruned hashes; they will never be reported again and we remove // them from the window of events. - let to_remove: HashSet = finalized_ev + let to_remove: HashSet = finalized_ev .finalized_block_hashes .iter() .chain(finalized_ev.pruned_block_hashes.iter()) @@ -337,7 +337,7 @@ impl Shared { } /// Create a new subscription. - pub fn subscribe(&self) -> FollowStreamDriverSubscription { + pub fn subscribe(&self) -> FollowStreamDriverSubscription { let mut shared = self.0.lock().unwrap(); let id = shared.next_id; @@ -382,30 +382,30 @@ impl Shared { /// Details for a given subscriber: any items it's not yet claimed, /// and a way to wake it up when there are more items for it. #[derive(Debug)] -struct SubscriberDetails { - items: VecDeque>>, +struct SubscriberDetails { + items: VecDeque>>, waker: Option, } /// A stream that subscribes to finalized blocks /// and indicates whether a block was missed if was restarted. #[derive(Debug)] -pub struct FollowStreamFinalizedHeads { - stream: FollowStreamDriverSubscription, +pub struct FollowStreamFinalizedHeads { + stream: FollowStreamDriverSubscription, sub_id: Option, - last_seen_block: Option>, + last_seen_block: Option>, f: F, is_done: bool, } -impl Unpin for FollowStreamFinalizedHeads {} +impl Unpin for FollowStreamFinalizedHeads {} -impl FollowStreamFinalizedHeads +impl FollowStreamFinalizedHeads where - Hash: BlockHash, - F: Fn(FollowEvent>) -> Vec>, + H: Hash, + F: Fn(FollowEvent>) -> Vec>, { - pub fn new(stream: FollowStreamDriverSubscription, f: F) -> Self { + pub fn new(stream: FollowStreamDriverSubscription, f: F) -> Self { Self { stream, sub_id: None, @@ -416,12 +416,12 @@ where } } -impl Stream for FollowStreamFinalizedHeads +impl Stream for FollowStreamFinalizedHeads where - Hash: BlockHash, - F: Fn(FollowEvent>) -> Vec>, + H: Hash, + F: Fn(FollowEvent>) -> Vec>, { - type Item = Result<(String, Vec>), Error>; + type Item = Result<(String, Vec>), Error>; fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { if self.is_done { @@ -493,14 +493,14 @@ mod test_utils { use super::*; /// Return a `FollowStreamDriver` - pub fn test_follow_stream_driver_getter( + pub fn test_follow_stream_driver_getter( events: F, max_life: usize, - ) -> FollowStreamDriver + ) -> FollowStreamDriver where - Hash: BlockHash + 'static, + H: Hash + 'static, F: Fn() -> I + Send + 'static, - I: IntoIterator, Error>>, + I: IntoIterator, Error>>, { let (stream, _) = test_unpin_stream_getter(events, max_life); FollowStreamDriver::new(stream) diff --git a/subxt/src/backend/chain_head/follow_stream_unpin.rs b/subxt/src/backend/chain_head/follow_stream_unpin.rs index d711c2a45d..a54f44de77 100644 --- a/subxt/src/backend/chain_head/follow_stream_unpin.rs +++ b/subxt/src/backend/chain_head/follow_stream_unpin.rs @@ -4,7 +4,7 @@ use super::follow_stream::FollowStream; use super::ChainHeadRpcMethods; -use crate::config::{BlockHash, Config}; +use crate::config::{Config, Hash, HashFor}; use crate::error::Error; use futures::stream::{FuturesUnordered, Stream, StreamExt}; use subxt_rpcs::methods::chain_head::{ @@ -27,11 +27,11 @@ pub use super::follow_stream::FollowStreamMsg; /// result). Put simply, it tries to keep every block pinned as long as possible until the block is no longer /// used anywhere. #[derive(Debug)] -pub struct FollowStreamUnpin { +pub struct FollowStreamUnpin { // The underlying stream of events. - inner: FollowStream, + inner: FollowStream, // A method to call to unpin a block, given a block hash and a subscription ID. - unpin_method: UnpinMethodHolder, + unpin_method: UnpinMethodHolder, // Futures for sending unpin events that we'll poll to completion as // part of polling the stream as a whole. unpin_futs: FuturesUnordered, @@ -46,14 +46,14 @@ pub struct FollowStreamUnpin { // The longest period a block can be pinned for. max_block_life: usize, // The currently seen and pinned blocks. - pinned: HashMap>, + pinned: HashMap>, // Shared state about blocks we've flagged to unpin from elsewhere - unpin_flags: UnpinFlags, + unpin_flags: UnpinFlags, } // Just a wrapper to make implementing debug on the whole thing easier. -struct UnpinMethodHolder(UnpinMethod); -impl std::fmt::Debug for UnpinMethodHolder { +struct UnpinMethodHolder(UnpinMethod); +impl std::fmt::Debug for UnpinMethodHolder { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!( f, @@ -63,15 +63,15 @@ impl std::fmt::Debug for UnpinMethodHolder { } /// The type of the unpin method that we need to provide. -pub type UnpinMethod = Box) -> UnpinFut + Send>; +pub type UnpinMethod = Box) -> UnpinFut + Send>; /// The future returned from [`UnpinMethod`]. pub type UnpinFut = Pin + Send + 'static>>; -impl std::marker::Unpin for FollowStreamUnpin {} +impl std::marker::Unpin for FollowStreamUnpin {} -impl Stream for FollowStreamUnpin { - type Item = Result>, Error>; +impl Stream for FollowStreamUnpin { + type Item = Result>, Error>; fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { let mut this = self.as_mut(); @@ -253,11 +253,11 @@ impl Stream for FollowStreamUnpin { } } -impl FollowStreamUnpin { +impl FollowStreamUnpin { /// Create a new [`FollowStreamUnpin`]. pub fn new( - follow_stream: FollowStream, - unpin_method: UnpinMethod, + follow_stream: FollowStream, + unpin_method: UnpinMethod, max_block_life: usize, ) -> Self { Self { @@ -274,11 +274,11 @@ impl FollowStreamUnpin { /// Create a new [`FollowStreamUnpin`] given the RPC methods. pub fn from_methods( - follow_stream: FollowStream, + follow_stream: FollowStream>, methods: ChainHeadRpcMethods, max_block_life: usize, - ) -> FollowStreamUnpin { - let unpin_method = Box::new(move |hash: T::Hash, sub_id: Arc| { + ) -> FollowStreamUnpin> { + let unpin_method = Box::new(move |hash: HashFor, sub_id: Arc| { let methods = methods.clone(); let fut: UnpinFut = Box::pin(async move { // We ignore any errors trying to unpin at the moment. @@ -291,14 +291,14 @@ impl FollowStreamUnpin { } /// Is the block hash currently pinned. - pub fn is_pinned(&self, hash: &Hash) -> bool { + pub fn is_pinned(&self, hash: &H) -> bool { self.pinned.contains_key(hash) } /// Pin a block, or return the reference to an already-pinned block. If the block has been registered to /// be unpinned, we'll clear those flags, so that it won't be unpinned. If the unpin request has already /// been sent though, then the block will be unpinned. - fn pin_block_at(&mut self, rel_block_age: usize, hash: Hash) -> BlockRef { + fn pin_block_at(&mut self, rel_block_age: usize, hash: H) -> BlockRef { self.pin_block_at_setting_unpinnable_flag(rel_block_age, hash, false) } @@ -306,16 +306,16 @@ impl FollowStreamUnpin { /// /// This is the same as [`Self::pin_block_at`], except that it also marks the block as being unpinnable now, /// which should be done for any block that will no longer be seen in future events. - fn pin_unpinnable_block_at(&mut self, rel_block_age: usize, hash: Hash) -> BlockRef { + fn pin_unpinnable_block_at(&mut self, rel_block_age: usize, hash: H) -> BlockRef { self.pin_block_at_setting_unpinnable_flag(rel_block_age, hash, true) } fn pin_block_at_setting_unpinnable_flag( &mut self, rel_block_age: usize, - hash: Hash, + hash: H, can_be_unpinned: bool, - ) -> BlockRef { + ) -> BlockRef { let entry = self .pinned .entry(hash) @@ -390,10 +390,10 @@ impl FollowStreamUnpin { // The set of block hashes that can be unpinned when ready. // BlockRefs write to this when they are dropped. -type UnpinFlags = Arc>>; +type UnpinFlags = Arc>>; #[derive(Debug)] -struct PinnedDetails { +struct PinnedDetails { /// Relatively speaking, how old is the block? When we start following /// blocks, the first finalized block gets an age of 0, the second an age /// of 1 and so on. @@ -401,7 +401,7 @@ struct PinnedDetails { /// A block ref we can hand out to keep blocks pinned. /// Because we store one here until it's unpinned, the live count /// will only drop to 1 when no external refs are left. - block_ref: BlockRef, + block_ref: BlockRef, /// Has this block showed up in the list of pruned blocks, or has it /// been finalized? In this case, it can now been pinned as it won't /// show up again in future events (except as a "parent block" of some @@ -411,21 +411,21 @@ struct PinnedDetails { /// All blocks reported will be wrapped in this. #[derive(Debug, Clone)] -pub struct BlockRef { - inner: Arc>, +pub struct BlockRef { + inner: Arc>, } #[derive(Debug)] -struct BlockRefInner { - hash: Hash, - unpin_flags: UnpinFlags, +struct BlockRefInner { + hash: H, + unpin_flags: UnpinFlags, } -impl BlockRef { +impl BlockRef { /// For testing purposes only, create a BlockRef from a hash /// that isn't pinned. #[cfg(test)] - pub fn new(hash: Hash) -> Self { + pub fn new(hash: H) -> Self { BlockRef { inner: Arc::new(BlockRefInner { hash, @@ -435,24 +435,24 @@ impl BlockRef { } /// Return the hash for this block. - pub fn hash(&self) -> Hash { + pub fn hash(&self) -> H { self.inner.hash } } -impl PartialEq for BlockRef { +impl PartialEq for BlockRef { fn eq(&self, other: &Self) -> bool { self.inner.hash == other.inner.hash } } -impl PartialEq for BlockRef { - fn eq(&self, other: &Hash) -> bool { +impl PartialEq for BlockRef { + fn eq(&self, other: &H) -> bool { &self.inner.hash == other } } -impl Drop for BlockRef { +impl Drop for BlockRef { fn drop(&mut self) { // PinnedDetails keeps one ref, so if this is the second ref, it's the // only "external" one left and we should ask to unpin it now. if it's @@ -472,23 +472,23 @@ pub(super) mod test_utils { use super::*; use crate::config::substrate::H256; - pub type UnpinRx = std::sync::mpsc::Receiver<(Hash, Arc)>; + pub type UnpinRx = std::sync::mpsc::Receiver<(H, Arc)>; /// Get a [`FollowStreamUnpin`] from an iterator over events. - pub fn test_unpin_stream_getter( + pub fn test_unpin_stream_getter( events: F, max_life: usize, - ) -> (FollowStreamUnpin, UnpinRx) + ) -> (FollowStreamUnpin, UnpinRx) where - Hash: BlockHash + 'static, + H: Hash + 'static, F: Fn() -> I + Send + 'static, - I: IntoIterator, Error>>, + I: IntoIterator, Error>>, { // Unpin requests will come here so that we can look out for them. let (unpin_tx, unpin_rx) = std::sync::mpsc::channel(); let follow_stream = FollowStream::new(test_stream_getter(events)); - let unpin_method: UnpinMethod = Box::new(move |hash, sub_id| { + let unpin_method: UnpinMethod = Box::new(move |hash, sub_id| { unpin_tx.send((hash, sub_id)).unwrap(); Box::pin(std::future::ready(())) }); @@ -498,11 +498,11 @@ pub(super) mod test_utils { } /// Assert that the unpinned blocks sent from the `UnpinRx` channel match the items given. - pub fn assert_from_unpin_rx( - unpin_rx: &UnpinRx, - items: impl IntoIterator, + pub fn assert_from_unpin_rx( + unpin_rx: &UnpinRx, + items: impl IntoIterator, ) { - let expected_hashes = HashSet::::from_iter(items); + let expected_hashes = HashSet::::from_iter(items); for i in 0..expected_hashes.len() { let Ok((hash, _)) = unpin_rx.try_recv() else { panic!("Another unpin event is expected, but failed to pull item {i} from channel"); diff --git a/subxt/src/backend/chain_head/mod.rs b/subxt/src/backend/chain_head/mod.rs index 4d3c2615c2..7143e229b1 100644 --- a/subxt/src/backend/chain_head/mod.rs +++ b/subxt/src/backend/chain_head/mod.rs @@ -21,9 +21,8 @@ use crate::backend::{ utils::retry, Backend, BlockRef, BlockRefT, RuntimeVersion, StorageResponse, StreamOf, StreamOfResults, TransactionStatus, }; -use crate::config::BlockHash; +use crate::config::{Config, Hash, HashFor}; use crate::error::{Error, RpcError}; -use crate::Config; use async_trait::async_trait; use follow_stream_driver::{FollowStreamDriver, FollowStreamDriverHandle}; use futures::future::Either; @@ -130,12 +129,13 @@ impl ChainHeadBackendBuilder { // Construct the underlying follow_stream layers: let rpc_methods = ChainHeadRpcMethods::new(client.into()); let follow_stream = - follow_stream::FollowStream::::from_methods(rpc_methods.clone()); - let follow_stream_unpin = follow_stream_unpin::FollowStreamUnpin::::from_methods( - follow_stream, - rpc_methods.clone(), - self.max_block_life, - ); + follow_stream::FollowStream::>::from_methods(rpc_methods.clone()); + let follow_stream_unpin = + follow_stream_unpin::FollowStreamUnpin::>::from_methods( + follow_stream, + rpc_methods.clone(), + self.max_block_life, + ); let follow_stream_driver = FollowStreamDriver::new(follow_stream_unpin); // Wrap these into the backend and driver that we'll expose. @@ -193,11 +193,11 @@ impl ChainHeadBackendBuilder { /// backend to make progress. #[derive(Debug)] pub struct ChainHeadBackendDriver { - driver: FollowStreamDriver, + driver: FollowStreamDriver>, } impl Stream for ChainHeadBackendDriver { - type Item = as Stream>::Item; + type Item = > as Stream>::Item; fn poll_next( mut self: std::pin::Pin<&mut Self>, cx: &mut std::task::Context<'_>, @@ -212,7 +212,7 @@ pub struct ChainHeadBackend { // RPC methods we'll want to call: methods: ChainHeadRpcMethods, // A handle to the chainHead_follow subscription: - follow_handle: FollowStreamDriverHandle, + follow_handle: FollowStreamDriverHandle>, // How long to wait until giving up on transactions: transaction_timeout_secs: usize, // Don't synchronise blocks with chainHead_follow when submitting txs: @@ -229,11 +229,11 @@ impl ChainHeadBackend { async fn stream_headers( &self, f: F, - ) -> Result)>, Error> + ) -> Result>)>, Error> where F: Fn( - FollowEvent>, - ) -> Vec> + FollowEvent>>, + ) -> Vec>> + Send + Sync + 'static, @@ -275,9 +275,9 @@ impl ChainHeadBackend { } } -impl BlockRefT for follow_stream_unpin::BlockRef {} -impl From> for BlockRef { - fn from(b: follow_stream_unpin::BlockRef) -> Self { +impl BlockRefT for follow_stream_unpin::BlockRef {} +impl From> for BlockRef { + fn from(b: follow_stream_unpin::BlockRef) -> Self { BlockRef::new(b.hash(), b) } } @@ -289,7 +289,7 @@ impl Backend for ChainHeadBackend { async fn storage_fetch_values( &self, keys: Vec>, - at: T::Hash, + at: HashFor, ) -> Result, Error> { retry(|| async { let queries = keys.iter().map(|key| StorageQuery { @@ -324,7 +324,7 @@ impl Backend for ChainHeadBackend { async fn storage_fetch_descendant_keys( &self, key: Vec, - at: T::Hash, + at: HashFor, ) -> Result>, Error> { retry(|| async { // Ask for hashes, and then just ignore them and return the keys that come back. @@ -350,7 +350,7 @@ impl Backend for ChainHeadBackend { async fn storage_fetch_descendant_values( &self, key: Vec, - at: T::Hash, + at: HashFor, ) -> Result, Error> { retry(|| async { let query = StorageQuery { @@ -386,7 +386,7 @@ impl Backend for ChainHeadBackend { .await } - async fn genesis_hash(&self) -> Result { + async fn genesis_hash(&self) -> Result, Error> { retry(|| async { let genesis_hash = self.methods.chainspec_v1_genesis_hash().await?; Ok(genesis_hash) @@ -394,7 +394,7 @@ impl Backend for ChainHeadBackend { .await } - async fn block_header(&self, at: T::Hash) -> Result, Error> { + async fn block_header(&self, at: HashFor) -> Result, Error> { retry(|| async { let sub_id = get_subscription_id(&self.follow_handle).await?; let header = self.methods.chainhead_v1_header(&sub_id, at).await?; @@ -403,7 +403,7 @@ impl Backend for ChainHeadBackend { .await } - async fn block_body(&self, at: T::Hash) -> Result>>, Error> { + async fn block_body(&self, at: HashFor) -> Result>>, Error> { retry(|| async { let sub_id = get_subscription_id(&self.follow_handle).await?; @@ -432,8 +432,8 @@ impl Backend for ChainHeadBackend { .await } - async fn latest_finalized_block_ref(&self) -> Result, Error> { - let next_ref: Option> = self + async fn latest_finalized_block_ref(&self) -> Result>, Error> { + let next_ref: Option>> = self .follow_handle .subscribe() .events() @@ -543,7 +543,8 @@ impl Backend for ChainHeadBackend { async fn stream_all_block_headers( &self, - ) -> Result)>, Error> { + _hasher: T::Hasher, + ) -> Result>)>, Error> { // TODO: https://github.com/paritytech/subxt/issues/1568 // // It's possible that blocks may be silently missed if @@ -560,7 +561,8 @@ impl Backend for ChainHeadBackend { async fn stream_best_block_headers( &self, - ) -> Result)>, Error> { + _hasher: T::Hasher, + ) -> Result>)>, Error> { // TODO: https://github.com/paritytech/subxt/issues/1568 // // It's possible that blocks may be silently missed if @@ -575,7 +577,8 @@ impl Backend for ChainHeadBackend { async fn stream_finalized_block_headers( &self, - ) -> Result)>, Error> { + _hasher: T::Hasher, + ) -> Result>)>, Error> { self.stream_headers(|ev| match ev { FollowEvent::Initialized(init) => init.finalized_block_hashes, FollowEvent::Finalized(ev) => ev.finalized_block_hashes, @@ -587,12 +590,12 @@ impl Backend for ChainHeadBackend { async fn submit_transaction( &self, extrinsic: &[u8], - ) -> Result>, Error> { + ) -> Result>>, Error> { // Submit a transaction. This makes no attempt to sync with follow events, async fn submit_transaction_ignoring_follow_events( extrinsic: &[u8], methods: &ChainHeadRpcMethods, - ) -> Result>, Error> { + ) -> Result>>, Error> { let tx_progress = methods .transactionwatch_v1_submit_and_watch(extrinsic) .await? @@ -633,8 +636,8 @@ impl Backend for ChainHeadBackend { extrinsic: &[u8], transaction_timeout_secs: u64, methods: &ChainHeadRpcMethods, - follow_handle: &FollowStreamDriverHandle, - ) -> Result>, Error> { + follow_handle: &FollowStreamDriverHandle>, + ) -> Result>>, Error> { // We care about new and finalized block hashes. enum SeenBlockMarker { New, @@ -655,7 +658,7 @@ impl Backend for ChainHeadBackend { // If we see the finalized event, we start waiting until we find a finalized block that // matches, so we can guarantee to return a pinned block hash and be properly in sync // with chainHead_follow. - let mut finalized_hash: Option = None; + let mut finalized_hash: Option> = None; // Record the start time so that we can time out if things appear to take too long. let start_instant = web_time::Instant::now(); @@ -818,7 +821,7 @@ impl Backend for ChainHeadBackend { &self, method: &str, call_parameters: Option<&[u8]>, - at: T::Hash, + at: HashFor, ) -> Result, Error> { retry(|| async { let sub_id = get_subscription_id(&self.follow_handle).await?; @@ -856,8 +859,8 @@ impl Backend for ChainHeadBackend { } /// A helper to obtain a subscription ID. -async fn get_subscription_id( - follow_handle: &FollowStreamDriverHandle, +async fn get_subscription_id( + follow_handle: &FollowStreamDriverHandle, ) -> Result { let Some(sub_id) = follow_handle.subscribe().subscription_id().await else { return Err(RpcError::SubscriptionDropped.into()); diff --git a/subxt/src/backend/chain_head/storage_items.rs b/subxt/src/backend/chain_head/storage_items.rs index 7e2b2f7688..5a108b6498 100644 --- a/subxt/src/backend/chain_head/storage_items.rs +++ b/subxt/src/backend/chain_head/storage_items.rs @@ -4,7 +4,7 @@ use super::follow_stream_driver::FollowStreamDriverHandle; use super::follow_stream_unpin::BlockRef; -use crate::config::Config; +use crate::config::{Config, HashFor}; use crate::error::{Error, RpcError}; use futures::{FutureExt, Stream, StreamExt}; use std::collections::VecDeque; @@ -24,7 +24,7 @@ pub struct StorageItems { buffered_responses: VecDeque, continue_call: ContinueFutGetter, continue_fut: Option, - follow_event_stream: FollowEventStream, + follow_event_stream: FollowEventStream>, } impl StorageItems { @@ -33,8 +33,8 @@ impl StorageItems { // needed, and stop when done. pub async fn from_methods( queries: impl Iterator>, - at: T::Hash, - follow_handle: &FollowStreamDriverHandle, + at: HashFor, + follow_handle: &FollowStreamDriverHandle>, methods: ChainHeadRpcMethods, ) -> Result { let sub_id = super::get_subscription_id(follow_handle).await?; @@ -76,7 +76,7 @@ impl StorageItems { fn new( operation_id: Arc, continue_call: ContinueFutGetter, - follow_event_stream: FollowEventStream, + follow_event_stream: FollowEventStream>, ) -> Self { Self { done: false, diff --git a/subxt/src/backend/legacy.rs b/subxt/src/backend/legacy.rs index 5c317fd32f..004225f935 100644 --- a/subxt/src/backend/legacy.rs +++ b/subxt/src/backend/legacy.rs @@ -11,7 +11,10 @@ use crate::backend::{ Backend, BlockRef, RuntimeVersion, StorageResponse, StreamOf, StreamOfResults, TransactionStatus, }; -use crate::{config::Header, Config, Error}; +use crate::{ + config::{Config, HashFor, Header}, + Error, +}; use async_trait::async_trait; use futures::TryStreamExt; use futures::{future, future::Either, stream, Future, FutureExt, Stream, StreamExt}; @@ -97,11 +100,11 @@ impl Backend for LegacyBackend { async fn storage_fetch_values( &self, keys: Vec>, - at: T::Hash, + at: HashFor, ) -> Result, Error> { fn get_entry( key: Vec, - at: T::Hash, + at: HashFor, methods: LegacyRpcMethods, ) -> impl Future, Error>> { retry(move || { @@ -134,7 +137,7 @@ impl Backend for LegacyBackend { async fn storage_fetch_descendant_keys( &self, key: Vec, - at: T::Hash, + at: HashFor, ) -> Result>, Error> { let keys = StorageFetchDescendantKeysStream { at, @@ -165,7 +168,7 @@ impl Backend for LegacyBackend { async fn storage_fetch_descendant_values( &self, key: Vec, - at: T::Hash, + at: HashFor, ) -> Result, Error> { let keys_stream = StorageFetchDescendantKeysStream { at, @@ -184,7 +187,7 @@ impl Backend for LegacyBackend { }))) } - async fn genesis_hash(&self) -> Result { + async fn genesis_hash(&self) -> Result, Error> { retry(|| async { let hash = self.methods.genesis_hash().await?; Ok(hash) @@ -192,7 +195,7 @@ impl Backend for LegacyBackend { .await } - async fn block_header(&self, at: T::Hash) -> Result, Error> { + async fn block_header(&self, at: HashFor) -> Result, Error> { retry(|| async { let header = self.methods.chain_get_header(Some(at)).await?; Ok(header) @@ -200,7 +203,7 @@ impl Backend for LegacyBackend { .await } - async fn block_body(&self, at: T::Hash) -> Result>>, Error> { + async fn block_body(&self, at: HashFor) -> Result>>, Error> { retry(|| async { let Some(details) = self.methods.chain_get_block(Some(at)).await? else { return Ok(None); @@ -212,7 +215,7 @@ impl Backend for LegacyBackend { .await } - async fn latest_finalized_block_ref(&self) -> Result, Error> { + async fn latest_finalized_block_ref(&self) -> Result>, Error> { retry(|| async { let hash = self.methods.chain_get_finalized_head().await?; Ok(BlockRef::from_hash(hash)) @@ -270,16 +273,16 @@ impl Backend for LegacyBackend { async fn stream_all_block_headers( &self, - ) -> Result)>, Error> { + hasher: T::Hasher, + ) -> Result>)>, Error> { let methods = self.methods.clone(); - let retry_sub = retry_stream(move || { let methods = methods.clone(); Box::pin(async move { let sub = methods.chain_subscribe_all_heads().await?; - let sub = sub.map_err(|e| e.into()).map(|r| { + let sub = sub.map_err(|e| e.into()).map(move |r| { r.map(|h| { - let hash = h.hash(); + let hash = h.hash_with(hasher); (h, BlockRef::from_hash(hash)) }) }); @@ -293,16 +296,17 @@ impl Backend for LegacyBackend { async fn stream_best_block_headers( &self, - ) -> Result)>, Error> { + hasher: T::Hasher, + ) -> Result>)>, Error> { let methods = self.methods.clone(); let retry_sub = retry_stream(move || { let methods = methods.clone(); Box::pin(async move { let sub = methods.chain_subscribe_new_heads().await?; - let sub = sub.map_err(|e| e.into()).map(|r| { + let sub = sub.map_err(|e| e.into()).map(move |r| { r.map(|h| { - let hash = h.hash(); + let hash = h.hash_with(hasher); (h, BlockRef::from_hash(hash)) }) }); @@ -316,7 +320,8 @@ impl Backend for LegacyBackend { async fn stream_finalized_block_headers( &self, - ) -> Result)>, Error> { + hasher: T::Hasher, + ) -> Result>)>, Error> { let this = self.clone(); let retry_sub = retry_stream(move || { @@ -338,9 +343,9 @@ impl Backend for LegacyBackend { sub, last_finalized_block_num, ); - let sub = sub.map(|r| { + let sub = sub.map(move |r| { r.map(|h| { - let hash = h.hash(); + let hash = h.hash_with(hasher); (h, BlockRef::from_hash(hash)) }) }); @@ -356,7 +361,7 @@ impl Backend for LegacyBackend { async fn submit_transaction( &self, extrinsic: &[u8], - ) -> Result>, Error> { + ) -> Result>>, Error> { let sub = self .methods .author_submit_and_watch_extrinsic(extrinsic) @@ -417,7 +422,7 @@ impl Backend for LegacyBackend { &self, method: &str, call_parameters: Option<&[u8]>, - at: T::Hash, + at: HashFor, ) -> Result, Error> { retry(|| async { let res = self @@ -484,7 +489,7 @@ where pub struct StorageFetchDescendantKeysStream { methods: LegacyRpcMethods, key: Vec, - at: T::Hash, + at: HashFor, // How many entries to ask for each time. storage_page_size: u32, // What key do we start paginating from? None = from the beginning. diff --git a/subxt/src/backend/mod.rs b/subxt/src/backend/mod.rs index 0c93f11a41..8ecafad5bb 100644 --- a/subxt/src/backend/mod.rs +++ b/subxt/src/backend/mod.rs @@ -10,9 +10,9 @@ pub mod chain_head; pub mod legacy; pub mod utils; +use crate::config::{Config, HashFor}; use crate::error::Error; use crate::metadata::Metadata; -use crate::Config; use async_trait::async_trait; use codec::{Decode, Encode}; use futures::{Stream, StreamExt}; @@ -82,37 +82,37 @@ pub trait Backend: sealed::Sealed + Send + Sync + 'static { async fn storage_fetch_values( &self, keys: Vec>, - at: T::Hash, + at: HashFor, ) -> Result, Error>; /// Fetch keys underneath the given key from storage. async fn storage_fetch_descendant_keys( &self, key: Vec, - at: T::Hash, + at: HashFor, ) -> Result>, Error>; /// Fetch values underneath the given key from storage. async fn storage_fetch_descendant_values( &self, key: Vec, - at: T::Hash, + at: HashFor, ) -> Result, Error>; /// Fetch the genesis hash - async fn genesis_hash(&self) -> Result; + async fn genesis_hash(&self) -> Result, Error>; /// Get a block header - async fn block_header(&self, at: T::Hash) -> Result, Error>; + async fn block_header(&self, at: HashFor) -> Result, Error>; /// Return the extrinsics found in the block. Each extrinsic is represented /// by a vector of bytes which has _not_ been SCALE decoded (in other words, the /// first bytes in the vector will decode to the compact encoded length of the extrinsic) - async fn block_body(&self, at: T::Hash) -> Result>>, Error>; + async fn block_body(&self, at: HashFor) -> Result>>, Error>; /// Get the most recent finalized block hash. /// Note: needed only in blocks client for finalized block stream; can prolly be removed. - async fn latest_finalized_block_ref(&self) -> Result, Error>; + async fn latest_finalized_block_ref(&self) -> Result>, Error>; /// Get information about the current runtime. async fn current_runtime_version(&self) -> Result; @@ -123,30 +123,33 @@ pub trait Backend: sealed::Sealed + Send + Sync + 'static { /// A stream of all new block headers as they arrive. async fn stream_all_block_headers( &self, - ) -> Result)>, Error>; + hasher: T::Hasher, + ) -> Result>)>, Error>; /// A stream of best block headers. async fn stream_best_block_headers( &self, - ) -> Result)>, Error>; + hasher: T::Hasher, + ) -> Result>)>, Error>; /// A stream of finalized block headers. async fn stream_finalized_block_headers( &self, - ) -> Result)>, Error>; + hasher: T::Hasher, + ) -> Result>)>, Error>; /// Submit a transaction. This will return a stream of events about it. async fn submit_transaction( &self, bytes: &[u8], - ) -> Result>, Error>; + ) -> Result>>, Error>; /// Make a call to some runtime API. async fn call( &self, method: &str, call_parameters: Option<&[u8]>, - at: T::Hash, + at: HashFor, ) -> Result, Error>; } @@ -157,7 +160,7 @@ pub trait BackendExt: Backend { async fn storage_fetch_value( &self, key: Vec, - at: T::Hash, + at: HashFor, ) -> Result>, Error> { self.storage_fetch_values(vec![key], at) .await? @@ -173,7 +176,7 @@ pub trait BackendExt: Backend { &self, method: &str, call_parameters: Option<&[u8]>, - at: T::Hash, + at: HashFor, ) -> Result { let bytes = self.call(method, call_parameters, at).await?; let res = D::decode(&mut &*bytes)?; @@ -181,7 +184,7 @@ pub trait BackendExt: Backend { } /// Return the metadata at some version. - async fn metadata_at_version(&self, version: u32, at: T::Hash) -> Result { + async fn metadata_at_version(&self, version: u32, at: HashFor) -> Result { let param = version.encode(); let opaque: Option = self @@ -196,7 +199,7 @@ pub trait BackendExt: Backend { } /// Return V14 metadata from the legacy `Metadata_metadata` call. - async fn legacy_metadata(&self, at: T::Hash) -> Result { + async fn legacy_metadata(&self, at: HashFor) -> Result { let opaque: frame_metadata::OpaqueMetadata = self.call_decoding("Metadata_metadata", None, at).await?; let metadata: Metadata = Decode::decode(&mut &opaque.0[..])?; @@ -412,7 +415,6 @@ mod test { // Define dummy config enum Conf {} impl Config for Conf { - type Hash = H256; type AccountId = crate::utils::AccountId32; type Address = crate::utils::MultiAddress; type Signature = crate::utils::MultiSignature; @@ -540,7 +542,7 @@ mod test { /// - `call` /// The test covers them because they follow the simple pattern of: /// ```no_run - /// async fn THE_THING(&self) -> Result { + /// async fn THE_THING(&self) -> Result, Error> { /// retry(|| ).await /// } /// ``` @@ -573,7 +575,7 @@ mod test { /// ```no_run /// async fn stream_the_thing( /// &self, - /// ) -> Result)>, Error> { + /// ) -> Result>)>, Error> { /// let methods = self.methods.clone(); /// let retry_sub = retry_stream(move || { /// let methods = methods.clone(); @@ -692,7 +694,7 @@ mod test { serde_json::from_value(spec).expect("Mock runtime spec should be the right shape") } - type FollowEvent = chain_head::FollowEvent<::Hash>; + type FollowEvent = chain_head::FollowEvent>; /// Build a mock client which can handle `chainHead_v1_follow` subscriptions. /// Messages from the provided receiver are sent to the latest active subscription. @@ -747,7 +749,7 @@ mod test { async move { if let Some(id) = id { let follow_event = - FollowEvent::Initialized(Initialized::<::Hash> { + FollowEvent::Initialized(Initialized::> { finalized_block_hashes: vec![random_hash()], finalized_block_runtime: Some(chain_head::RuntimeEvent::Valid( RuntimeVersionEvent { diff --git a/subxt/src/blocks/block_types.rs b/subxt/src/blocks/block_types.rs index 75858fe977..a67d7d2be0 100644 --- a/subxt/src/blocks/block_types.rs +++ b/subxt/src/blocks/block_types.rs @@ -6,7 +6,7 @@ use crate::{ backend::BlockRef, blocks::Extrinsics, client::{OfflineClientT, OnlineClientT}, - config::{Config, Header}, + config::{Config, HashFor, Header}, error::{BlockError, DecodeError, Error}, events, runtime_api::RuntimeApi, @@ -20,7 +20,7 @@ use std::sync::Arc; /// A representation of a block. pub struct Block { header: T::Header, - block_ref: BlockRef, + block_ref: BlockRef>, client: C, // Since we obtain the same events for every extrinsic, let's // cache them so that we only ever do that once: @@ -36,7 +36,7 @@ where T: Config, C: OfflineClientT, { - pub(crate) fn new(header: T::Header, block_ref: BlockRef, client: C) -> Self { + pub(crate) fn new(header: T::Header, block_ref: BlockRef>, client: C) -> Self { Block { header, block_ref, @@ -47,12 +47,12 @@ where /// Return a reference to the given block. While this reference is kept alive, /// the backend will (if possible) endeavour to keep hold of the block. - pub fn reference(&self) -> BlockRef { + pub fn reference(&self) -> BlockRef> { self.block_ref.clone() } /// Return the block hash. - pub fn hash(&self) -> T::Hash { + pub fn hash(&self) -> HashFor { self.block_ref.hash() } @@ -74,12 +74,12 @@ where { /// Return the events associated with the block, fetching them from the node if necessary. pub async fn events(&self) -> Result, Error> { - get_events(&self.client, self.header.hash(), &self.cached_events).await + get_events(&self.client, self.hash(), &self.cached_events).await } /// Fetch and return the extrinsics in the block body. pub async fn extrinsics(&self) -> Result, Error> { - let block_hash = self.header.hash(); + let block_hash = self.hash(); let Some(extrinsics) = self.client.backend().block_body(block_hash).await? else { return Err(BlockError::not_found(block_hash).into()); }; @@ -111,7 +111,7 @@ where // Return Events from the cache, or fetch from the node if needed. pub(crate) async fn get_events( client: &C, - block_hash: T::Hash, + block_hash: HashFor, cached_events: &AsyncMutex>>, ) -> Result, Error> where @@ -140,7 +140,7 @@ where pub(crate) async fn get_account_nonce( client: &C, account_id: &T::AccountId, - block_hash: T::Hash, + block_hash: HashFor, ) -> Result where C: OnlineClientT, diff --git a/subxt/src/blocks/blocks_client.rs b/subxt/src/blocks/blocks_client.rs index 6e71208b42..4e065a3ce8 100644 --- a/subxt/src/blocks/blocks_client.rs +++ b/subxt/src/blocks/blocks_client.rs @@ -6,7 +6,7 @@ use super::Block; use crate::{ backend::{BlockRef, StreamOfResults}, client::OnlineClientT, - config::Config, + config::{Config, HashFor}, error::{BlockError, Error}, utils::PhantomDataSendSync, }; @@ -48,7 +48,7 @@ where /// but may run into errors attempting to work with them. pub fn at( &self, - block_ref: impl Into>, + block_ref: impl Into>>, ) -> impl Future, Error>> + Send + 'static { self.at_or_latest(Some(block_ref.into())) } @@ -64,7 +64,7 @@ where /// provided. fn at_or_latest( &self, - block_ref: Option>, + block_ref: Option>>, ) -> impl Future, Error>> + Send + 'static { let client = self.client.clone(); async move { @@ -94,8 +94,9 @@ where Client: Send + Sync + 'static, { let client = self.client.clone(); + let hasher = client.hasher(); header_sub_fut_to_block_sub(self.clone(), async move { - let stream = client.backend().stream_all_block_headers().await?; + let stream = client.backend().stream_all_block_headers(hasher).await?; BlockStreamRes::Ok(stream) }) } @@ -111,8 +112,9 @@ where Client: Send + Sync + 'static, { let client = self.client.clone(); + let hasher = client.hasher(); header_sub_fut_to_block_sub(self.clone(), async move { - let stream = client.backend().stream_best_block_headers().await?; + let stream = client.backend().stream_best_block_headers(hasher).await?; BlockStreamRes::Ok(stream) }) } @@ -125,8 +127,12 @@ where Client: Send + Sync + 'static, { let client = self.client.clone(); + let hasher = client.hasher(); header_sub_fut_to_block_sub(self.clone(), async move { - let stream = client.backend().stream_finalized_block_headers().await?; + let stream = client + .backend() + .stream_finalized_block_headers(hasher) + .await?; BlockStreamRes::Ok(stream) }) } @@ -140,7 +146,9 @@ async fn header_sub_fut_to_block_sub( ) -> Result>, Error> where T: Config, - S: Future)>, Error>> + Send + 'static, + S: Future>)>, Error>> + + Send + + 'static, Client: OnlineClientT + Send + Sync + 'static, { let sub = sub.await?.then(move |header_and_ref| { diff --git a/subxt/src/blocks/extrinsic_types.rs b/subxt/src/blocks/extrinsic_types.rs index a4d87e681d..18fed219f7 100644 --- a/subxt/src/blocks/extrinsic_types.rs +++ b/subxt/src/blocks/extrinsic_types.rs @@ -5,7 +5,7 @@ use crate::{ blocks::block_types::{get_events, CachedEvents}, client::{OfflineClientT, OnlineClientT}, - config::Config, + config::{Config, HashFor}, error::Error, events, }; @@ -25,7 +25,7 @@ pub struct Extrinsics { inner: CoreExtrinsics, client: C, cached_events: CachedEvents, - hash: T::Hash, + hash: HashFor, } impl Extrinsics @@ -37,7 +37,7 @@ where client: C, extrinsics: Vec>, cached_events: CachedEvents, - hash: T::Hash, + hash: HashFor, ) -> Result { let inner = CoreExtrinsics::decode_from(extrinsics, client.metadata())?; Ok(Self { @@ -59,7 +59,7 @@ where } /// Return the block hash that these extrinsics are from. - pub fn block_hash(&self) -> T::Hash { + pub fn block_hash(&self) -> HashFor { self.hash } @@ -125,7 +125,7 @@ where pub struct ExtrinsicDetails { inner: CoreExtrinsicDetails, /// The block hash of this extrinsic (needed to fetch events). - block_hash: T::Hash, + block_hash: HashFor, /// Subxt client. client: C, /// Cached events. @@ -141,7 +141,7 @@ where pub(crate) fn new( inner: CoreExtrinsicDetails, client: C, - block_hash: T::Hash, + block_hash: HashFor, cached_events: CachedEvents, ) -> ExtrinsicDetails { ExtrinsicDetails { @@ -153,7 +153,7 @@ where } /// See [`subxt_core::blocks::ExtrinsicDetails::hash()`]. - pub fn hash(&self) -> T::Hash { + pub fn hash(&self) -> HashFor { self.inner.hash() } @@ -271,7 +271,7 @@ pub struct ExtrinsicEvents { // this type is returned from TxProgress things in the most // basic flows, so it's the only place people can access it // without complicating things for themselves). - ext_hash: T::Hash, + ext_hash: HashFor, // The index of the extrinsic: idx: u32, // All of the events in the block: @@ -281,7 +281,7 @@ pub struct ExtrinsicEvents { impl ExtrinsicEvents { /// Creates a new instance of `ExtrinsicEvents`. #[doc(hidden)] - pub fn new(ext_hash: T::Hash, idx: u32, events: events::Events) -> Self { + pub fn new(ext_hash: HashFor, idx: u32, events: events::Events) -> Self { Self { ext_hash, idx, @@ -295,7 +295,7 @@ impl ExtrinsicEvents { } /// Return the hash of the extrinsic. - pub fn extrinsic_hash(&self) -> T::Hash { + pub fn extrinsic_hash(&self) -> HashFor { self.ext_hash } diff --git a/subxt/src/client/offline_client.rs b/subxt/src/client/offline_client.rs index 8102a9b0a2..9f8a8f0d68 100644 --- a/subxt/src/client/offline_client.rs +++ b/subxt/src/client/offline_client.rs @@ -4,8 +4,14 @@ use crate::custom_values::CustomValuesClient; use crate::{ - blocks::BlocksClient, constants::ConstantsClient, events::EventsClient, - runtime_api::RuntimeApiClient, storage::StorageClient, tx::TxClient, Config, Metadata, + blocks::BlocksClient, + config::{Config, HashFor}, + constants::ConstantsClient, + events::EventsClient, + runtime_api::RuntimeApiClient, + storage::StorageClient, + tx::TxClient, + Metadata, }; use derive_where::derive_where; @@ -19,11 +25,14 @@ pub trait OfflineClientT: Clone + Send + Sync + 'static { fn metadata(&self) -> Metadata; /// Return the provided genesis hash. - fn genesis_hash(&self) -> T::Hash; + fn genesis_hash(&self) -> HashFor; /// Return the provided [`RuntimeVersion`]. fn runtime_version(&self) -> RuntimeVersion; + /// Return the hasher used on the chain. + fn hasher(&self) -> T::Hasher; + /// Return the [subxt_core::client::ClientState] (metadata, runtime version and genesis hash). fn client_state(&self) -> ClientState { ClientState { @@ -74,19 +83,22 @@ pub trait OfflineClientT: Clone + Send + Sync + 'static { #[derive_where(Debug, Clone)] pub struct OfflineClient { inner: Arc>, + hasher: T::Hasher, } impl OfflineClient { /// Construct a new [`OfflineClient`], providing /// the necessary runtime and compile-time arguments. pub fn new( - genesis_hash: T::Hash, + genesis_hash: HashFor, runtime_version: RuntimeVersion, metadata: impl Into, ) -> OfflineClient { let metadata = metadata.into(); + let hasher = ::new(&metadata); OfflineClient { + hasher, inner: Arc::new(ClientState { genesis_hash, runtime_version, @@ -96,7 +108,7 @@ impl OfflineClient { } /// Return the genesis hash. - pub fn genesis_hash(&self) -> T::Hash { + pub fn genesis_hash(&self) -> HashFor { self.inner.genesis_hash } @@ -110,6 +122,11 @@ impl OfflineClient { self.inner.metadata.clone() } + /// Return the hasher used for the chain. + pub fn hasher(&self) -> T::Hasher { + self.hasher + } + // Just a copy of the most important trait methods so that people // don't need to import the trait for most things: @@ -140,7 +157,7 @@ impl OfflineClient { } impl OfflineClientT for OfflineClient { - fn genesis_hash(&self) -> T::Hash { + fn genesis_hash(&self) -> HashFor { self.genesis_hash() } fn runtime_version(&self) -> RuntimeVersion { @@ -149,6 +166,9 @@ impl OfflineClientT for OfflineClient { fn metadata(&self) -> Metadata { self.metadata() } + fn hasher(&self) -> T::Hasher { + self.hasher() + } } // For ergonomics; cloning a client is deliberately fairly cheap (via Arc), diff --git a/subxt/src/client/online_client.rs b/subxt/src/client/online_client.rs index a49b720355..9824520fad 100644 --- a/subxt/src/client/online_client.rs +++ b/subxt/src/client/online_client.rs @@ -7,13 +7,14 @@ use crate::custom_values::CustomValuesClient; use crate::{ backend::{legacy::LegacyBackend, rpc::RpcClient, Backend, BackendExt, StreamOfResults}, blocks::{BlockRef, BlocksClient}, + config::{Config, HashFor}, constants::ConstantsClient, error::Error, events::EventsClient, runtime_api::RuntimeApiClient, storage::StorageClient, tx::TxClient, - Config, Metadata, + Metadata, }; use derive_where::derive_where; use futures::future; @@ -37,9 +38,10 @@ pub struct OnlineClient { #[derive_where(Debug)] struct Inner { - genesis_hash: T::Hash, + genesis_hash: HashFor, runtime_version: RuntimeVersion, metadata: Metadata, + hasher: T::Hasher, } impl std::fmt::Debug for OnlineClient { @@ -103,7 +105,7 @@ impl OnlineClient { /// If you're unsure what you're doing, prefer one of the alternate methods to instantiate /// a client. pub fn from_rpc_client_with( - genesis_hash: T::Hash, + genesis_hash: HashFor, runtime_version: RuntimeVersion, metadata: impl Into, rpc_client: impl Into, @@ -141,16 +143,22 @@ impl OnlineClient { /// If you're unsure what you're doing, prefer one of the alternate methods to instantiate /// a client. pub fn from_backend_with>( - genesis_hash: T::Hash, + genesis_hash: HashFor, runtime_version: RuntimeVersion, metadata: impl Into, backend: Arc, ) -> Result, Error> { + use subxt_core::config::Hasher; + + let metadata = metadata.into(); + let hasher = T::Hasher::new(&metadata); + Ok(OnlineClient { inner: Arc::new(RwLock::new(Inner { genesis_hash, runtime_version, - metadata: metadata.into(), + metadata, + hasher, })), backend, }) @@ -159,7 +167,7 @@ impl OnlineClient { /// Fetch the metadata from substrate using the runtime API. async fn fetch_metadata( backend: &dyn Backend, - block_hash: T::Hash, + block_hash: HashFor, ) -> Result { #[cfg(feature = "unstable-metadata")] { @@ -184,7 +192,7 @@ impl OnlineClient { /// Fetch the latest stable metadata from the node. async fn fetch_latest_stable_metadata( backend: &dyn Backend, - block_hash: T::Hash, + block_hash: HashFor, ) -> Result { // This is the latest stable metadata that subxt can utilize. const V15_METADATA_VERSION: u32 = 15; @@ -246,6 +254,11 @@ impl OnlineClient { ClientRuntimeUpdater(self.clone()) } + /// Return the hasher configured for hashing blocks and extrinsics. + pub fn hasher(&self) -> T::Hasher { + self.inner.read().expect("shouldn't be poisoned").hasher + } + /// Return the [`Metadata`] used in this client. pub fn metadata(&self) -> Metadata { let inner = self.inner.read().expect("shouldn't be poisoned"); @@ -264,7 +277,7 @@ impl OnlineClient { } /// Return the genesis hash. - pub fn genesis_hash(&self) -> T::Hash { + pub fn genesis_hash(&self) -> HashFor { let inner = self.inner.read().expect("shouldn't be poisoned"); inner.genesis_hash } @@ -275,7 +288,7 @@ impl OnlineClient { /// /// Setting a custom genesis hash may leave Subxt unable to /// submit valid transactions. - pub fn set_genesis_hash(&self, genesis_hash: T::Hash) { + pub fn set_genesis_hash(&self, genesis_hash: HashFor) { let mut inner = self.inner.write().expect("shouldn't be poisoned"); inner.genesis_hash = genesis_hash; } @@ -355,12 +368,15 @@ impl OfflineClientT for OnlineClient { fn metadata(&self) -> Metadata { self.metadata() } - fn genesis_hash(&self) -> T::Hash { + fn genesis_hash(&self) -> HashFor { self.genesis_hash() } fn runtime_version(&self) -> RuntimeVersion { self.runtime_version() } + fn hasher(&self) -> T::Hasher { + self.hasher() + } // This is provided by default, but we can optimise here and only lock once: fn client_state(&self) -> ClientState { let inner = self.inner.read().expect("shouldn't be poisoned"); @@ -501,10 +517,20 @@ impl Update { async fn wait_runtime_upgrade_in_finalized_block( client: &OnlineClient, runtime_version: &RuntimeVersion, -) -> Option, Error>> { +) -> Option>, Error>> { use scale_value::At; - let mut block_sub = match client.backend().stream_finalized_block_headers().await { + let hasher = client + .inner + .read() + .expect("Lock shouldn't be poisoned") + .hasher; + + let mut block_sub = match client + .backend() + .stream_finalized_block_headers(hasher) + .await + { Ok(s) => s, Err(err) => return Some(Err(err)), }; diff --git a/subxt/src/events/events_client.rs b/subxt/src/events/events_client.rs index c02a7e71d2..1c4f2c8c93 100644 --- a/subxt/src/events/events_client.rs +++ b/subxt/src/events/events_client.rs @@ -3,7 +3,12 @@ // see LICENSE for license details. use crate::backend::{Backend, BackendExt, BlockRef}; -use crate::{client::OnlineClientT, error::Error, events::Events, Config}; +use crate::{ + client::OnlineClientT, + config::{Config, HashFor}, + error::Error, + events::Events, +}; use derive_where::derive_where; use std::future::Future; @@ -38,7 +43,7 @@ where /// but may run into errors attempting to work with them. pub fn at( &self, - block_ref: impl Into>, + block_ref: impl Into>>, ) -> impl Future, Error>> + Send + 'static { self.at_or_latest(Some(block_ref.into())) } @@ -51,7 +56,7 @@ where /// Obtain events at some block hash. fn at_or_latest( &self, - block_ref: Option>, + block_ref: Option>>, ) -> impl Future, Error>> + Send + 'static { // Clone and pass the client in like this so that we can explicitly // return a Future that's Send + 'static, rather than tied to &self. @@ -82,7 +87,7 @@ fn system_events_key() -> [u8; 32] { // Get the event bytes from the provided client, at the provided block hash. pub(crate) async fn get_event_bytes( backend: &dyn Backend, - block_hash: T::Hash, + block_hash: HashFor, ) -> Result, Error> { Ok(backend .storage_fetch_value(system_events_key().to_vec(), block_hash) diff --git a/subxt/src/events/events_type.rs b/subxt/src/events/events_type.rs index b4a650d603..00156c2486 100644 --- a/subxt/src/events/events_type.rs +++ b/subxt/src/events/events_type.rs @@ -1,4 +1,7 @@ -use crate::{Config, Error, Metadata}; +use crate::{ + config::{Config, HashFor}, + Error, Metadata, +}; use derive_where::derive_where; use scale_decode::DecodeAsType; use subxt_core::events::{EventDetails as CoreEventDetails, Events as CoreEvents}; @@ -153,7 +156,7 @@ impl EventDetails { } /// Return the topics associated with this event. - pub fn topics(&self) -> &[T::Hash] { + pub fn topics(&self) -> &[HashFor] { self.inner.topics() } } diff --git a/subxt/src/events/mod.rs b/subxt/src/events/mod.rs index ab376efea4..1b8a8858d5 100644 --- a/subxt/src/events/mod.rs +++ b/subxt/src/events/mod.rs @@ -11,7 +11,10 @@ mod events_type; use crate::client::OnlineClientT; use crate::Error; -use subxt_core::{Config, Metadata}; +use subxt_core::{ + config::{Config, HashFor}, + Metadata, +}; pub use events_client::EventsClient; pub use events_type::{EventDetails, EventMetadataDetails, Events, Phase, StaticEvent}; @@ -19,7 +22,7 @@ pub use events_type::{EventDetails, EventMetadataDetails, Events, Phase, StaticE /// Creates a new [`Events`] instance by fetching the corresponding bytes at `block_hash` from the client. pub async fn new_events_from_client( metadata: Metadata, - block_hash: T::Hash, + block_hash: HashFor, client: C, ) -> Result, Error> where diff --git a/subxt/src/lib.rs b/subxt/src/lib.rs index 0db67754ca..57dc44263c 100644 --- a/subxt/src/lib.rs +++ b/subxt/src/lib.rs @@ -57,10 +57,10 @@ pub mod utils; /// Polkadot node. pub mod config { pub use subxt_core::config::{ - polkadot, substrate, transaction_extensions, BlockHash, Config, DefaultExtrinsicParams, - DefaultExtrinsicParamsBuilder, ExtrinsicParams, ExtrinsicParamsEncoder, Hasher, Header, - PolkadotConfig, PolkadotExtrinsicParams, SubstrateConfig, SubstrateExtrinsicParams, - TransactionExtension, + polkadot, substrate, transaction_extensions, Config, DefaultExtrinsicParams, + DefaultExtrinsicParamsBuilder, ExtrinsicParams, ExtrinsicParamsEncoder, Hash, HashFor, + Hasher, Header, PolkadotConfig, PolkadotExtrinsicParams, SubstrateConfig, + SubstrateExtrinsicParams, TransactionExtension, }; pub use subxt_core::error::ExtrinsicParamsError; } diff --git a/subxt/src/runtime_api/runtime_client.rs b/subxt/src/runtime_api/runtime_client.rs index dde9b5e3b3..c75063364a 100644 --- a/subxt/src/runtime_api/runtime_client.rs +++ b/subxt/src/runtime_api/runtime_client.rs @@ -4,7 +4,12 @@ use super::runtime_types::RuntimeApi; -use crate::{backend::BlockRef, client::OnlineClientT, error::Error, Config}; +use crate::{ + backend::BlockRef, + client::OnlineClientT, + config::{Config, HashFor}, + error::Error, +}; use derive_where::derive_where; use std::{future::Future, marker::PhantomData}; @@ -31,7 +36,7 @@ where Client: OnlineClientT, { /// Obtain a runtime API interface at some block hash. - pub fn at(&self, block_ref: impl Into>) -> RuntimeApi { + pub fn at(&self, block_ref: impl Into>>) -> RuntimeApi { RuntimeApi::new(self.client.clone(), block_ref.into()) } diff --git a/subxt/src/runtime_api/runtime_types.rs b/subxt/src/runtime_api/runtime_types.rs index c08ac7ef02..205b986744 100644 --- a/subxt/src/runtime_api/runtime_types.rs +++ b/subxt/src/runtime_api/runtime_types.rs @@ -6,8 +6,8 @@ use super::Payload; use crate::{ backend::{BackendExt, BlockRef}, client::OnlineClientT, + config::{Config, HashFor}, error::Error, - Config, }; use codec::Decode; use derive_where::derive_where; @@ -17,13 +17,13 @@ use std::{future::Future, marker::PhantomData}; #[derive_where(Clone; Client)] pub struct RuntimeApi { client: Client, - block_ref: BlockRef, + block_ref: BlockRef>, _marker: PhantomData, } impl RuntimeApi { /// Create a new [`RuntimeApi`] - pub(crate) fn new(client: Client, block_ref: BlockRef) -> Self { + pub(crate) fn new(client: Client, block_ref: BlockRef>) -> Self { Self { client, block_ref, diff --git a/subxt/src/storage/storage_client.rs b/subxt/src/storage/storage_client.rs index 99eb49f427..278246ca12 100644 --- a/subxt/src/storage/storage_client.rs +++ b/subxt/src/storage/storage_client.rs @@ -6,8 +6,8 @@ use super::storage_type::Storage; use crate::{ backend::BlockRef, client::{OfflineClientT, OnlineClientT}, + config::{Config, HashFor}, error::Error, - Config, }; use derive_where::derive_where; use std::{future::Future, marker::PhantomData}; @@ -65,7 +65,7 @@ where Client: OnlineClientT, { /// Obtain storage at some block hash. - pub fn at(&self, block_ref: impl Into>) -> Storage { + pub fn at(&self, block_ref: impl Into>>) -> Storage { Storage::new(self.client.clone(), block_ref.into()) } diff --git a/subxt/src/storage/storage_type.rs b/subxt/src/storage/storage_type.rs index 1736728e68..022e87b2f6 100644 --- a/subxt/src/storage/storage_type.rs +++ b/subxt/src/storage/storage_type.rs @@ -5,9 +5,9 @@ use crate::{ backend::{BackendExt, BlockRef}, client::OnlineClientT, + config::{Config, HashFor}, error::{Error, MetadataError, StorageAddressError}, metadata::DecodeWithMetadata, - Config, }; use codec::Decode; use derive_where::derive_where; @@ -23,13 +23,13 @@ pub use crate::backend::StreamOfResults; #[derive_where(Clone; Client)] pub struct Storage { client: Client, - block_ref: BlockRef, + block_ref: BlockRef>, _marker: PhantomData, } impl Storage { /// Create a new [`Storage`] - pub(crate) fn new(client: Client, block_ref: BlockRef) -> Self { + pub(crate) fn new(client: Client, block_ref: BlockRef>) -> Self { Self { client, block_ref, diff --git a/subxt/src/tx/tx_client.rs b/subxt/src/tx/tx_client.rs index 1dbf0aa82d..71848d1901 100644 --- a/subxt/src/tx/tx_client.rs +++ b/subxt/src/tx/tx_client.rs @@ -5,7 +5,7 @@ use crate::{ backend::{BackendExt, BlockRef, TransactionStatus}, client::{OfflineClientT, OnlineClientT}, - config::{Config, ExtrinsicParams, Header}, + config::{Config, ExtrinsicParams, HashFor, Header}, error::{BlockError, Error}, tx::{Payload, Signer as SignerT, TxProgress}, utils::PhantomDataSendSync, @@ -321,7 +321,7 @@ where &mut self, call: &Call, signer: &Signer, - ) -> Result + ) -> Result, Error> where Call: Payload, Signer: SignerT, @@ -344,7 +344,7 @@ where call: &Call, signer: &Signer, params: >::Params, - ) -> Result + ) -> Result, Error> where Call: Payload, Signer: SignerT, @@ -459,8 +459,8 @@ where } /// Calculate and return the hash of the transaction, based on the configured hasher. - pub fn hash(&self) -> T::Hash { - self.inner.hash() + pub fn hash(&self) -> HashFor { + self.inner.hash_with(self.client.hasher()) } /// Returns the SCALE encoded transaction bytes. @@ -503,7 +503,7 @@ where /// It's usually better to call `submit_and_watch` to get an idea of the progress of the /// submission and whether it's eventually successful or not. This call does not guarantee /// success, and is just sending the transaction to the chain. - pub async fn submit(&self) -> Result { + pub async fn submit(&self) -> Result, Error> { let ext_hash = self.hash(); let mut sub = self .client @@ -551,7 +551,7 @@ where /// Returns `Ok` with a [`ValidationResult`], which is the result of attempting to dry run the transaction. pub async fn validate_at( &self, - at: impl Into>, + at: impl Into>>, ) -> Result { let block_hash = at.into().hash(); @@ -614,7 +614,7 @@ async fn inject_account_nonce_and_block>( crate::blocks::get_account_nonce(client, account_id, block_ref.hash()).await?; params.inject_account_nonce(account_nonce); - params.inject_block(block_header.number().into(), block_header.hash()); + params.inject_block(block_header.number().into(), block_ref.hash()); Ok(()) } diff --git a/subxt/src/tx/tx_progress.rs b/subxt/src/tx/tx_progress.rs index d89790c0bb..4142b9a8b7 100644 --- a/subxt/src/tx/tx_progress.rs +++ b/subxt/src/tx/tx_progress.rs @@ -9,18 +9,18 @@ use std::task::Poll; use crate::{ backend::{BlockRef, StreamOfResults, TransactionStatus as BackendTxStatus}, client::OnlineClientT, + config::{Config, HashFor}, error::{DispatchError, Error, RpcError, TransactionError}, events::EventsClient, utils::strip_compact_prefix, - Config, }; use derive_where::derive_where; use futures::{Stream, StreamExt}; /// This struct represents a subscription to the progress of some transaction. pub struct TxProgress { - sub: Option>>, - ext_hash: T::Hash, + sub: Option>>>, + ext_hash: HashFor, client: C, } @@ -42,9 +42,9 @@ impl Unpin for TxProgress {} impl TxProgress { /// Instantiate a new [`TxProgress`] from a custom subscription. pub fn new( - sub: StreamOfResults>, + sub: StreamOfResults>>, client: C, - ext_hash: T::Hash, + ext_hash: HashFor, ) -> Self { Self { sub: Some(sub), @@ -54,7 +54,7 @@ impl TxProgress { } /// Return the hash of the extrinsic. - pub fn extrinsic_hash(&self) -> T::Hash { + pub fn extrinsic_hash(&self) -> HashFor { self.ext_hash } } @@ -219,13 +219,13 @@ impl TxStatus { /// This struct represents a transaction that has made it into a block. #[derive_where(Debug; C)] pub struct TxInBlock { - block_ref: BlockRef, - ext_hash: T::Hash, + block_ref: BlockRef>, + ext_hash: HashFor, client: C, } impl TxInBlock { - pub(crate) fn new(block_ref: BlockRef, ext_hash: T::Hash, client: C) -> Self { + pub(crate) fn new(block_ref: BlockRef>, ext_hash: HashFor, client: C) -> Self { Self { block_ref, ext_hash, @@ -234,12 +234,12 @@ impl TxInBlock { } /// Return the hash of the block that the transaction has made it into. - pub fn block_hash(&self) -> T::Hash { + pub fn block_hash(&self) -> HashFor { self.block_ref.hash() } /// Return the hash of the extrinsic that was submitted. - pub fn extrinsic_hash(&self) -> T::Hash { + pub fn extrinsic_hash(&self) -> HashFor { self.ext_hash } } @@ -281,6 +281,8 @@ impl> TxInBlock { /// **Note:** This has to download block details from the node and decode events /// from them. pub async fn fetch_events(&self) -> Result, Error> { + let hasher = self.client.hasher(); + let block_body = self .client .backend() @@ -295,7 +297,7 @@ impl> TxInBlock { let Ok((_, stripped)) = strip_compact_prefix(ext) else { return false; }; - let hash = T::Hasher::hash_of(&stripped); + let hash = hasher.hash_of(&stripped); hash == self.ext_hash }) // If we successfully obtain the block hash we think contains our @@ -321,12 +323,13 @@ mod test { use crate::{ backend::{StreamOfResults, TransactionStatus}, client::{OfflineClientT, OnlineClientT}, + config::{Config, HashFor}, tx::TxProgress, - Config, Error, SubstrateConfig, + Error, SubstrateConfig, }; type MockTxProgress = TxProgress; - type MockHash = ::Hash; + type MockHash = HashFor; type MockSubstrateTxStatus = TransactionStatus; /// a mock client to satisfy trait bounds in tests @@ -346,6 +349,10 @@ mod test { unimplemented!("just a mock impl to satisfy trait bounds") } + fn hasher(&self) -> ::Hasher { + unimplemented!("just a mock impl to satisfy trait bounds") + } + fn client_state(&self) -> subxt_core::client::ClientState { unimplemented!("just a mock impl to satisfy trait bounds") } diff --git a/testing/integration-tests/src/full_client/client/archive_rpcs.rs b/testing/integration-tests/src/full_client/client/archive_rpcs.rs index e41a9af7a0..781a171c70 100644 --- a/testing/integration-tests/src/full_client/client/archive_rpcs.rs +++ b/testing/integration-tests/src/full_client/client/archive_rpcs.rs @@ -16,7 +16,6 @@ use subxt::{ client::OnlineClient, config::{Config, Hasher}, utils::AccountId32, - SubstrateConfig, }; use subxt_rpcs::methods::chain_head::{ ArchiveStorageEventItem, Bytes, StorageQuery, StorageQueryType, @@ -178,6 +177,7 @@ async fn archive_v1_storage() { let ctx = test_context().await; let rpc = ctx.chainhead_rpc_methods().await; let api = ctx.client(); + let hasher = api.hasher(); let mut blocks = fetch_finalized_blocks(&ctx, 3).await; while let Some(block) = blocks.next().await { @@ -236,9 +236,7 @@ async fn archive_v1_storage() { ArchiveStorageEventItem { key: Bytes(account_info_addr), value: None, - hash: Some(::Hasher::hash( - &subxt_account_info - )), + hash: Some(hasher.hash(&subxt_account_info)), closest_descendant_merkle_value: None, child_trie_key: None } diff --git a/testing/integration-tests/src/full_client/client/chain_head_rpcs.rs b/testing/integration-tests/src/full_client/client/chain_head_rpcs.rs index c938e87dd7..29afda0b60 100644 --- a/testing/integration-tests/src/full_client/client/chain_head_rpcs.rs +++ b/testing/integration-tests/src/full_client/client/chain_head_rpcs.rs @@ -15,7 +15,6 @@ use futures::Stream; use subxt::{ config::Hasher, utils::{AccountId32, MultiAddress}, - SubstrateConfig, }; use subxt_rpcs::methods::chain_head::{ FollowEvent, Initialized, MethodResponse, RuntimeEvent, RuntimeVersionEvent, StorageQuery, @@ -329,6 +328,7 @@ async fn transaction_v1_broadcast() { let ctx = test_context().await; let api = ctx.client(); + let hasher = api.hasher(); let rpc = ctx.chainhead_rpc_methods().await; let tx_payload = node_runtime::tx() @@ -374,7 +374,7 @@ async fn transaction_v1_broadcast() { let Some(ext) = block_extrinsics .iter() - .find(|ext| ::Hasher::hash(ext.bytes()) == tx_hash) + .find(|ext| hasher.hash(ext.bytes()) == tx_hash) else { continue; }; diff --git a/testing/integration-tests/src/full_client/frame/contracts.rs b/testing/integration-tests/src/full_client/frame/contracts.rs index f2f942b147..77f24ac159 100644 --- a/testing/integration-tests/src/full_client/frame/contracts.rs +++ b/testing/integration-tests/src/full_client/frame/contracts.rs @@ -12,7 +12,12 @@ use crate::{ subxt_test, test_context, TestClient, TestConfig, TestContext, }; use subxt::ext::futures::StreamExt; -use subxt::{tx::TxProgress, utils::MultiAddress, Config, Error}; +use subxt::{ + config::{Config, HashFor}, + tx::TxProgress, + utils::MultiAddress, + Error, +}; use subxt_signer::sr25519::{self, dev}; struct ContractsTestContext { @@ -20,7 +25,7 @@ struct ContractsTestContext { signer: sr25519::Keypair, } -type Hash = ::Hash; +type Hash = HashFor; type AccountId = ::AccountId; /// A dummy contract which does nothing at all. diff --git a/testing/wasm-rpc-tests/tests/wasm.rs b/testing/wasm-rpc-tests/tests/wasm.rs index 8302892695..f87f6d9675 100644 --- a/testing/wasm-rpc-tests/tests/wasm.rs +++ b/testing/wasm-rpc-tests/tests/wasm.rs @@ -31,8 +31,9 @@ async fn wasm_ws_transport_works() { let client = subxt::client::OnlineClient::::from_url("ws://127.0.0.1:9944") .await .unwrap(); + let hasher = client.hasher(); - let mut stream = client.backend().stream_best_block_headers().await.unwrap(); + let mut stream = client.backend().stream_best_block_headers(hasher).await.unwrap(); assert!(stream.next().await.is_some()); } @@ -41,8 +42,9 @@ async fn wasm_ws_chainhead_works() { let rpc = subxt::backend::rpc::RpcClient::from_url("ws://127.0.0.1:9944").await.unwrap(); let backend = subxt::backend::chain_head::ChainHeadBackendBuilder::new().build_with_background_driver(rpc); let client = subxt::client::OnlineClient::::from_backend(std::sync::Arc::new(backend)).await.unwrap(); + let hasher = client.hasher(); - let mut stream = client.backend().stream_best_block_headers().await.unwrap(); + let mut stream = client.backend().stream_best_block_headers(hasher).await.unwrap(); assert!(stream.next().await.is_some()); } @@ -50,7 +52,9 @@ async fn wasm_ws_chainhead_works() { async fn reconnecting_rpc_client_ws_transport_works() { let rpc = ReconnectingRpcClient::builder().build("ws://127.0.0.1:9944".to_string()).await.unwrap(); let client = subxt::client::OnlineClient::::from_rpc_client(rpc.clone()).await.unwrap(); - let mut stream = client.backend().stream_best_block_headers().await.unwrap(); + let hasher = client.hasher(); + + let mut stream = client.backend().stream_best_block_headers(hasher).await.unwrap(); assert!(stream.next().await.is_some()); } diff --git a/utils/strip-metadata/src/lib.rs b/utils/strip-metadata/src/lib.rs index 1b9f3a6dd4..8a8527f708 100644 --- a/utils/strip-metadata/src/lib.rs +++ b/utils/strip-metadata/src/lib.rs @@ -75,10 +75,36 @@ impl StripMetadata for v16::RuntimeMetadataV16 { PalletFilter: Fn(&str) -> bool, RuntimeApiFilter: Fn(&str) -> bool, { - // Throw away pallets and runtime APIs we don't care about: - self.pallets.retain(|pallet| keep_pallet(&pallet.name)); + // Throw away pallets and runtime APIs we don't care about. + // Keep the System pallet, because it has some associated types that we care about in Subxt. + self.pallets + .retain(|pallet| pallet.name == "System" || keep_pallet(&pallet.name)); self.apis.retain(|api| keep_runtime_api(&api.name)); + // If the user asked to strip the System pallet, we'll strip most things from it but keep the + // associated types, because Subxt makes use of them. + if !keep_pallet("System") { + if let Some(system_pallet) = self.pallets.iter_mut().find(|p| p.name == "System") { + let index = system_pallet.index; + let associated_types = core::mem::take(&mut system_pallet.associated_types); + + *system_pallet = v16::PalletMetadata { + name: "System".to_string(), + index, + associated_types, + // Everything else is empty: + storage: None, + calls: None, + event: None, + constants: vec![], + error: None, + view_functions: vec![], + docs: vec![], + deprecation_info: v16::DeprecationStatus::NotDeprecated, + }; + } + } + // Now, only retain types we care about in the registry: retain_types(self); }