From 4d47acd24b1ba989c77b7f097d3d8783deb9de29 Mon Sep 17 00:00:00 2001 From: James Wilson Date: Mon, 15 Dec 2025 16:37:17 +0000 Subject: [PATCH] Add ability to iterate and visit event fields and storage values --- subxt/src/extrinsics.rs | 57 ++++++++++++++++++++++++++++++ subxt/src/storage/storage_entry.rs | 13 ------- subxt/src/storage/storage_value.rs | 18 ++++++++++ 3 files changed, 75 insertions(+), 13 deletions(-) diff --git a/subxt/src/extrinsics.rs b/subxt/src/extrinsics.rs index fe53e2fdf2..e82833efd0 100644 --- a/subxt/src/extrinsics.rs +++ b/subxt/src/extrinsics.rs @@ -21,6 +21,7 @@ use crate::error::{ use crate::events::{self, DecodeAsEvent}; use frame_decode::extrinsics::Extrinsic as ExtrinsicInfo; use scale_decode::{DecodeAsFields, DecodeAsType}; +use scale_info::PortableRegistry; use std::marker::PhantomData; use std::sync::Arc; use subxt_metadata::Metadata; @@ -353,6 +354,19 @@ where Ok(decoded) } + + /// Iterate over each of the fields in the call data. + pub fn iter_call_data_fields( + &self, + ) -> impl Iterator> { + let ext_bytes = self.bytes(); + self.info.call_data().map(|field| ExtrinsicCallDataField { + bytes: &ext_bytes[field.range()], + name: field.name(), + type_id: *field.ty(), + metadata: self.metadata, + }) + } } impl<'atblock, T, C> Extrinsic<'atblock, T, C> @@ -366,6 +380,49 @@ where } } +/// A field in the extrinsic call data. +pub struct ExtrinsicCallDataField<'atblock, 'extrinsic> { + bytes: &'extrinsic [u8], + name: &'extrinsic str, + type_id: u32, + metadata: &'atblock Metadata, +} + +impl<'atblock, 'extrinsic> ExtrinsicCallDataField<'atblock, 'extrinsic> { + /// The bytes for this field. + pub fn bytes(&self) -> &'extrinsic [u8] { + self.bytes + } + + /// Name of this field. + pub fn name(&self) -> &'extrinsic str { + self.name + } + + /// The type ID for this field. + pub fn type_id(&self) -> u32 { + self.type_id + } + + /// Decode this field into the given type. + pub fn decode_as(&self) -> Result { + E::decode_as_type(&mut &*self.bytes, self.type_id, self.metadata.types()) + } + + /// Visit this field with the provided visitor, returning the output from it. + pub fn visit(&self, visitor: V) -> Result, V::Error> + where + V: scale_decode::visitor::Visitor, + { + scale_decode::visitor::decode_with_visitor( + &mut &*self.bytes, + self.type_id, + self.metadata.types(), + visitor, + ) + } +} + /// The events associated with a given extrinsic. #[derive(Debug)] pub struct ExtrinsicEvents { diff --git a/subxt/src/storage/storage_entry.rs b/subxt/src/storage/storage_entry.rs index 7270b4fc0b..fe8ca17f00 100644 --- a/subxt/src/storage/storage_entry.rs +++ b/subxt/src/storage/storage_entry.rs @@ -250,19 +250,6 @@ where .await .map_err(StorageError::CannotIterateValues)?; - // .map(move |kv| { - // let kv = match kv { - // Ok(kv) => kv, - // Err(e) => return Err(StorageError::StreamFailure(e)), - // }; - // Ok(StorageKeyValue::new( - // info.clone(), - // types, - // kv.key.into(), - // kv.value, - // )) - // }); - Ok(StorageEntries { info, stream, diff --git a/subxt/src/storage/storage_value.rs b/subxt/src/storage/storage_value.rs index 1b4800bd8f..f2e4636661 100644 --- a/subxt/src/storage/storage_value.rs +++ b/subxt/src/storage/storage_value.rs @@ -37,6 +37,11 @@ impl<'info, Value: DecodeAsType> StorageValue<'info, Value> { &self.bytes } + /// The type ID for this storage value. + pub fn type_id(&self) -> u32 { + self.info.value_id + } + /// Consume this storage value and return the raw bytes. pub fn into_bytes(self) -> Vec { self.bytes.to_vec() @@ -67,4 +72,17 @@ impl<'info, Value: DecodeAsType> StorageValue<'info, Value> { Ok(value) } + + /// Visit this storage value with the provided visitor, returning the output from it. + pub fn visit(&self, visitor: V) -> Result, V::Error> + where + V: scale_decode::visitor::Visitor, + { + scale_decode::visitor::decode_with_visitor( + &mut &*self.bytes, + self.type_id(), + self.types, + visitor, + ) + } }