1use crate::{
6 dynamic::{DecodedValueThunk, Value},
7 error::{Error, MetadataError, StorageAddressError},
8 metadata::{DecodeWithMetadata, EncodeWithMetadata, Metadata},
9 utils::{Encoded, Static},
10};
11use scale_info::TypeDef;
12use std::borrow::Cow;
13use subxt_metadata::{StorageEntryType, StorageHasher};
14
15pub trait StorageAddress {
18 type Target: DecodeWithMetadata;
20 type IsFetchable;
23 type IsDefaultable;
26 type IsIterable;
29
30 fn pallet_name(&self) -> &str;
32
33 fn entry_name(&self) -> &str;
35
36 fn append_entry_bytes(&self, metadata: &Metadata, bytes: &mut Vec<u8>) -> Result<(), Error>;
39
40 fn validation_hash(&self) -> Option<[u8; 32]> {
44 None
45 }
46}
47
48pub struct Yes;
51
52pub struct Address<StorageKey, ReturnTy, Fetchable, Defaultable, Iterable> {
55 pallet_name: Cow<'static, str>,
56 entry_name: Cow<'static, str>,
57 storage_entry_keys: Vec<StorageKey>,
58 validation_hash: Option<[u8; 32]>,
59 _marker: std::marker::PhantomData<(ReturnTy, Fetchable, Defaultable, Iterable)>,
60}
61
62pub type DynamicAddress<StorageKey> = Address<StorageKey, DecodedValueThunk, Yes, Yes, Yes>;
65
66impl<StorageKey, ReturnTy, Fetchable, Defaultable, Iterable>
67 Address<StorageKey, ReturnTy, Fetchable, Defaultable, Iterable>
68where
69 StorageKey: EncodeWithMetadata,
70 ReturnTy: DecodeWithMetadata,
71{
72 pub fn new(
74 pallet_name: impl Into<String>,
75 entry_name: impl Into<String>,
76 storage_entry_keys: Vec<StorageKey>,
77 ) -> Self {
78 Self {
79 pallet_name: Cow::Owned(pallet_name.into()),
80 entry_name: Cow::Owned(entry_name.into()),
81 storage_entry_keys: storage_entry_keys.into_iter().collect(),
82 validation_hash: None,
83 _marker: std::marker::PhantomData,
84 }
85 }
86
87 #[doc(hidden)]
90 pub fn new_static(
91 pallet_name: &'static str,
92 entry_name: &'static str,
93 storage_entry_keys: Vec<StorageKey>,
94 hash: [u8; 32],
95 ) -> Self {
96 Self {
97 pallet_name: Cow::Borrowed(pallet_name),
98 entry_name: Cow::Borrowed(entry_name),
99 storage_entry_keys: storage_entry_keys.into_iter().collect(),
100 validation_hash: Some(hash),
101 _marker: std::marker::PhantomData,
102 }
103 }
104
105 pub fn unvalidated(self) -> Self {
107 Self {
108 validation_hash: None,
109 ..self
110 }
111 }
112
113 pub fn to_root_bytes(&self) -> Vec<u8> {
117 super::utils::storage_address_root_bytes(self)
118 }
119}
120
121impl<StorageKey, ReturnTy, Fetchable, Defaultable, Iterable> StorageAddress
122 for Address<StorageKey, ReturnTy, Fetchable, Defaultable, Iterable>
123where
124 StorageKey: EncodeWithMetadata,
125 ReturnTy: DecodeWithMetadata,
126{
127 type Target = ReturnTy;
128 type IsFetchable = Fetchable;
129 type IsDefaultable = Defaultable;
130 type IsIterable = Iterable;
131
132 fn pallet_name(&self) -> &str {
133 &self.pallet_name
134 }
135
136 fn entry_name(&self) -> &str {
137 &self.entry_name
138 }
139
140 fn append_entry_bytes(&self, metadata: &Metadata, bytes: &mut Vec<u8>) -> Result<(), Error> {
141 let pallet = metadata.pallet_by_name_err(self.pallet_name())?;
142 let storage = pallet
143 .storage()
144 .ok_or_else(|| MetadataError::StorageNotFoundInPallet(self.pallet_name().to_owned()))?;
145 let entry = storage
146 .entry_by_name(self.entry_name())
147 .ok_or_else(|| MetadataError::StorageEntryNotFound(self.entry_name().to_owned()))?;
148
149 match entry.entry_type() {
150 StorageEntryType::Plain(_) => {
151 if !self.storage_entry_keys.is_empty() {
152 Err(StorageAddressError::WrongNumberOfKeys {
153 expected: 0,
154 actual: self.storage_entry_keys.len(),
155 }
156 .into())
157 } else {
158 Ok(())
159 }
160 }
161 StorageEntryType::Map {
162 hashers, key_ty, ..
163 } => {
164 let ty = metadata
165 .types()
166 .resolve(*key_ty)
167 .ok_or(MetadataError::TypeNotFound(*key_ty))?;
168
169 let type_ids = match &ty.type_def {
172 TypeDef::Tuple(tuple) => {
173 either::Either::Left(tuple.fields.iter().map(|f| f.id))
174 }
175 _other => either::Either::Right(std::iter::once(*key_ty)),
176 };
177
178 if type_ids.len() != self.storage_entry_keys.len() {
179 return Err(StorageAddressError::WrongNumberOfKeys {
180 expected: type_ids.len(),
181 actual: self.storage_entry_keys.len(),
182 }
183 .into());
184 }
185
186 if hashers.len() == 1 {
187 let mut input = Vec::new();
189 let iter = self.storage_entry_keys.iter().zip(type_ids);
190 for (key, type_id) in iter {
191 key.encode_with_metadata(type_id, metadata, &mut input)?;
192 }
193 hash_bytes(&input, &hashers[0], bytes);
194 Ok(())
195 } else if hashers.len() == type_ids.len() {
196 let iter = self.storage_entry_keys.iter().zip(type_ids).zip(hashers);
197 for ((key, type_id), hasher) in iter {
199 let mut input = Vec::new();
200 key.encode_with_metadata(type_id, metadata, &mut input)?;
201 hash_bytes(&input, hasher, bytes);
202 }
203 Ok(())
204 } else {
205 Err(StorageAddressError::WrongNumberOfHashers {
207 hashers: hashers.len(),
208 fields: type_ids.len(),
209 }
210 .into())
211 }
212 }
213 }
214 }
215
216 fn validation_hash(&self) -> Option<[u8; 32]> {
217 self.validation_hash
218 }
219}
220
221pub type StaticStorageMapKey = Static<Encoded>;
224
225#[doc(hidden)]
227pub fn make_static_storage_map_key<T: codec::Encode>(t: T) -> StaticStorageMapKey {
228 Static(Encoded(t.encode()))
229}
230
231pub fn dynamic_root(
233 pallet_name: impl Into<String>,
234 entry_name: impl Into<String>,
235) -> DynamicAddress<Value> {
236 DynamicAddress::new(pallet_name, entry_name, vec![])
237}
238
239pub fn dynamic<StorageKey: EncodeWithMetadata>(
241 pallet_name: impl Into<String>,
242 entry_name: impl Into<String>,
243 storage_entry_keys: Vec<StorageKey>,
244) -> DynamicAddress<StorageKey> {
245 DynamicAddress::new(pallet_name, entry_name, storage_entry_keys)
246}
247
248fn hash_bytes(input: &[u8], hasher: &StorageHasher, bytes: &mut Vec<u8>) {
250 match hasher {
251 StorageHasher::Identity => bytes.extend(input),
252 StorageHasher::Blake2_128 => bytes.extend(sp_core_hashing::blake2_128(input)),
253 StorageHasher::Blake2_128Concat => {
254 bytes.extend(sp_core_hashing::blake2_128(input));
255 bytes.extend(input);
256 }
257 StorageHasher::Blake2_256 => bytes.extend(sp_core_hashing::blake2_256(input)),
258 StorageHasher::Twox128 => bytes.extend(sp_core_hashing::twox_128(input)),
259 StorageHasher::Twox256 => bytes.extend(sp_core_hashing::twox_256(input)),
260 StorageHasher::Twox64Concat => {
261 bytes.extend(sp_core_hashing::twox_64(input));
262 bytes.extend(input);
263 }
264 }
265}