1

The example here https://github.com/paritytech/subxt/blob/master/subxt/examples/storage_iterating.rs

use subxt::{OnlineClient, PolkadotConfig};

#[subxt::subxt(runtime_metadata_path = "../artifacts/polkadot_metadata_full.scale")]
pub mod polkadot {}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Create a new API client, configured to talk to Polkadot nodes.
    let api = OnlineClient::<PolkadotConfig>::new().await?;

    // Build a storage query to iterate over account information.
    let storage_query = polkadot::storage().system().account_iter();

    // Get back an iterator of results (here, we are fetching 10 items at
    // a time from the node, but we always iterate over one at a time).
    let mut results = api.storage().at_latest().await?.iter(storage_query).await?;

    while let Some(Ok((key, value))) = results.next().await {
        println!("Key: 0x{}", hex::encode(&key));
        println!("Value: {:?}", value);
    }

    Ok(())
}

Shows how to iterate over a storage map and get typed results. However, only the values are typed in this case and I didn't find a way to get a typed key value as well. Instead I have to decode into AccountId using a code like:

let account_bytes = key[40..].to_vec();
let array_u8: [u8; 32] = account_bytes.as_slice().try_into().unwrap();
let account = AccountId32::from(array_u8);

Is there a better way?

1 Answer 1

1

No, I don't think this is the perfect way to do it.

You need to manually cut the bytes based on the xxx_concat algorithm used by the storage.

As for the remaining part, if you don't want to specify a type every time, using scale value type might be another option.

For more information, please refer to: https://docs.rs/scale-value/latest/scale_value/struct.Value.html.

6
  • Thanks! I'm still not sure what is the suggested way of doing it. So, as I understand I need to get rid of the prefix first manually. Is it always of the same length? If not, how do I know the length? Then suppose I got rid of the prefix. How do get the typed value? Do I need to define the type by myself, implement/derive Decode and the run decode on the Vec<u8>? Or is there a better way for the second step? I would like a method that works when the key type is not necessarily AccountId, but any type T.
    – Damian
    Commented Oct 7, 2023 at 19:31
  • Currently, you'd have to know which type of hasher is used and, if it's a concat one, chop the first bytes off and such. Potentially we could do something more helpful in Subxt here, so I'll raise an issue for us to think about it.
    – jsdw
    Commented Oct 9, 2023 at 11:13
  • Is there a specific reason the keys are not deserialized by default? Are they different than values in terms of type information?
    – Damian
    Commented Oct 13, 2023 at 14:36
  • Only some keys contain a value (the _concat ones), some entries have multiple keys that would each need decoding (if they can be), and "dynamic" queries don't have key information (but we could probably return Value's here). So I think it's doable, but it just hasn't been done yet!
    – jsdw
    Commented Oct 16, 2023 at 9:48
  • An issue in Subxt for this feature is here: github.com/paritytech/subxt/issues/1201
    – jsdw
    Commented Oct 16, 2023 at 10:08

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.