Skip to content

Commit

Permalink
Add DecodedValueThunk to allow getting bytes back from dynamic queries
Browse files Browse the repository at this point in the history
  • Loading branch information
jsdw committed Oct 3, 2022
1 parent d4fda93 commit c87b4a5
Show file tree
Hide file tree
Showing 8 changed files with 13,257 additions and 11 deletions.
13,166 changes: 13,166 additions & 0 deletions OUTPUT.rs

Large diffs are not rendered by default.

7 changes: 4 additions & 3 deletions examples/examples/dynamic_queries.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -67,15 +67,16 @@ 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).

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(())
Expand Down
Binary file added full-md.scale
Binary file not shown.
Binary file added stripped-md.scale
Binary file not shown.
4 changes: 2 additions & 2 deletions subxt/src/constants/constant_address.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
// see LICENSE for license details.

use crate::{
dynamic::DecodedValue,
dynamic::DecodedValueThunk,
metadata::DecodeWithMetadata,
};
use std::borrow::Cow;
Expand Down Expand Up @@ -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
Expand Down
55 changes: 55 additions & 0 deletions subxt/src/dynamic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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,
)
}
}
4 changes: 2 additions & 2 deletions subxt/src/storage/storage_address.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
use super::storage_map_key::StorageMapKey;
use crate::{
dynamic::{
DecodedValue,
DecodedValueThunk,
Value,
},
error::{
Expand Down Expand Up @@ -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:
Expand Down
32 changes: 28 additions & 4 deletions testing/integration-tests/src/frame/balances.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down

0 comments on commit c87b4a5

Please sign in to comment.