mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-13 09:21:05 +00:00
Add DecodedValueThunk to allow getting bytes back from dynamic queries (#680)
This commit is contained in:
@@ -51,7 +51,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
// 2. Dynamic constant access (the dynamic equivalent to the fetch_constants example).
|
||||
|
||||
let constant_address = subxt::dynamic::constant("Balances", "ExistentialDeposit");
|
||||
let existential_deposit = api.constants().at(&constant_address)?;
|
||||
let existential_deposit = api.constants().at(&constant_address)?.to_value()?;
|
||||
println!("Existential Deposit: {}", existential_deposit);
|
||||
|
||||
// 3. Dynamic storage access
|
||||
@@ -67,7 +67,8 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let account = api
|
||||
.storage()
|
||||
.fetch_or_default(&storage_address, None)
|
||||
.await?;
|
||||
.await?
|
||||
.to_value()?;
|
||||
println!("Bob's account details: {account}");
|
||||
|
||||
// 4. Dynamic storage iteration (the dynamic equivalent to the fetch_all_accounts example).
|
||||
@@ -75,7 +76,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let storage_address = subxt::dynamic::storage_root("System", "Account");
|
||||
let mut iter = api.storage().iter(storage_address, 10, None).await?;
|
||||
while let Some((key, account)) = iter.next().await? {
|
||||
println!("{}: {}", hex::encode(key), account);
|
||||
println!("{}: {}", hex::encode(key), account.to_value()?);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
// see LICENSE for license details.
|
||||
|
||||
use crate::{
|
||||
dynamic::DecodedValue,
|
||||
dynamic::DecodedValueThunk,
|
||||
metadata::DecodeWithMetadata,
|
||||
};
|
||||
use std::borrow::Cow;
|
||||
@@ -97,7 +97,7 @@ pub fn dynamic<'a>(
|
||||
}
|
||||
|
||||
impl<'a> ConstantAddress for DynamicConstantAddress<'a> {
|
||||
type Target = DecodedValue;
|
||||
type Target = DecodedValueThunk;
|
||||
|
||||
fn pallet_name(&self) -> &str {
|
||||
&self.pallet_name
|
||||
|
||||
@@ -5,6 +5,14 @@
|
||||
//! This module provides the entry points to create dynamic
|
||||
//! transactions, storage and constant lookups.
|
||||
|
||||
use crate::{
|
||||
error::Error,
|
||||
metadata::{
|
||||
DecodeWithMetadata,
|
||||
Metadata,
|
||||
},
|
||||
};
|
||||
|
||||
pub use scale_value::Value;
|
||||
|
||||
/// A [`scale_value::Value`] type endowed with contextual information
|
||||
@@ -24,3 +32,50 @@ pub use crate::storage::{
|
||||
dynamic as storage,
|
||||
dynamic_root as storage_root,
|
||||
};
|
||||
|
||||
/// This is the result of making a dynamic request to a node. From this,
|
||||
/// we can return the raw SCALE bytes that we were handed back, or we can
|
||||
/// complete the decoding of the bytes into a [`DecodedValue`] type.
|
||||
pub struct DecodedValueThunk {
|
||||
type_id: u32,
|
||||
metadata: Metadata,
|
||||
scale_bytes: Vec<u8>,
|
||||
}
|
||||
|
||||
impl DecodeWithMetadata for DecodedValueThunk {
|
||||
type Target = Self;
|
||||
|
||||
fn decode_with_metadata(
|
||||
bytes: &mut &[u8],
|
||||
type_id: u32,
|
||||
metadata: &Metadata,
|
||||
) -> Result<Self::Target, Error> {
|
||||
let mut v = Vec::with_capacity(bytes.len());
|
||||
v.extend_from_slice(*bytes);
|
||||
*bytes = &[];
|
||||
Ok(DecodedValueThunk {
|
||||
type_id,
|
||||
metadata: metadata.clone(),
|
||||
scale_bytes: v,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl DecodedValueThunk {
|
||||
/// Return the SCALE encoded bytes handed back from the node.
|
||||
pub fn to_encoded(self) -> Vec<u8> {
|
||||
self.scale_bytes
|
||||
}
|
||||
/// Return the SCALE encoded bytes handed back from the node without taking ownership of them.
|
||||
pub fn encoded(&self) -> &[u8] {
|
||||
&self.scale_bytes
|
||||
}
|
||||
/// Decode the SCALE encoded storage entry into a dynamic [`DecodedValue`] type.
|
||||
pub fn to_value(&self) -> Result<DecodedValue, Error> {
|
||||
DecodedValue::decode_with_metadata(
|
||||
&mut &*self.scale_bytes,
|
||||
self.type_id,
|
||||
&self.metadata,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
use super::storage_map_key::StorageMapKey;
|
||||
use crate::{
|
||||
dynamic::{
|
||||
DecodedValue,
|
||||
DecodedValueThunk,
|
||||
Value,
|
||||
},
|
||||
error::{
|
||||
@@ -194,7 +194,7 @@ impl<'a, Encodable> StorageAddress for DynamicStorageAddress<'a, Encodable>
|
||||
where
|
||||
Encodable: EncodeWithMetadata,
|
||||
{
|
||||
type Target = DecodedValue;
|
||||
type Target = DecodedValueThunk;
|
||||
|
||||
// For dynamic types, we have no static guarantees about any of
|
||||
// this stuff, so we just allow it and let it fail at runtime:
|
||||
|
||||
@@ -164,11 +164,35 @@ async fn tx_dynamic_transfer() -> Result<(), subxt::Error> {
|
||||
.fetch_or_default(&bob_account_addr, None)
|
||||
.await?;
|
||||
|
||||
let alice_pre_free = alice_pre.at("data").at("free").unwrap().as_u128().unwrap();
|
||||
let alice_post_free = alice_post.at("data").at("free").unwrap().as_u128().unwrap();
|
||||
let alice_pre_free = alice_pre
|
||||
.to_value()?
|
||||
.at("data")
|
||||
.at("free")
|
||||
.unwrap()
|
||||
.as_u128()
|
||||
.unwrap();
|
||||
let alice_post_free = alice_post
|
||||
.to_value()?
|
||||
.at("data")
|
||||
.at("free")
|
||||
.unwrap()
|
||||
.as_u128()
|
||||
.unwrap();
|
||||
|
||||
let bob_pre_free = bob_pre.at("data").at("free").unwrap().as_u128().unwrap();
|
||||
let bob_post_free = bob_post.at("data").at("free").unwrap().as_u128().unwrap();
|
||||
let bob_pre_free = bob_pre
|
||||
.to_value()?
|
||||
.at("data")
|
||||
.at("free")
|
||||
.unwrap()
|
||||
.as_u128()
|
||||
.unwrap();
|
||||
let bob_post_free = bob_post
|
||||
.to_value()?
|
||||
.at("data")
|
||||
.at("free")
|
||||
.unwrap()
|
||||
.as_u128()
|
||||
.unwrap();
|
||||
|
||||
assert!(alice_pre_free - 10_000 >= alice_post_free);
|
||||
assert_eq!(bob_pre_free + 10_000, bob_post_free);
|
||||
|
||||
Reference in New Issue
Block a user