// Copyright 2019-2021 Parity Technologies (UK) Ltd.
// This file is part of substrate-desub.
//
// substrate-desub is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// substrate-desub is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with substrate-desub. If not, see .
use codec::Encode;
use desub_current::{
decoder::{self, StorageHasher},
Metadata, Value,
};
static V14_METADATA_POLKADOT_SCALE: &[u8] = include_bytes!("data/v14_metadata_polkadot.scale");
fn metadata() -> Metadata {
Metadata::from_bytes(V14_METADATA_POLKADOT_SCALE).expect("valid metadata")
}
fn account_id_to_value>(account_id_bytes: A) -> Value<()> {
Value::unnamed_composite(vec![Value::unnamed_composite(account_id_bytes.as_ref().iter().map(|&b| Value::u8(b)).collect())])
}
macro_rules! assert_hasher_eq {
($actual:expr, $hasher:path, $value:expr) => {
if let $hasher(val) = &$actual {
assert_eq!(val.clone().without_context(), $value);
} else {
panic!("Passed {:?}, but expected hasher {}", $actual, stringify!($hasher));
}
};
}
macro_rules! bytes {
($name:ident = $hex:literal) => {
let hex_str = $hex.strip_prefix("0x").expect("0x should prefix hex encoded bytes");
let bytes = hex::decode(hex_str).expect("valid bytes from hex");
let $name = &mut &*bytes;
};
}
// A very basic storage query; get the current timestamp.
#[test]
fn timestamp_now() {
let meta = metadata();
let storage = decoder::decode_storage(&meta);
// Timestamp.Now(): u64
bytes!(storage_key = "0xf0c365c3cf59d671eb72da0e7a4113c49f1f0515f462cdcf84e0f1d6045dfcbb");
let entry = storage.decode_key(&meta, storage_key).expect("can decode storage");
assert!(storage_key.is_empty(), "No more bytes expected");
assert_eq!(entry.prefix, "Timestamp");
assert_eq!(entry.name, "Now");
// We can decode values at this location, now:
let bytes = 123u64.encode();
let val = decoder::decode_value_by_id(&meta, &entry.ty, &mut &*bytes).unwrap();
assert_eq!(val.without_context(), Value::u64(123));
}
// A simple map lookup with an Identity hash (ie just the key itself)
#[test]
fn democracy_blacklist() {
let meta = metadata();
let storage = decoder::decode_storage(&meta);
// Democracy.Blacklist([1u8; 32]: H256): ..
bytes!(storage_key = "0xf2794c22e353e9a839f12faab03a911bb7612c99e31defd01cd5a28e9967e2080101010101010101010101010101010101010101010101010101010101010101");
let entry = storage.decode_key(&meta, storage_key).expect("can decode storage");
assert!(storage_key.is_empty(), "No more bytes expected");
assert_eq!(entry.prefix, "Democracy");
assert_eq!(entry.name, "Blacklist");
let keys = entry.details.map_keys();
// Because the hasher is Identity, we can even see the decoded original map key:
assert_eq!(keys.len(), 1);
assert_hasher_eq!(
keys[0].hasher,
StorageHasher::Identity,
Value::unnamed_composite(vec![Value::unnamed_composite(vec![Value::u8(1); 32])])
);
assert!(matches!(keys[0].hasher, StorageHasher::Identity(..)));
}
// A map storage entry with a Twox64Concat key.
#[test]
fn system_blockhash() {
let meta = metadata();
let storage = decoder::decode_storage(&meta);
// System.BlockHash(1000): [u8; 32]
bytes!(storage_key = "0x26aa394eea5630e07c48ae0c9558cef7a44704b568d21667356a5a050c118746b6ff6f7d467b87a9e8030000");
let entry = storage.decode_key(&meta, storage_key).expect("can decode storage");
assert!(storage_key.is_empty(), "No more bytes expected");
assert_eq!(entry.prefix, "System");
assert_eq!(entry.name, "BlockHash");
let keys = entry.details.map_keys();
// Because the hasher is Twox64Concat, we can even see the decoded original map key:
assert_eq!(keys.len(), 1);
assert_hasher_eq!(keys[0].hasher, StorageHasher::Twox64Concat, Value::u32(1000));
// We can decode values at this location:
let bytes = [1u8; 32].encode();
let val = decoder::decode_value_by_id(&meta, &entry.ty, &mut &*bytes).unwrap();
assert_eq!(
val.without_context(),
// The Type appears to take the form of a newtype-wrapped [u8; 32]:
Value::unnamed_composite(vec![Value::unnamed_composite(vec![Value::u8(1); 32])])
);
}
// A simple map lookup like above, but using a Blake2_128Concat key
#[test]
fn balances_account() {
let meta = metadata();
let storage = decoder::decode_storage(&meta);
// Balances.Account(BOB: AccountId32): PalletBalancesAccountData
bytes!(storage_key = "0xc2261276cc9d1f8598ea4b6a74b15c2fb99d880ec681799c0cf30e8886371da94f9aea1afa791265fae359272badc1cf8eaf04151687736326c9fea17e25fc5287613693c912909cb226aa4794f26a48");
let entry = storage.decode_key(&meta, storage_key).expect("can decode storage");
assert!(storage_key.is_empty(), "No more bytes expected");
assert_eq!(entry.prefix, "Balances");
assert_eq!(entry.name, "Account");
let keys = entry.details.map_keys();
let bobs_accountid = sp_keyring::AccountKeyring::Bob.to_account_id();
let bobs_value = account_id_to_value(&bobs_accountid);
assert_eq!(keys.len(), 1);
assert_hasher_eq!(keys[0].hasher, StorageHasher::Blake2_128Concat, bobs_value);
}
// A map storage entry keyed by a tuple of 2 Twox64Concat values.
#[test]
fn imonline_authoredblocks() {
let meta = metadata();
let storage = decoder::decode_storage(&meta);
// ImOnline.AuthoredBlocks(1234: u32, BOB:AccountId32): u32
bytes!(storage_key = "0x2b06af9719ac64d755623cda8ddd9b94b1c371ded9e9c565e89ba783c4d5f5f9548491cbfe725727d2040000a647e755c30521d38eaf04151687736326c9fea17e25fc5287613693c912909cb226aa4794f26a48");
let entry = storage.decode_key(&meta, storage_key).expect("can decode storage");
assert!(storage_key.is_empty(), "No more bytes expected");
assert_eq!(entry.prefix, "ImOnline");
assert_eq!(entry.name, "AuthoredBlocks");
let keys = entry.details.map_keys();
let bobs_accountid = sp_keyring::AccountKeyring::Bob.to_account_id();
let bobs_value = account_id_to_value(&bobs_accountid);
// Because the hashers are Twox64Concat, we can check the keys we provided:
assert_eq!(keys.len(), 2);
assert_hasher_eq!(keys[0].hasher, StorageHasher::Twox64Concat, Value::u32(1234));
assert_hasher_eq!(keys[1].hasher, StorageHasher::Twox64Concat, bobs_value);
// We can decode values at this location:
let bytes = 5678u32.encode();
let val = decoder::decode_value_by_id(&meta, &entry.ty, &mut &*bytes).unwrap();
assert_eq!(val.without_context(), Value::u32(5678));
}