Skip to content

Commit 630c20e

Browse files
authored
Prep v0.16.0 release: allow working with old V9 storage hashers (#68)
* Accomodate a breaking change and allow old V9 storage hashers to work properly * Prep 0.16.0 release
1 parent 5563691 commit 630c20e

File tree

5 files changed

+59
-3
lines changed

5 files changed

+59
-3
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@ The format is based on [Keep a Changelog].
44

55
[Keep a Changelog]: http://keepachangelog.com/en/1.0.0/
66

7+
## 0.16.0 (2025-11-26)
8+
9+
- Add a flag to `StorageInfo` which can be set in order to tell `frame-decode` to use the old version of V9 storage hashers when decoding storage keys. We need to manually toggle this flag when using metadata produced by runtimes prior to [this change](https://github.com/paritytech/substrate/commit/bbb363f4320b4a72e059c0fca96af42296d5a6bf#diff-aa7bc120d701816def0f2a5eb469212d2b7021d2fc9d3b284f843f3f8089e91a), which altered the storage hashers (and thus their encoding/decoding). Kusama prior to spec version 1032 is one such case when this needs to be toggled.
10+
711
## 0.15.0 (2025-11-20)
812

913
- Update to `scale-info-legacy` 0.4.0.

Cargo.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "frame-decode"
3-
version = "0.15.0"
3+
version = "0.16.0"
44
edition = "2024"
55
description = "Decode extrinsics and storage from Substrate based chains"
66
license = "Apache-2.0"

src/methods/storage_decoder.rs

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -383,7 +383,12 @@ where
383383

384384
let mut parts = vec![];
385385
for key in &*storage_info.keys {
386-
let hasher = key.hasher;
386+
let hasher = if storage_info.use_old_v9_storage_hashers {
387+
map_to_old_v9_storage_hashers(key.hasher)
388+
} else {
389+
key.hasher
390+
};
391+
387392
let start_idx = curr_idx(cursor);
388393
let part = match &hasher {
389394
StorageHasher::Blake2_128 | StorageHasher::Twox128 => {
@@ -756,6 +761,23 @@ fn strip_bytes<'a, T>(
756761
Ok(bytes)
757762
}
758763

764+
fn map_to_old_v9_storage_hashers(hasher: StorageHasher) -> StorageHasher {
765+
match hasher {
766+
// See https://github.com/paritytech/substrate/commit/bbb363f4320b4a72e059c0fca96af42296d5a6bf#diff-aa7bc120d701816def0f2a5eb469212d2b7021d2fc9d3b284f843f3f8089e91a.
767+
// We SCALE decode into the "new" variants seen there, but need to translate back to the old ones, which
768+
// is what was actually encoded from the runtime.
769+
StorageHasher::Blake2_128 => StorageHasher::Blake2_128,
770+
StorageHasher::Blake2_256 => StorageHasher::Blake2_256,
771+
StorageHasher::Blake2_128Concat => StorageHasher::Twox128,
772+
StorageHasher::Twox128 => StorageHasher::Twox256,
773+
StorageHasher::Twox256 => StorageHasher::Twox64Concat,
774+
775+
// These types didn't exist prior to the change, so just leave them alone:
776+
StorageHasher::Twox64Concat => StorageHasher::Twox64Concat,
777+
StorageHasher::Identity => StorageHasher::Identity,
778+
}
779+
}
780+
759781
#[cfg(test)]
760782
mod test {
761783
use super::*;

src/methods/storage_type_info.rs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,15 +139,34 @@ pub struct StorageInfo<'info, TypeId: Clone> {
139139
pub value_id: TypeId,
140140
/// Bytes representing the default value for this entry, if one exists.
141141
pub default_value: Option<Cow<'info, [u8]>>,
142+
/// Are we using V9 metadata prior to a change which added a new storage hasher?
143+
///
144+
/// See https://github.com/paritytech/substrate/commit/bbb363f4320b4a72e059c0fca96af42296d5a6bf#diff-aa7bc120d701816def0f2a5eb469212d2b7021d2fc9d3b284f843f3f8089e91a
145+
/// Here a new hasher is added in the middle of the hashers enum. Thus, Metadata produced
146+
/// by V9 runtimes prior to this change will not correctly decode into `frame-metadata`'s V9
147+
/// which includes the change.
148+
///
149+
/// On Kusama for instance, this should be set to true when using metadata from any spec
150+
/// version below 1032 in order to enable decoding correctly from it.
151+
pub use_old_v9_storage_hashers: bool,
142152
}
143153

144154
impl<'info, TypeId: Clone + 'static> StorageInfo<'info, TypeId> {
155+
/// For older V9 metadatas, this needs toggling. See the docs on [`StorageInfo::use_old_v9_storage_hashers`].
156+
pub fn use_use_old_v9_storage_hashers(self, b: bool) -> Self {
157+
StorageInfo {
158+
use_old_v9_storage_hashers: b,
159+
..self
160+
}
161+
}
162+
145163
/// Take ownership of this [`StorageInfo`], turning any lifetimes to `'static`.
146164
pub fn into_owned(self) -> StorageInfo<'static, TypeId> {
147165
StorageInfo {
148166
keys: Cow::Owned(self.keys.into_owned()),
149167
value_id: self.value_id,
150168
default_value: self.default_value.map(|v| Cow::Owned(v.into_owned())),
169+
use_old_v9_storage_hashers: self.use_old_v9_storage_hashers,
151170
}
152171
}
153172

@@ -171,6 +190,7 @@ impl<'info, TypeId: Clone + 'static> StorageInfo<'info, TypeId> {
171190
keys: Cow::Owned(new_keys),
172191
value_id: new_value_id,
173192
default_value: self.default_value.map(|d| Cow::Owned(d.into_owned())),
193+
use_old_v9_storage_hashers: false,
174194
})
175195
}
176196
}
@@ -253,6 +273,7 @@ macro_rules! impl_storage_type_info_for_v14_to_v16 {
253273
keys: Cow::Owned(Vec::new()),
254274
value_id: value.id,
255275
default_value,
276+
use_old_v9_storage_hashers: false,
256277
}),
257278
path::StorageEntryType::Map {
258279
hashers,
@@ -278,6 +299,7 @@ macro_rules! impl_storage_type_info_for_v14_to_v16 {
278299
}])),
279300
value_id,
280301
default_value,
302+
use_old_v9_storage_hashers: false,
281303
})
282304
} else if let scale_info::TypeDef::Tuple(tuple) = &key_ty.type_def {
283305
// Else, if the key is a tuple, we expect a matching number of hashers
@@ -297,6 +319,7 @@ macro_rules! impl_storage_type_info_for_v14_to_v16 {
297319
keys,
298320
value_id,
299321
default_value,
322+
use_old_v9_storage_hashers: false,
300323
})
301324
} else {
302325
// Hasher and key mismatch
@@ -494,6 +517,7 @@ mod legacy {
494517
keys: Cow::Owned(Vec::new()),
495518
value_id,
496519
default_value,
520+
use_old_v9_storage_hashers: false,
497521
})
498522
}
499523
path::StorageEntryType::Map {
@@ -509,6 +533,7 @@ mod legacy {
509533
}])),
510534
value_id,
511535
default_value,
536+
use_old_v9_storage_hashers: false,
512537
})
513538
}
514539
path::StorageEntryType::DoubleMap {
@@ -536,6 +561,7 @@ mod legacy {
536561
])),
537562
value_id,
538563
default_value,
564+
use_old_v9_storage_hashers: false,
539565
})
540566
}
541567
}
@@ -668,6 +694,7 @@ mod legacy {
668694
keys: Cow::Owned(Vec::new()),
669695
value_id,
670696
default_value,
697+
use_old_v9_storage_hashers: false,
671698
})
672699
}
673700
frame_metadata::v13::StorageEntryType::Map {
@@ -680,6 +707,7 @@ mod legacy {
680707
keys: Cow::Owned(Vec::from_iter([StorageKeyInfo { hasher, key_id }])),
681708
value_id,
682709
default_value,
710+
use_old_v9_storage_hashers: false,
683711
})
684712
}
685713
frame_metadata::v13::StorageEntryType::DoubleMap {
@@ -707,6 +735,7 @@ mod legacy {
707735
])),
708736
value_id,
709737
default_value,
738+
use_old_v9_storage_hashers: false,
710739
})
711740
}
712741
frame_metadata::v13::StorageEntryType::NMap {
@@ -749,6 +778,7 @@ mod legacy {
749778
keys: Cow::Owned(keys?),
750779
value_id,
751780
default_value,
781+
use_old_v9_storage_hashers: false,
752782
})
753783
}
754784
}

0 commit comments

Comments
 (0)