miden_objects/account/component/template/storage/
entry_content.rs

1use alloc::{boxed::Box, collections::BTreeSet, string::ToString, vec::Vec};
2
3use vm_core::{
4    utils::{ByteReader, ByteWriter, Deserializable, Serializable},
5    Felt, FieldElement, Word,
6};
7use vm_processor::{DeserializationError, Digest};
8
9use super::{placeholder::PlaceholderType, InitStorageData, MapEntry, StoragePlaceholder};
10use crate::account::{component::template::AccountComponentTemplateError, StorageMap};
11
12// WORDS
13// ================================================================================================
14
15/// Supported word representations. Represents slot values and keys.
16#[derive(Debug, Clone, PartialEq, Eq)]
17pub enum WordRepresentation {
18    /// A word represented by its four felts.
19    Value([Felt; 4]),
20    /// A word represented by 4 [FeltRepresentation].
21    Array([FeltRepresentation; 4]),
22    /// A placeholder value, represented as "{{key}}", where `key` is the inner value of the
23    /// [StoragePlaceholder].
24    Template(StoragePlaceholder),
25}
26
27impl WordRepresentation {
28    /// Returns an iterator over all storage placeholder references within the [WordRepresentation]
29    /// along with their expected types
30    pub fn all_placeholders_iter(
31        &self,
32    ) -> Box<dyn Iterator<Item = (&StoragePlaceholder, PlaceholderType)> + '_> {
33        match self {
34            WordRepresentation::Array(array) => {
35                Box::new(array.iter().flat_map(|felt| felt.all_placeholders_iter()))
36            },
37            WordRepresentation::Template(storage_placeholder) => {
38                Box::new(core::iter::once((storage_placeholder, PlaceholderType::Word)))
39            },
40            WordRepresentation::Value(_) => Box::new(core::iter::empty()),
41        }
42    }
43
44    /// Attempts to convert the [WordRepresentation] into a [Word].
45    ///
46    /// If the representation is a template, the value is retrieved from
47    /// `init_storage_data`, identified by its key. If any of the inner elements
48    /// within the value are a template, they are retrieved in the same way.
49    pub fn try_build_word(
50        &self,
51        init_storage_data: &InitStorageData,
52    ) -> Result<Word, AccountComponentTemplateError> {
53        match self {
54            WordRepresentation::Value(word) => Ok(*word),
55            WordRepresentation::Array(array) => {
56                let mut result = [Felt::ZERO; 4];
57                for (index, felt_repr) in array.iter().enumerate() {
58                    result[index] = felt_repr.clone().try_build_felt(init_storage_data)?;
59                }
60                // SAFETY: result is guaranteed to have all its 4 indices rewritten
61                Ok(result)
62            },
63            WordRepresentation::Template(storage_placeholder) => {
64                let user_value = init_storage_data
65                    .get(storage_placeholder)
66                    .ok_or_else(|| {
67                        AccountComponentTemplateError::PlaceholderValueNotProvided(
68                            storage_placeholder.clone(),
69                        )
70                    })?
71                    .as_word()?;
72                Ok(*user_value)
73            },
74        }
75    }
76}
77
78impl From<Word> for WordRepresentation {
79    fn from(value: Word) -> Self {
80        WordRepresentation::Value(value)
81    }
82}
83
84impl Serializable for WordRepresentation {
85    fn write_into<W: ByteWriter>(&self, target: &mut W) {
86        match self {
87            WordRepresentation::Value(value) => {
88                target.write_u8(0);
89                target.write(value);
90            },
91            WordRepresentation::Array(value) => {
92                target.write_u8(1);
93                target.write(value);
94            },
95            WordRepresentation::Template(storage_placeholder) => {
96                target.write_u8(2);
97                target.write(storage_placeholder);
98            },
99        }
100    }
101}
102
103impl Deserializable for WordRepresentation {
104    fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
105        let variant_tag = source.read_u8()?;
106
107        match variant_tag {
108            0 => {
109                // Hexadecimal
110                let value = <[Felt; 4]>::read_from(source)?;
111                Ok(WordRepresentation::Value(value))
112            },
113            1 => {
114                // Array
115                let value = <[FeltRepresentation; 4]>::read_from(source)?;
116                Ok(WordRepresentation::Array(value))
117            },
118            2 => {
119                // Template
120                let storage_placeholder = StoragePlaceholder::read_from(source)?;
121                Ok(WordRepresentation::Template(storage_placeholder))
122            },
123            _ => Err(DeserializationError::InvalidValue(format!(
124                "unknown variant tag for WordRepresentation: {variant_tag}"
125            ))),
126        }
127    }
128}
129
130impl Default for WordRepresentation {
131    fn default() -> Self {
132        WordRepresentation::Value(Default::default())
133    }
134}
135
136impl core::fmt::Display for WordRepresentation {
137    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
138        match self {
139            WordRepresentation::Value(hex) => f.write_str(&Digest::from(hex).to_hex()),
140            WordRepresentation::Array(array) => {
141                f.write_str("[")?;
142                f.write_fmt(format_args!("{}, ", array[0]))?;
143                f.write_fmt(format_args!("{}, ", array[1]))?;
144                f.write_fmt(format_args!("{}, ", array[2]))?;
145                f.write_fmt(format_args!("{}, ", array[3]))?;
146
147                f.write_str("]")
148            },
149            WordRepresentation::Template(storage_placeholder) => {
150                f.write_fmt(format_args!("{}", storage_placeholder))
151            },
152        }
153    }
154}
155
156// FELTS
157// ================================================================================================
158
159/// Supported element representations for a component's storage entries.
160#[derive(Debug, Clone, PartialEq, Eq)]
161pub enum FeltRepresentation {
162    /// Hexadecimal representation of a field element.
163    Hexadecimal(Felt),
164    /// Single decimal representation of a field element.
165    Decimal(Felt),
166    /// A placeholder value, represented as "{{key}}".
167    Template(StoragePlaceholder),
168}
169
170impl FeltRepresentation {
171    /// Returns the storage placeholders within this representation, alongside their expected type.
172    pub fn all_placeholders_iter(
173        &self,
174    ) -> impl Iterator<Item = (&StoragePlaceholder, PlaceholderType)> {
175        let maybe_key = match self {
176            FeltRepresentation::Template(storage_placeholder) => {
177                Some((storage_placeholder, PlaceholderType::Felt))
178            },
179            _ => None,
180        };
181
182        maybe_key.into_iter()
183    }
184
185    /// Attempts to convert the [FeltRepresentation] into a [Felt].
186    ///
187    /// If the representation is a template, the value is retrieved from `init_storage_data`,
188    /// identified by its key. Otherwise, the returned value is just the inner element.
189    pub fn try_build_felt(
190        self,
191        init_storage_data: &InitStorageData,
192    ) -> Result<Felt, AccountComponentTemplateError> {
193        match self {
194            FeltRepresentation::Hexadecimal(base_element) => Ok(base_element),
195            FeltRepresentation::Decimal(base_element) => Ok(base_element),
196            FeltRepresentation::Template(storage_placeholder) => init_storage_data
197                .get(&storage_placeholder)
198                .ok_or(AccountComponentTemplateError::PlaceholderValueNotProvided(
199                    storage_placeholder,
200                ))?
201                .as_felt()
202                .copied(),
203        }
204    }
205}
206
207impl Default for FeltRepresentation {
208    fn default() -> Self {
209        FeltRepresentation::Hexadecimal(Felt::default())
210    }
211}
212
213impl Serializable for FeltRepresentation {
214    fn write_into<W: ByteWriter>(&self, target: &mut W) {
215        match self {
216            FeltRepresentation::Hexadecimal(felt) => {
217                target.write_u8(0);
218                target.write(felt);
219            },
220            FeltRepresentation::Decimal(felt) => {
221                target.write_u8(1);
222                target.write(felt);
223            },
224            FeltRepresentation::Template(storage_placeholder) => {
225                target.write_u8(2);
226                target.write(storage_placeholder);
227            },
228        }
229    }
230}
231
232impl Deserializable for FeltRepresentation {
233    fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
234        let variant_tag = source.read_u8()?;
235
236        match variant_tag {
237            0 => {
238                // Hexadecimal
239                let felt = Felt::read_from(source)?;
240                Ok(FeltRepresentation::Hexadecimal(felt))
241            },
242            1 => {
243                // Decimal
244                let felt = Felt::read_from(source)?;
245                Ok(FeltRepresentation::Decimal(felt))
246            },
247            2 => {
248                // Template
249                let storage_placeholder = StoragePlaceholder::read_from(source)?;
250                Ok(FeltRepresentation::Template(storage_placeholder))
251            },
252            _ => Err(DeserializationError::InvalidValue(format!(
253                "unknown variant tag for FeltRepresentation: {}",
254                variant_tag
255            ))),
256        }
257    }
258}
259
260impl core::fmt::Display for FeltRepresentation {
261    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
262        match self {
263            FeltRepresentation::Hexadecimal(base_element) => {
264                f.write_fmt(format_args!("{}", base_element))
265            },
266            FeltRepresentation::Decimal(base_element) => {
267                f.write_fmt(format_args!("{}", base_element))
268            },
269            FeltRepresentation::Template(storage_placeholder) => {
270                f.write_fmt(format_args!("{}", storage_placeholder))
271            },
272        }
273    }
274}
275
276// MAP REPRESENTATION
277// ================================================================================================
278
279/// Supported map representations for a component's storage entries.
280#[derive(Debug, Clone, PartialEq, Eq)]
281#[cfg_attr(feature = "std", derive(::serde::Deserialize, ::serde::Serialize))]
282#[cfg_attr(feature = "std", serde(untagged))]
283pub enum MapRepresentation {
284    List(Vec<MapEntry>),
285    Template(StoragePlaceholder),
286}
287
288impl MapRepresentation {
289    /// Returns an iterator over all of the storage entries's placeholder keys, alongside their
290    /// expected type.
291    pub fn all_placeholders_iter(
292        &self,
293    ) -> Box<dyn Iterator<Item = (&StoragePlaceholder, PlaceholderType)> + '_> {
294        match self {
295            MapRepresentation::Template(storage_placeholder) => {
296                Box::new(core::iter::once((storage_placeholder, PlaceholderType::Map)))
297            },
298            MapRepresentation::List(entries) => {
299                Box::new(entries.iter().flat_map(|entry| entry.all_placeholders_iter()))
300            },
301        }
302    }
303
304    /// Returns the amount of key-value pairs in the entry, or `None` if the representation is a
305    /// placeholder.
306    pub fn len(&self) -> Option<usize> {
307        match self {
308            MapRepresentation::List(vec) => Some(vec.len()),
309            MapRepresentation::Template(_) => None,
310        }
311    }
312
313    /// Returns `true` if the map is represented by a list of key-value entries, and the list is
314    /// empty. Returns false otherwise
315    pub fn is_empty(&self) -> bool {
316        match self {
317            MapRepresentation::List(vec) => vec.is_empty(),
318            MapRepresentation::Template(_) => false,
319        }
320    }
321
322    /// Attempts to convert the [MapRepresentation] into a [StorageMap].
323    ///
324    /// If the representation is a template, the value is retrieved from
325    /// `init_storage_data`, identified by its key. If any of the inner elements
326    /// within the value are a template, they are retrieved in the same way.
327    pub fn try_build_map(
328        &self,
329        init_storage_data: &InitStorageData,
330    ) -> Result<StorageMap, AccountComponentTemplateError> {
331        let map = match self {
332            MapRepresentation::List(vec) => {
333                let entries = vec
334                    .iter()
335                    .map(|map_entry| {
336                        let key = map_entry.key().try_build_word(init_storage_data)?;
337                        let value = map_entry.value().try_build_word(init_storage_data)?;
338                        Ok((key.into(), value))
339                    })
340                    .collect::<Result<Vec<(Digest, Word)>, _>>()?;
341
342                // validate that no key appears multiple times
343                let mut seen_keys = BTreeSet::new();
344                for (map_key, _map_value) in entries.iter() {
345                    if !seen_keys.insert(map_key) {
346                        return Err(AccountComponentTemplateError::StorageMapHasDuplicateKeys(
347                            map_key.to_hex(),
348                        ));
349                    }
350                }
351
352                StorageMap::with_entries(entries)
353            },
354            MapRepresentation::Template(storage_placeholder) => init_storage_data
355                .get(storage_placeholder)
356                .ok_or_else(|| {
357                    AccountComponentTemplateError::PlaceholderValueNotProvided(
358                        storage_placeholder.clone(),
359                    )
360                })?
361                .as_map()
362                .cloned()?,
363        };
364
365        Ok(map)
366    }
367
368    /// Validates map keys by checking for duplicates.
369    ///
370    /// Because keys can be represented in a variety of ways, the `to_string()` implementation is
371    /// used to check for duplicates.  
372    pub(crate) fn validate(&self) -> Result<(), AccountComponentTemplateError> {
373        match self {
374            MapRepresentation::List(entries) => {
375                let mut seen_keys = BTreeSet::new();
376                for entry in entries {
377                    if !seen_keys.insert(entry.key().to_string()) {
378                        return Err(AccountComponentTemplateError::StorageMapHasDuplicateKeys(
379                            entry.key().to_string(),
380                        ));
381                    }
382                }
383            },
384            MapRepresentation::Template(_) => {},
385        }
386        Ok(())
387    }
388}
389
390impl Serializable for MapRepresentation {
391    fn write_into<W: ByteWriter>(&self, target: &mut W) {
392        match self {
393            MapRepresentation::List(entries) => {
394                target.write_u8(0);
395                entries.write_into(target);
396            },
397            MapRepresentation::Template(storage_placeholder) => {
398                target.write_u8(1);
399                storage_placeholder.write_into(target);
400            },
401        }
402    }
403}
404
405impl Deserializable for MapRepresentation {
406    fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
407        match source.read_u8()? {
408            0 => Ok(MapRepresentation::List(Vec::<MapEntry>::read_from(source)?)),
409            1 => Ok(MapRepresentation::Template(StoragePlaceholder::read_from(source)?)),
410            other => Err(DeserializationError::InvalidValue(format!(
411                "Unknown variant tag for MapRepresentation: {}",
412                other
413            ))),
414        }
415    }
416}
417
418// TESTS
419// ================================================================================================
420
421#[cfg(test)]
422mod tests {
423    use vm_core::{
424        utils::{Deserializable, Serializable},
425        Felt, Word,
426    };
427
428    use crate::account::component::template::{
429        storage::{FeltRepresentation, StorageValue, WordRepresentation},
430        InitStorageData, StoragePlaceholder,
431    };
432
433    #[test]
434    fn test_storage_placeholder_try_from_str() {
435        let invalid_strings = vec![
436            "{invalid}",
437            "no_braces",
438            "{{unclosed",
439            "unopened}}",
440            "{}",
441            "{{}}",
442            "{{.}}",
443            "{{foo..bar}}",
444        ];
445
446        for s in invalid_strings {
447            let result = StoragePlaceholder::try_from(s);
448            result.unwrap_err();
449        }
450
451        let s = "{{storage_placeholder}}";
452        let tk = StoragePlaceholder::try_from(s).unwrap();
453        assert_eq!(tk.inner(), "storage_placeholder");
454    }
455
456    #[test]
457    fn test_storage_placeholder_serialization_deserialization() {
458        let original = StoragePlaceholder::new("serialize_test").unwrap();
459        let serialized = original.to_bytes();
460        let deserialized = StoragePlaceholder::read_from_bytes(&serialized).unwrap();
461        assert_eq!(original, deserialized);
462    }
463
464    #[test]
465    fn test_felt_representation_serde() {
466        let felt = Felt::new(1234);
467        let original = FeltRepresentation::Hexadecimal(felt);
468        let serialized = original.to_bytes();
469        let deserialized = FeltRepresentation::read_from_bytes(&serialized).unwrap();
470        assert_eq!(original, deserialized);
471
472        let felt = Felt::new(45563);
473        let original = FeltRepresentation::Decimal(felt);
474        let serialized = original.to_bytes();
475        let deserialized = FeltRepresentation::read_from_bytes(&serialized).unwrap();
476        assert_eq!(original, deserialized);
477
478        let storage_placeholder = StoragePlaceholder::new("template_felt").unwrap();
479        let original = FeltRepresentation::Template(storage_placeholder.clone());
480        let serialized = original.to_bytes();
481        let deserialized = FeltRepresentation::read_from_bytes(&serialized).unwrap();
482        assert_eq!(original, deserialized);
483    }
484
485    #[test]
486    fn test_felt_representation_try_build_felt() {
487        let dyn_key = StoragePlaceholder::new("felt_key").unwrap();
488        let template = FeltRepresentation::Template(dyn_key.clone());
489        let init_storage_data = InitStorageData::new([(
490            StoragePlaceholder::new("felt_key").unwrap(),
491            StorageValue::Felt(Felt::new(300)),
492        )]);
493        let built = template.try_build_felt(&init_storage_data).unwrap();
494        assert_eq!(built, Felt::new(300));
495
496        let dyn_key = StoragePlaceholder::new("missing_key").unwrap();
497        let template = FeltRepresentation::Template(dyn_key.clone());
498        let result = template.try_build_felt(&init_storage_data);
499        result.unwrap_err();
500    }
501
502    #[test]
503    fn test_word_representation_serde() {
504        let word = Word::default();
505        let original = WordRepresentation::Value(word);
506        let serialized = original.to_bytes();
507        let deserialized = WordRepresentation::read_from_bytes(&serialized).unwrap();
508        assert_eq!(original, deserialized);
509
510        let array = [
511            FeltRepresentation::Hexadecimal(Felt::new(10)),
512            FeltRepresentation::Decimal(Felt::new(20)),
513            FeltRepresentation::Template(StoragePlaceholder::new("word_key1").unwrap()),
514            FeltRepresentation::Template(StoragePlaceholder::new("word_key2").unwrap()),
515        ];
516        let original = WordRepresentation::Array(array);
517        let serialized = original.to_bytes();
518        let deserialized = WordRepresentation::read_from_bytes(&serialized).unwrap();
519        assert_eq!(original, deserialized);
520    }
521
522    #[test]
523    fn test_word_representation_template_serde() {
524        let storage_placeholder = StoragePlaceholder::new("temlpate_word").unwrap();
525        let original = WordRepresentation::Template(storage_placeholder.clone());
526        let serialized = original.to_bytes();
527        let deserialized = WordRepresentation::read_from_bytes(&serialized).unwrap();
528        assert_eq!(original, deserialized);
529    }
530}