From b75ce69b763e5ae3b9e89c5ee12cb4606242363b Mon Sep 17 00:00:00 2001 From: James Wilson Date: Tue, 9 Dec 2025 16:59:04 +0000 Subject: [PATCH] Everything has lifetime from ClientAtBlock --- new/src/client.rs | 32 +++--- new/src/constants.rs | 10 +- new/src/custom_values.rs | 12 +- new/src/events.rs | 56 ++++----- new/src/extrinsics.rs | 104 ++++++++--------- .../extrinsic_transaction_extensions.rs | 32 +++--- new/src/runtime_apis.rs | 12 +- new/src/storage.rs | 20 ++-- new/src/transactions.rs | 106 ++++++++++-------- new/src/transactions/transaction_progress.rs | 79 +++++++------ new/src/view_functions.rs | 12 +- 11 files changed, 249 insertions(+), 226 deletions(-) diff --git a/new/src/client.rs b/new/src/client.rs index b5cea2eebd..76e3cafaad 100644 --- a/new/src/client.rs +++ b/new/src/client.rs @@ -39,42 +39,42 @@ where Client: OfflineClientAtBlockT, { /// Construct and submit transactions. - pub fn tx(&self) -> TransactionsClient { - TransactionsClient::new(self.client.clone()) + pub fn tx(&self) -> TransactionsClient<'_, T, Client> { + TransactionsClient::new(&self.client) } /// Access storage at this block. - pub fn storage(&self) -> StorageClient { - StorageClient::new(self.client.clone()) + pub fn storage(&self) -> StorageClient<'_, T, Client> { + StorageClient::new(&self.client) } /// Access constants at this block. - pub fn constants(&self) -> ConstantsClient { - ConstantsClient::new(self.client.clone()) + pub fn constants(&self) -> ConstantsClient<'_, T, Client> { + ConstantsClient::new(&self.client) } /// Access custom values at this block. - pub fn custom_values(&self) -> CustomValuesClient { - CustomValuesClient::new(self.client.clone()) + pub fn custom_values(&self) -> CustomValuesClient<'_, T, Client> { + CustomValuesClient::new(&self.client) } /// Work with the extrinsics in this block. - pub fn extrinsics(&self) -> ExtrinsicsClient { - ExtrinsicsClient::new(self.client.clone()) + pub fn extrinsics(&self) -> ExtrinsicsClient<'_, T, Client> { + ExtrinsicsClient::new(&self.client) } /// Work with the events at this block. - pub fn events(&self) -> EventsClient { - EventsClient::new(self.client.clone()) + pub fn events(&self) -> EventsClient<'_, T, Client> { + EventsClient::new(&self.client) } /// Access runtime APIs at this block. - pub fn runtime_apis(&self) -> RuntimeApisClient { - RuntimeApisClient::new(self.client.clone()) + pub fn runtime_apis(&self) -> RuntimeApisClient<'_, T, Client> { + RuntimeApisClient::new(&self.client) } - pub fn view_functions(&self) -> ViewFunctionsClient { - ViewFunctionsClient::new(self.client.clone()) + pub fn view_functions(&self) -> ViewFunctionsClient<'_, T, Client> { + ViewFunctionsClient::new(&self.client) } /// Obtain a reference to the metadata. diff --git a/new/src/constants.rs b/new/src/constants.rs index d26a24ff26..d01bc0218e 100644 --- a/new/src/constants.rs +++ b/new/src/constants.rs @@ -10,13 +10,13 @@ pub mod address; /// A client for working with storage entries. #[derive(Clone)] -pub struct ConstantsClient { - client: Client, +pub struct ConstantsClient<'atblock, T, Client> { + client: &'atblock Client, marker: PhantomData, } -impl ConstantsClient { - pub(crate) fn new(client: Client) -> Self { +impl<'atblock, T, Client> ConstantsClient<'atblock, T, Client> { + pub(crate) fn new(client: &'atblock Client) -> Self { ConstantsClient { client, marker: PhantomData, @@ -24,7 +24,7 @@ impl ConstantsClient { } } -impl> ConstantsClient { +impl<'atblock, T: Config, Client: OfflineClientAtBlockT> ConstantsClient<'atblock, T, Client> { /// Run the validation logic against some constant address you'd like to access. Returns `Ok(())` /// if the address is valid (or if it's not possible to check since the address has no validation hash). /// Return an error if the address was not valid or something went wrong trying to validate it (ie diff --git a/new/src/custom_values.rs b/new/src/custom_values.rs index dc785cb012..435f62d4d6 100644 --- a/new/src/custom_values.rs +++ b/new/src/custom_values.rs @@ -11,14 +11,14 @@ pub mod address; /// A client for accessing custom values stored in the metadata. #[derive_where(Clone; Client)] -pub struct CustomValuesClient { - client: Client, +pub struct CustomValuesClient<'atblock, T, Client> { + client: &'atblock Client, marker: std::marker::PhantomData, } -impl CustomValuesClient { +impl<'atblock, T, Client> CustomValuesClient<'atblock, T, Client> { /// Create a new [`CustomValuesClient`]. - pub(crate) fn new(client: Client) -> Self { + pub(crate) fn new(client: &'atblock Client) -> Self { Self { client, marker: std::marker::PhantomData, @@ -26,7 +26,9 @@ impl CustomValuesClient { } } -impl> CustomValuesClient { +impl<'atblock, T: Config, Client: OfflineClientAtBlockT> + CustomValuesClient<'atblock, T, Client> +{ /// Run the validation logic against some custom value address you'd like to access. Returns `Ok(())` /// if the address is valid (or if it's not possible to check since the address has no validation hash). /// Returns an error if the address was not valid (wrong name, type or raw bytes) diff --git a/new/src/events.rs b/new/src/events.rs index 772678ecb5..83dc7b4f38 100644 --- a/new/src/events.rs +++ b/new/src/events.rs @@ -13,13 +13,13 @@ use subxt_metadata::Metadata; pub use decode_as_event::DecodeAsEvent; /// A client for working with events. -pub struct EventsClient { - client: Client, +pub struct EventsClient<'atblock, T, Client> { + client: &'atblock Client, marker: PhantomData, } -impl EventsClient { - pub(crate) fn new(client: Client) -> Self { +impl<'atblock, T, Client> EventsClient<'atblock, T, Client> { + pub(crate) fn new(client: &'atblock Client) -> Self { EventsClient { client, marker: PhantomData, @@ -27,12 +27,12 @@ impl EventsClient { } } -impl> EventsClient { +impl<'atblock, T: Config, Client: OfflineClientAtBlockT> EventsClient<'atblock, T, Client> { /// Work with the block event bytes given. /// /// No attempt to validate the provided bytes is made here; if invalid bytes are /// provided then attempting to iterate and decode them will fail. - pub fn from_bytes(&self, event_bytes: Vec) -> Events { + pub fn from_bytes(&self, event_bytes: Vec) -> Events<'atblock, T> { // event_bytes is a SCALE encoded vector of events. So, pluck the // compact encoded length from the front, leaving the remaining bytes // for our iterating to decode. @@ -46,8 +46,8 @@ impl> EventsClient { let start_idx = event_bytes.len() - cursor.len(); Events { - metadata: self.client.metadata(), - event_bytes, + metadata: self.client.metadata_ref(), + event_bytes: event_bytes.into(), start_idx, num_events, marker: PhantomData, @@ -55,10 +55,10 @@ impl> EventsClient { } } -impl> EventsClient { +impl<'atblock, T: Config, Client: OnlineClientAtBlockT> EventsClient<'atblock, T, Client> { /// Fetch the events at this block. - pub async fn fetch(&self) -> Result, EventsError> { - let client = &self.client; + pub async fn fetch(&self) -> Result, EventsError> { + let client = self.client; // Fetch the bytes. Ensure things work if we get 0 bytes back. let block_hash = client.block_hash(); @@ -75,18 +75,18 @@ impl> EventsClient { /// The events at some block. #[derive(Debug)] -pub struct Events { - metadata: Arc, +pub struct Events<'atblock, T> { + metadata: &'atblock Metadata, // Note; raw event bytes are prefixed with a Compact containing // the number of events to be decoded. The start_idx reflects that, so // that we can skip over those bytes when decoding them - event_bytes: Vec, + event_bytes: Arc<[u8]>, start_idx: usize, num_events: u32, marker: core::marker::PhantomData, } -impl Events { +impl<'atblock, T: Config> Events<'atblock, T> { /// The number of events. pub fn len(&self) -> u32 { self.num_events @@ -108,9 +108,11 @@ impl Events { /// details. If an error occurs, all subsequent iterations return `None`. // Dev note: The returned iterator is 'static + Send so that we can box it up and make // use of it with our `FilterEvents` stuff. - pub fn iter(&'_ self) -> impl Iterator, EventsError>> + Send + Sync { + pub fn iter( + &'_ self, + ) -> impl Iterator, EventsError>> + Send + Sync { // The event bytes ignoring the compact encoded length on the front: - let event_bytes = &*self.event_bytes; + let event_bytes = self.event_bytes.clone(); let metadata = &*self.metadata; let num_events = self.num_events; @@ -120,7 +122,7 @@ impl Events { if event_bytes.len() <= pos || num_events == index { None } else { - match Event::decode_from(metadata, event_bytes, pos, index) { + match Event::decode_from(metadata, event_bytes.clone(), pos, index) { Ok(event_details) => { // Skip over decoded bytes in next iteration: pos += event_details.bytes().len(); @@ -171,12 +173,12 @@ pub enum Phase { /// The event details. #[derive(Debug, Clone)] -pub struct Event<'events, T: Config> { - pallet_name: &'events str, - event_name: &'events str, - metadata: &'events Metadata, +pub struct Event<'atblock, T: Config> { + pallet_name: &'atblock str, + event_name: &'atblock str, + metadata: &'atblock Metadata, // all of the event bytes (not just this one). - all_bytes: &'events [u8], + all_bytes: Arc<[u8]>, // event phase. phase: Phase, /// The index of the event in the list of events in a given block. @@ -195,14 +197,14 @@ pub struct Event<'events, T: Config> { topics: Vec>, } -impl<'events, T: Config> Event<'events, T> { +impl<'atblock, T: Config> Event<'atblock, T> { /// Attempt to dynamically decode a single event from our events input. fn decode_from( - metadata: &'events Metadata, - all_bytes: &'events [u8], + metadata: &'atblock Metadata, + all_bytes: Arc<[u8]>, start_idx: usize, index: u32, - ) -> Result, EventsError> { + ) -> Result, EventsError> { let input = &mut &all_bytes[start_idx..]; let phase = Phase::decode(input).map_err(EventsError::CannotDecodePhase)?; diff --git a/new/src/extrinsics.rs b/new/src/extrinsics.rs index 80670740a0..35dbeda472 100644 --- a/new/src/extrinsics.rs +++ b/new/src/extrinsics.rs @@ -19,13 +19,13 @@ pub use extrinsic_transaction_extensions::{ }; /// A client for working with extrinsics. -pub struct ExtrinsicsClient { - client: Client, +pub struct ExtrinsicsClient<'atblock, T, Client> { + client: &'atblock Client, marker: PhantomData, } -impl ExtrinsicsClient { - pub(crate) fn new(client: Client) -> Self { +impl<'atblock, T, Client> ExtrinsicsClient<'atblock, T, Client> { + pub(crate) fn new(client: &'atblock Client) -> Self { ExtrinsicsClient { client, marker: PhantomData, @@ -33,24 +33,24 @@ impl ExtrinsicsClient { } } -impl> ExtrinsicsClient { +impl<'atblock, T: Config, Client: OfflineClientAtBlockT> ExtrinsicsClient<'atblock, T, Client> { /// Work with the block body bytes given. /// /// No attempt to validate the provided bytes is made here; if invalid bytes are /// provided then attempting to iterate and decode them will fail. - pub async fn from_bytes(&self, extrinsics: Vec>) -> Extrinsics { + pub async fn from_bytes(&self, extrinsics: Vec>) -> Extrinsics<'atblock, T, Client> { Extrinsics { - client: self.client.clone(), + client: self.client, extrinsics: Arc::new(extrinsics), marker: PhantomData, } } } -impl> ExtrinsicsClient { +impl<'atblock, T: Config, Client: OnlineClientAtBlockT> ExtrinsicsClient<'atblock, T, Client> { /// Fetch the extrinsics at this block. - pub async fn fetch(&self) -> Result, ExtrinsicError> { - let client = &self.client; + pub async fn fetch(&self) -> Result, ExtrinsicError> { + let client = self.client; let block_hash = client.block_hash(); let extrinsics = client .backend() @@ -60,7 +60,7 @@ impl> ExtrinsicsClient { .ok_or_else(|| ExtrinsicError::BlockNotFound(block_hash.into()))?; Ok(Extrinsics { - client: client.clone(), + client, extrinsics: Arc::new(extrinsics), marker: PhantomData, }) @@ -69,13 +69,13 @@ impl> ExtrinsicsClient { /// The extrinsics in a block. #[derive(Debug, Clone)] -pub struct Extrinsics { - client: C, +pub struct Extrinsics<'atblock, T, C> { + client: &'atblock C, extrinsics: Arc>>, marker: PhantomData, } -impl> Extrinsics { +impl<'atblock, T: Config, C: OfflineClientAtBlockT> Extrinsics<'atblock, T, C> { /// The number of extrinsics. pub fn len(&self) -> usize { self.extrinsics.len() @@ -94,7 +94,8 @@ impl> Extrinsics { ) -> impl Iterator, ExtrinsicDecodeErrorAt>> { let hasher = self.client.hasher(); let metadata = self.client.metadata_ref(); - let client = &self.client; + let client = self.client; + let all_extrinsic_bytes = self.extrinsics.clone(); self.extrinsics .iter() @@ -122,8 +123,8 @@ impl> Extrinsics { Ok(Extrinsic { client: client, index: extrinsic_index, - info, - extrinsic: &**extrinsic_bytes, + info: Arc::new(info), + extrinsics: Arc::clone(&all_extrinsic_bytes), hasher, metadata, }) @@ -148,29 +149,28 @@ impl> Extrinsics { } /// A single extrinsic in a block. -pub struct Extrinsic<'extrinsics, T: Config, C> { - client: &'extrinsics C, +pub struct Extrinsic<'atblock, T: Config, C> { + client: &'atblock C, /// The index of the extrinsic in the block. index: usize, /// Information about the extrinsic - info: ExtrinsicInfo<'extrinsics, u32>, - /// Extrinsic bytes and decode info. - extrinsic: &'extrinsics [u8], + info: Arc>, + /// All extrinsic bytes. use the index to select the correct bytes. + extrinsics: Arc>>, /// Hash the extrinsic if we want. - hasher: &'extrinsics T::Hasher, + hasher: &'atblock T::Hasher, /// Subxt metadata to fetch the extrinsic metadata. - metadata: &'extrinsics Metadata, + metadata: &'atblock Metadata, } -impl<'extrinsics, T, C> Extrinsic<'extrinsics, T, C> +impl<'atblock, T, C> Extrinsic<'atblock, T, C> where T: Config, C: OfflineClientAtBlockT, { /// Calculate and return the hash of the extrinsic, based on the configured hasher. pub fn hash(&self) -> HashFor { - // Use hash(), not hash_of(), because we don't want to double encode the bytes. - self.hasher.hash(self.extrinsic) + self.hasher.hash(&self.extrinsics[self.index]) } /// Is the extrinsic signed? @@ -204,8 +204,8 @@ where } /// Return the extrinsic bytes. - pub fn bytes(&self) -> &'extrinsics [u8] { - self.extrinsic + pub fn bytes(&self) -> &[u8] { + &self.extrinsics[self.index] } /// Return only the bytes representing this extrinsic call: @@ -216,8 +216,8 @@ where /// # Note /// /// Please use [`Self::bytes`] if you want to get all extrinsic bytes. - pub fn call_data_bytes(&self) -> &'extrinsics [u8] { - &self.extrinsic[self.info.call_data_range()] + pub fn call_data_bytes(&self) -> &[u8] { + &self.bytes()[self.info.call_data_range()] } /// Return the bytes representing the fields stored in this extrinsic. @@ -226,8 +226,8 @@ where /// /// This is a subset of [`Self::call_bytes`] that does not include the /// first two bytes that denote the pallet index and the variant index. - pub fn call_data_field_bytes(&self) -> &'extrinsics [u8] { - &self.extrinsic[self.info.call_data_args_range()] + pub fn call_data_field_bytes(&self) -> &[u8] { + &self.bytes()[self.info.call_data_args_range()] } /// Return only the bytes of the address that signed this extrinsic. @@ -235,17 +235,17 @@ where /// # Note /// /// Returns `None` if the extrinsic is not signed. - pub fn address_bytes(&self) -> Option<&'extrinsics [u8]> { + pub fn address_bytes(&self) -> Option<&[u8]> { self.info .signature_payload() - .map(|s| &self.extrinsic[s.address_range()]) + .map(|s| &self.bytes()[s.address_range()]) } /// Returns Some(signature_bytes) if the extrinsic was signed otherwise None is returned. - pub fn signature_bytes(&self) -> Option<&'extrinsics [u8]> { + pub fn signature_bytes(&self) -> Option<&[u8]> { self.info .signature_payload() - .map(|s| &self.extrinsic[s.signature_range()]) + .map(|s| &self.bytes()[s.signature_range()]) } /// Returns the signed extension `extra` bytes of the extrinsic. @@ -257,16 +257,19 @@ where pub fn transaction_extensions_bytes(&self) -> Option<&[u8]> { self.info .transaction_extension_payload() - .map(|t| &self.extrinsic[t.range()]) + .map(|t| &self.bytes()[t.range()]) } /// Returns `None` if the extrinsic is not signed. pub fn transaction_extensions( &self, - ) -> Option> { + ) -> Option> { + let bytes = self.bytes(); + let metadata = self.metadata; + self.info .transaction_extension_payload() - .map(|t| ExtrinsicTransactionExtensions::new(self.extrinsic, self.metadata, t)) + .map(move |t| ExtrinsicTransactionExtensions::new(bytes, metadata, t)) } /// Return true if this [`Extrinsic`] matches the provided type. @@ -334,20 +337,20 @@ where } } -impl<'extrinsics, T, C> Extrinsic<'extrinsics, T, C> +impl<'atblock, T, C> Extrinsic<'atblock, T, C> where T: Config, C: OnlineClientAtBlockT, { /// The events associated with the extrinsic. - pub async fn events(&self) -> Result, EventsError> { - ExtrinsicEvents::fetch(self.client.clone(), self.hash(), self.index()).await + pub async fn events(&self) -> Result, EventsError> { + ExtrinsicEvents::fetch(self.client, self.hash(), self.index()).await } } /// The events associated with a given extrinsic. #[derive(Debug)] -pub struct ExtrinsicEvents { +pub struct ExtrinsicEvents<'atblock, T: Config> { // The hash of the extrinsic (handy to expose here because // this type is returned from TxProgress things in the most // basic flows, so it's the only place people can access it @@ -356,19 +359,16 @@ pub struct ExtrinsicEvents { // The index of the extrinsic: extrinsic_index: usize, // All of the events in the block: - events: crate::events::Events, + events: crate::events::Events<'atblock, T>, } -impl ExtrinsicEvents { +impl<'atblock, T: Config> ExtrinsicEvents<'atblock, T> { pub(crate) async fn fetch( - client: impl OnlineClientAtBlockT, + client: &'atblock impl OnlineClientAtBlockT, extrinsic_hash: HashFor, extrinsic_index: usize, ) -> Result { - let events = crate::client::ClientAtBlock::new(client) - .events() - .fetch() - .await?; + let events = crate::events::EventsClient::new(client).fetch().await?; Ok(ExtrinsicEvents { extrinsic_hash, extrinsic_index, @@ -387,7 +387,7 @@ impl ExtrinsicEvents { } /// Return all of the events in the block that the extrinsic is in. - pub fn all_events_in_block(&self) -> &events::Events { + pub fn all_events_in_block(&self) -> &events::Events<'atblock, T> { &self.events } diff --git a/new/src/extrinsics/extrinsic_transaction_extensions.rs b/new/src/extrinsics/extrinsic_transaction_extensions.rs index e1dc37d0b5..169ec5d731 100644 --- a/new/src/extrinsics/extrinsic_transaction_extensions.rs +++ b/new/src/extrinsics/extrinsic_transaction_extensions.rs @@ -10,20 +10,18 @@ use subxt_metadata::Metadata; /// The signed extensions of an extrinsic. #[derive(Debug, Clone)] -pub struct ExtrinsicTransactionExtensions<'extrinsics, 'extrinsic, T: Config> { - bytes: &'extrinsics [u8], - metadata: &'extrinsics Metadata, - decoded_info: &'extrinsic ExtrinsicExtensionsInfo<'extrinsics, u32>, +pub struct ExtrinsicTransactionExtensions<'atblock, 'extrinsic, T: Config> { + bytes: &'extrinsic [u8], + metadata: &'atblock Metadata, + decoded_info: &'extrinsic ExtrinsicExtensionsInfo<'atblock, u32>, marker: core::marker::PhantomData, } -impl<'extrinsics, 'extrinsic, T: Config> - ExtrinsicTransactionExtensions<'extrinsics, 'extrinsic, T> -{ +impl<'atblock, 'extrinsic, T: Config> ExtrinsicTransactionExtensions<'atblock, 'extrinsic, T> { pub(crate) fn new( - bytes: &'extrinsics [u8], - metadata: &'extrinsics Metadata, - decoded_info: &'extrinsic ExtrinsicExtensionsInfo<'extrinsics, u32>, + bytes: &'extrinsic [u8], + metadata: &'atblock Metadata, + decoded_info: &'extrinsic ExtrinsicExtensionsInfo<'atblock, u32>, ) -> Self { Self { bytes, @@ -36,10 +34,10 @@ impl<'extrinsics, 'extrinsic, T: Config> /// Returns an iterator over each of the signed extension details of the extrinsic. pub fn iter( &self, - ) -> impl Iterator> { + ) -> impl Iterator> { self.decoded_info .iter() - .map(|s| ExtrinsicTransactionExtension { + .map(move |s| ExtrinsicTransactionExtension { bytes: &self.bytes[s.range()], ty_id: *s.ty(), identifier: s.name(), @@ -85,17 +83,17 @@ impl<'extrinsics, 'extrinsic, T: Config> /// A single signed extension #[derive(Debug, Clone)] -pub struct ExtrinsicTransactionExtension<'extrinsics, 'extrinsic, T: Config> { - bytes: &'extrinsics [u8], +pub struct ExtrinsicTransactionExtension<'atblock, 'extrinsic, T: Config> { + bytes: &'extrinsic [u8], ty_id: u32, identifier: &'extrinsic str, - metadata: &'extrinsics Metadata, + metadata: &'atblock Metadata, _marker: core::marker::PhantomData, } -impl<'extrinsics, 'extrinsic, T: Config> ExtrinsicTransactionExtension<'extrinsics, 'extrinsic, T> { +impl<'atblock, 'extrinsic, T: Config> ExtrinsicTransactionExtension<'atblock, 'extrinsic, T> { /// The bytes representing this signed extension. - pub fn bytes(&self) -> &'extrinsics [u8] { + pub fn bytes(&self) -> &'extrinsic [u8] { self.bytes } diff --git a/new/src/runtime_apis.rs b/new/src/runtime_apis.rs index 49fdb12ab9..c6362a22dd 100644 --- a/new/src/runtime_apis.rs +++ b/new/src/runtime_apis.rs @@ -14,14 +14,14 @@ pub mod payload; /// Execute runtime API calls. #[derive_where(Clone; Client)] -pub struct RuntimeApisClient { - client: Client, +pub struct RuntimeApisClient<'atblock, T: Config, Client> { + client: &'atblock Client, marker: PhantomData, } -impl RuntimeApisClient { +impl<'atblock, T: Config, Client> RuntimeApisClient<'atblock, T, Client> { /// Create a new [`RuntimeApi`] - pub(crate) fn new(client: Client) -> Self { + pub(crate) fn new(client: &'atblock Client) -> Self { Self { client, marker: PhantomData, @@ -29,7 +29,7 @@ impl RuntimeApisClient { } } -impl RuntimeApisClient +impl<'atblock, T, Client> RuntimeApisClient<'atblock, T, Client> where T: Config, Client: OfflineClientAtBlockT, @@ -85,7 +85,7 @@ where } } -impl RuntimeApisClient +impl<'atblock, T, Client> RuntimeApisClient<'atblock, T, Client> where T: Config, Client: OnlineClientAtBlockT, diff --git a/new/src/storage.rs b/new/src/storage.rs index debdf2e1af..50513b89b3 100644 --- a/new/src/storage.rs +++ b/new/src/storage.rs @@ -23,13 +23,13 @@ pub mod address; /// A client for working with storage entries. #[derive(Clone)] -pub struct StorageClient { - client: Client, +pub struct StorageClient<'atblock, T, Client> { + client: &'atblock Client, marker: PhantomData, } -impl StorageClient { - pub(crate) fn new(client: Client) -> Self { +impl<'atblock, T, Client> StorageClient<'atblock, T, Client> { + pub(crate) fn new(client: &'atblock Client) -> Self { StorageClient { client, marker: PhantomData, @@ -37,7 +37,7 @@ impl StorageClient { } } -impl> StorageClient { +impl<'atblock, T: Config, Client: OfflineClientAtBlockT> StorageClient<'atblock, T, Client> { /// When the provided `address` is statically generated via the `#[subxt]` macro, this validates /// that the shape of the storage value is the same as the shape expected by the static address. /// @@ -74,27 +74,27 @@ impl> StorageClient { pub fn entry( &self, address: Addr, - ) -> Result, StorageError> { + ) -> Result, StorageError> { self.validate(&address)?; - StorageEntry::new(&self.client, address) + StorageEntry::new(self.client, address) } /// Iterate over all of the storage entries listed in the metadata for the current block. This does **not** include well known /// storage entries like `:code` which are not listed in the metadata. - pub fn entries(&self) -> impl Iterator> { + pub fn entries(&self) -> impl Iterator> { let metadata = self.client.metadata_ref(); Entry::tuples_of(metadata.storage_entries()).map(|(pallet_name, entry_name)| { StorageEntryRef { pallet_name: pallet_name.clone(), entry_name, - client: &self.client, + client: self.client, marker: std::marker::PhantomData, } }) } } -impl> StorageClient { +impl<'atblock, T: Config, Client: OnlineClientAtBlockT> StorageClient<'atblock, T, Client> { /// This is essentially a shorthand for `client.entry(addr)?.fetch(key_parts)`. See [`StorageEntry::fetch()`]. pub async fn fetch( &self, diff --git a/new/src/transactions.rs b/new/src/transactions.rs index 293fee9a2d..e2eb301d9d 100644 --- a/new/src/transactions.rs +++ b/new/src/transactions.rs @@ -29,13 +29,13 @@ pub use validation_result::{ /// A client for working with transactions. #[derive(Clone)] -pub struct TransactionsClient { - client: Client, +pub struct TransactionsClient<'atblock, T, Client> { + client: &'atblock Client, marker: PhantomData, } -impl TransactionsClient { - pub(crate) fn new(client: Client) -> Self { +impl<'atblock, T, Client> TransactionsClient<'atblock, T, Client> { + pub(crate) fn new(client: &'atblock Client) -> Self { TransactionsClient { client, marker: PhantomData, @@ -43,7 +43,9 @@ impl TransactionsClient { } } -impl> TransactionsClient { +impl<'atblock, T: Config, Client: OfflineClientAtBlockT> + TransactionsClient<'atblock, T, Client> +{ /// Run the validation logic against some transaction you'd like to submit. Returns `Ok(())` /// if the call is valid (or if it's not possible to check since the call has no validation hash). /// Return an error if the call was not valid or something went wrong trying to validate it (ie @@ -77,6 +79,20 @@ impl> TransactionsClient } } + /// Create a [`SubmittableTransaction`] from some already-signed and prepared + /// transaction bytes, and some client (anything implementing [`OfflineClientAtBlockT`] + /// or [`OnlineClientAtBlockT`]). + pub fn from_bytes( + client: &'atblock Client, + tx_bytes: Vec, + ) -> SubmittableTransaction<'atblock, T, Client> { + SubmittableTransaction { + client, + encoded: tx_bytes, + marker: PhantomData, + } + } + /// Return the SCALE encoded bytes representing the call data of the transaction. pub fn call_data(&self, call: &Call) -> Result, ExtrinsicError> where @@ -94,7 +110,7 @@ impl> TransactionsClient pub fn create_unsigned( &self, call: &Call, - ) -> Result, ExtrinsicError> + ) -> Result, ExtrinsicError> where Call: Payload, { @@ -110,7 +126,7 @@ impl> TransactionsClient pub fn create_v4_unsigned( &self, call: &Call, - ) -> Result, ExtrinsicError> + ) -> Result, ExtrinsicError> where Call: Payload, { @@ -121,7 +137,7 @@ impl> TransactionsClient pub fn create_v5_unsigned( &self, call: &Call, - ) -> Result, ExtrinsicError> + ) -> Result, ExtrinsicError> where Call: Payload, { @@ -138,7 +154,7 @@ impl> TransactionsClient &self, call: &Call, params: >::Params, - ) -> Result, ExtrinsicError> + ) -> Result, ExtrinsicError> where Call: Payload, { @@ -159,7 +175,7 @@ impl> TransactionsClient &self, call: &Call, params: >::Params, - ) -> Result, ExtrinsicError> + ) -> Result, ExtrinsicError> where Call: Payload, { @@ -177,7 +193,7 @@ impl> TransactionsClient &self, call: &Call, params: >::Params, - ) -> Result, ExtrinsicError> + ) -> Result, ExtrinsicError> where Call: Payload, { @@ -209,7 +225,7 @@ impl> TransactionsClient &self, call: &Call, tx_version: SupportedTransactionVersion, - ) -> Result, ExtrinsicError> { + ) -> Result, ExtrinsicError> { let metadata = self.client.metadata_ref(); // 1. Validate this call against the current node metadata if the call comes @@ -235,7 +251,7 @@ impl> TransactionsClient // Wrap in Encoded to ensure that any more "encode" calls leave it in the right state. Ok(SubmittableTransaction { - client: self.client.clone(), + client: self.client, encoded: extrinsic, marker: PhantomData, }) @@ -247,7 +263,7 @@ impl> TransactionsClient call: &Call, params: >::Params, tx_version: SupportedTransactionVersion, - ) -> Result, ExtrinsicError> + ) -> Result, ExtrinsicError> where Call: Payload, { @@ -286,7 +302,7 @@ impl> TransactionsClient // Return these details, ready to construct a signed extrinsic from. Ok(SignableTransaction { - client: self.client.clone(), + client: self.client, call_data, additional_and_extra_params, tx_extension_version, @@ -294,10 +310,10 @@ impl> TransactionsClient } } -impl> TransactionsClient { +impl<'atblock, T: Config, Client: OnlineClientAtBlockT> TransactionsClient<'atblock, T, Client> { /// Get the account nonce for a given account ID. pub async fn account_nonce(&self, account_id: &T::AccountId) -> Result { - account_nonce::get_account_nonce(&self.client, account_id) + account_nonce::get_account_nonce(self.client, account_id) .await .map_err(|e| ExtrinsicError::AccountNonceError { block_hash: self.client.block_hash().into(), @@ -312,7 +328,7 @@ impl> TransactionsClient { call: &Call, account_id: &T::AccountId, mut params: >::Params, - ) -> Result, ExtrinsicError> + ) -> Result, ExtrinsicError> where Call: Payload, { @@ -330,7 +346,7 @@ impl> TransactionsClient { call: &Call, account_id: &T::AccountId, mut params: >::Params, - ) -> Result, ExtrinsicError> + ) -> Result, ExtrinsicError> where Call: Payload, { @@ -348,7 +364,7 @@ impl> TransactionsClient { call: &Call, account_id: &T::AccountId, mut params: >::Params, - ) -> Result, ExtrinsicError> + ) -> Result, ExtrinsicError> where Call: Payload, { @@ -363,7 +379,7 @@ impl> TransactionsClient { call: &Call, signer: &S, params: >::Params, - ) -> Result, ExtrinsicError> + ) -> Result, ExtrinsicError> where Call: Payload, S: Signer, @@ -384,7 +400,7 @@ impl> TransactionsClient { &mut self, call: &Call, signer: &S, - ) -> Result, ExtrinsicError> + ) -> Result, ExtrinsicError> where Call: Payload, S: Signer, @@ -403,7 +419,7 @@ impl> TransactionsClient { call: &Call, signer: &S, params: >::Params, - ) -> Result, ExtrinsicError> + ) -> Result, ExtrinsicError> where Call: Payload, S: Signer, @@ -506,15 +522,17 @@ pub enum SupportedTransactionVersion { } /// This is a transaction that requires signing before it can be submitted. -pub struct SignableTransaction { - client: Client, +pub struct SignableTransaction<'atblock, T: Config, Client> { + client: &'atblock Client, call_data: Vec, additional_and_extra_params: ::ExtrinsicParams, // For V4 transactions this doesn't exist, and for V5 it does. tx_extension_version: Option, } -impl> SignableTransaction { +impl<'atblock, T: Config, Client: OfflineClientAtBlockT> + SignableTransaction<'atblock, T, Client> +{ /// Return the bytes representing the call data for this partially constructed /// transaction. pub fn call_data(&self) -> &[u8] { @@ -530,7 +548,10 @@ impl> SignableTransaction /// Convert this [`SignableTransaction`] into a [`SubmittableTransaction`], ready to submit. /// The provided `signer` is responsible for providing the "from" address for the transaction, /// as well as providing a signature to attach to it. - pub fn sign>(&mut self, signer: &S) -> SubmittableTransaction { + pub fn sign>( + &mut self, + signer: &S, + ) -> SubmittableTransaction<'atblock, T, Client> { // Given our signer, we can sign the payload representing this extrinsic. let signature = signer.sign(&self.signer_payload()); // Now, use the signature and "from" account to build the extrinsic. @@ -545,7 +566,7 @@ impl> SignableTransaction &mut self, account_id: &T::AccountId, signature: &T::Signature, - ) -> SubmittableTransaction { + ) -> SubmittableTransaction<'atblock, T, Client> { let encoded = if let Some(tx_extensions_version) = self.tx_extension_version { let mut encoded_inner = Vec::new(); // Pass account and signature to extensions to be added. @@ -593,7 +614,7 @@ impl> SignableTransaction }; SubmittableTransaction { - client: self.client.clone(), + client: self.client, encoded, marker: PhantomData, } @@ -627,28 +648,17 @@ impl> SignableTransaction } /// This is a transaction that is ready to submit. -pub struct SubmittableTransaction { - client: Client, +pub struct SubmittableTransaction<'atblock, T, Client> { + client: &'atblock Client, encoded: Vec, marker: PhantomData, } -impl SubmittableTransaction +impl<'atblock, T, Client> SubmittableTransaction<'atblock, T, Client> where T: Config, Client: OfflineClientAtBlockT, { - /// Create a [`SubmittableTransaction`] from some already-signed and prepared - /// transaction bytes, and some client (anything implementing [`OfflineClientAtBlockT`] - /// or [`OnlineClientAtBlockT`]). - pub fn from_bytes(client: Client, tx_bytes: Vec) -> Self { - Self { - client, - encoded: tx_bytes, - marker: PhantomData, - } - } - /// Calculate and return the hash of the transaction, based on the configured hasher. pub fn hash(&self) -> HashFor { self.client.hasher().hash(&self.encoded) @@ -666,12 +676,16 @@ where } } -impl> SubmittableTransaction { +impl<'atblock, T: Config, Client: OnlineClientAtBlockT> + SubmittableTransaction<'atblock, T, Client> +{ /// Submits the transaction to the chain. /// /// Returns a [`TransactionProgress`], which can be used to track the status of the transaction /// and obtain details about it, once it has made it into a block. - pub async fn submit_and_watch(&self) -> Result, ExtrinsicError> { + pub async fn submit_and_watch( + &self, + ) -> Result, ExtrinsicError> { // Get a hash of the transaction (we'll need this later). let ext_hash = self.hash(); @@ -683,7 +697,7 @@ impl> SubmittableTransaction { +pub struct TransactionProgress<'atblock, T: Config, C> { sub: Option>>>, ext_hash: HashFor, - client: C, + client: &'atblock C, } // The above type is not `Unpin` by default unless the generic param `T` is, // so we manually make it clear that Unpin is actually fine regardless of `T` // (we don't care if this moves around in memory while it's "pinned"). -impl Unpin for TransactionProgress {} +impl<'atblock, T: Config, C> Unpin for TransactionProgress<'atblock, T, C> {} -impl TransactionProgress { +impl<'atblock, T: Config, C> TransactionProgress<'atblock, T, C> { /// Instantiate a new [`TransactionProgress`] from a custom subscription. pub fn new( sub: StreamOfResults>>, - client: C, + client: &'atblock C, ext_hash: HashFor, ) -> Self { Self { @@ -43,7 +43,7 @@ impl TransactionProgress { } } -impl TransactionProgress +impl<'atblock, T, C> TransactionProgress<'atblock, T, C> where T: Config, C: OnlineClientAtBlockT, @@ -53,7 +53,7 @@ where /// avoid importing that trait if you don't otherwise need it. pub async fn next( &mut self, - ) -> Option, TransactionProgressError>> { + ) -> Option, TransactionProgressError>> { StreamExt::next(self).await } @@ -69,7 +69,7 @@ where /// out if they finally made it into a block or not. pub async fn wait_for_finalized( mut self, - ) -> Result, TransactionProgressError> { + ) -> Result, TransactionProgressError> { while let Some(status) = self.next().await { match status? { // Finalized! Return. @@ -104,15 +104,15 @@ where /// out if they finally made it into a block or not. pub async fn wait_for_finalized_success( self, - ) -> Result, TransactionFinalizedSuccessError> { + ) -> Result, TransactionFinalizedSuccessError> { let evs = self.wait_for_finalized().await?.wait_for_success().await?; Ok(evs) } } // TransactionProgress is a stream of transaction events -impl Stream for TransactionProgress { - type Item = Result, TransactionProgressError>; +impl<'atblock, T: Config, C: Clone> Stream for TransactionProgress<'atblock, T, C> { + type Item = Result, TransactionProgressError>; fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { let sub = match self.sub.as_mut() { @@ -133,7 +133,7 @@ impl Stream for TransactionProgress { TransactionStatus::InBestBlock(TransactionInBlock::new( hash, self.ext_hash, - self.client.clone(), + self.client, )) } // These stream events mean that nothing further will be sent: @@ -142,7 +142,7 @@ impl Stream for TransactionProgress { TransactionStatus::InFinalizedBlock(TransactionInBlock::new( hash, self.ext_hash, - self.client.clone(), + self.client, )) } BackendTransactionStatus::Error { message } => { @@ -164,7 +164,7 @@ impl Stream for TransactionProgress { /// Possible transaction statuses returned from our [`TransactionProgress::next()`] call. #[derive(Debug)] -pub enum TransactionStatus { +pub enum TransactionStatus<'atblock, T: Config, C> { /// Transaction is part of the future queue. Validated, /// The transaction has been broadcast to other nodes. @@ -172,9 +172,9 @@ pub enum TransactionStatus { /// Transaction is no longer in a best block. NoLongerInBestBlock, /// Transaction has been included in block with given hash. - InBestBlock(TransactionInBlock), + InBestBlock(TransactionInBlock<'atblock, T, C>), /// Transaction has been finalized by a finality-gadget, e.g GRANDPA - InFinalizedBlock(TransactionInBlock), + InFinalizedBlock(TransactionInBlock<'atblock, T, C>), /// Something went wrong in the node. Error { /// Human readable message; what went wrong. @@ -192,10 +192,10 @@ pub enum TransactionStatus { }, } -impl TransactionStatus { +impl<'atblock, T: Config, C> TransactionStatus<'atblock, T, C> { /// A convenience method to return the finalized details. Returns /// [`None`] if the enum variant is not [`TxStatus::InFinalizedBlock`]. - pub fn as_finalized(&self) -> Option<&TransactionInBlock> { + pub fn as_finalized(&self) -> Option<&TransactionInBlock<'atblock, T, C>> { match self { Self::InFinalizedBlock(val) => Some(val), _ => None, @@ -204,7 +204,7 @@ impl TransactionStatus { /// A convenience method to return the best block details. Returns /// [`None`] if the enum variant is not [`TxStatus::InBestBlock`]. - pub fn as_in_block(&self) -> Option<&TransactionInBlock> { + pub fn as_in_block(&self) -> Option<&TransactionInBlock<'atblock, T, C>> { match self { Self::InBestBlock(val) => Some(val), _ => None, @@ -214,14 +214,18 @@ impl TransactionStatus { /// This struct represents a transaction that has made it into a block. #[derive(Debug)] -pub struct TransactionInBlock { +pub struct TransactionInBlock<'atblock, T: Config, C> { block_ref: BlockRef>, ext_hash: HashFor, - client: C, + client: &'atblock C, } -impl TransactionInBlock { - pub(crate) fn new(block_ref: BlockRef>, ext_hash: HashFor, client: C) -> Self { +impl<'atblock, T: Config, C> TransactionInBlock<'atblock, T, C> { + pub(crate) fn new( + block_ref: BlockRef>, + ext_hash: HashFor, + client: &'atblock C, + ) -> Self { Self { block_ref, ext_hash, @@ -240,7 +244,7 @@ impl TransactionInBlock { } } -impl> TransactionInBlock { +impl<'atblock, T: Config, C: OnlineClientAtBlockT> TransactionInBlock<'atblock, T, C> { /// Fetch the events associated with this transaction. If the transaction /// was successful (ie no `ExtrinsicFailed`) events were found, then we return /// the events associated with it. If the transaction was not successful, or @@ -254,7 +258,9 @@ impl> TransactionInBlock { /// /// **Note:** This has to download block details from the node and decode events /// from them. - pub async fn wait_for_success(&self) -> Result, TransactionEventsError> { + pub async fn wait_for_success( + &self, + ) -> Result, TransactionEventsError> { let events = self.fetch_events().await?; // Try to find any errors; return the first one we encounter. @@ -286,7 +292,9 @@ impl> TransactionInBlock { /// /// **Note:** This has to download block details from the node and decode events /// from them. - pub async fn fetch_events(&self) -> Result, TransactionEventsError> { + pub async fn fetch_events( + &self, + ) -> Result, TransactionEventsError> { let hasher = self.client.hasher(); let block_body = self @@ -316,16 +324,15 @@ impl> TransactionInBlock { transaction_hash: self.ext_hash.into(), })?; - let events = - ExtrinsicEvents::fetch(self.client.clone(), self.extrinsic_hash(), extrinsic_index) - .await - .map_err( - |e| TransactionEventsError::CannotFetchEventsForTransaction { - block_hash: self.block_hash().into(), - transaction_hash: self.ext_hash.into(), - error: e, - }, - )?; + let events = ExtrinsicEvents::fetch(self.client, self.extrinsic_hash(), extrinsic_index) + .await + .map_err( + |e| TransactionEventsError::CannotFetchEventsForTransaction { + block_hash: self.block_hash().into(), + transaction_hash: self.ext_hash.into(), + error: e, + }, + )?; Ok(events) } diff --git a/new/src/view_functions.rs b/new/src/view_functions.rs index 3a89d55938..95b8a13e23 100644 --- a/new/src/view_functions.rs +++ b/new/src/view_functions.rs @@ -17,14 +17,14 @@ const CALL_NAME: &str = "RuntimeViewFunction_execute_view_function"; /// Execute View Function calls. #[derive_where(Clone; Client)] -pub struct ViewFunctionsClient { - client: Client, +pub struct ViewFunctionsClient<'atblock, T: Config, Client> { + client: &'atblock Client, marker: PhantomData, } -impl ViewFunctionsClient { +impl<'atblock, T: Config, Client> ViewFunctionsClient<'atblock, T, Client> { /// Create a new [`ViewFunctionsClient`] - pub(crate) fn new(client: Client) -> Self { + pub(crate) fn new(client: &'atblock Client) -> Self { Self { client, marker: PhantomData, @@ -32,7 +32,7 @@ impl ViewFunctionsClient { } } -impl ViewFunctionsClient +impl<'atblock, T, Client> ViewFunctionsClient<'atblock, T, Client> where T: Config, Client: OfflineClientAtBlockT, @@ -83,7 +83,7 @@ where } } -impl ViewFunctionsClient +impl<'atblock, T, Client> ViewFunctionsClient<'atblock, T, Client> where T: Config, Client: OnlineClientAtBlockT,