Skip to main content

miden_protocol/account/storage/slot/
slot_id.rs

1use core::cmp::Ordering;
2use core::fmt::Display;
3use core::hash::Hash;
4
5use miden_core::utils::hash_string_to_word;
6
7use crate::Felt;
8use crate::utils::serde::{
9    ByteReader,
10    ByteWriter,
11    Deserializable,
12    DeserializationError,
13    Serializable,
14};
15
16/// The partial hash of a [`StorageSlotName`](super::StorageSlotName).
17///
18/// The ID of a slot are the first (`suffix`) and second (`prefix`) field elements of the
19/// blake3-hashed slot name.
20///
21/// The slot ID is used to uniquely identify a storage slot and is used to sort slots in account
22/// storage.
23#[derive(Debug, Clone, Copy, PartialEq, Eq)]
24pub struct StorageSlotId {
25    suffix: Felt,
26    prefix: Felt,
27}
28
29impl StorageSlotId {
30    // CONSTRUCTORS
31    // --------------------------------------------------------------------------------------------
32
33    /// Creates a new [`StorageSlotId`] from the provided felts.
34    pub fn new(suffix: Felt, prefix: Felt) -> Self {
35        Self { suffix, prefix }
36    }
37
38    /// Computes the [`StorageSlotId`] from a slot name.
39    ///
40    /// The provided `name`'s validity is **not** checked.
41    pub(super) fn from_str(name: &str) -> StorageSlotId {
42        let hashed_word = hash_string_to_word(name);
43        let suffix = hashed_word[0];
44        let prefix = hashed_word[1];
45        StorageSlotId::new(suffix, prefix)
46    }
47
48    // ACCESSORS
49    // --------------------------------------------------------------------------------------------
50
51    /// Returns the suffix of the [`StorageSlotId`].
52    pub fn suffix(&self) -> Felt {
53        self.suffix
54    }
55
56    /// Returns the prefix of the [`StorageSlotId`].
57    pub fn prefix(&self) -> Felt {
58        self.prefix
59    }
60
61    /// Returns the [`StorageSlotId`]'s felts encoded into a u128.
62    fn as_u128(&self) -> u128 {
63        let mut le_bytes = [0_u8; 16];
64        le_bytes[..8].copy_from_slice(&self.suffix().as_int().to_le_bytes());
65        le_bytes[8..].copy_from_slice(&self.prefix().as_int().to_le_bytes());
66        u128::from_le_bytes(le_bytes)
67    }
68}
69
70impl Ord for StorageSlotId {
71    fn cmp(&self, other: &Self) -> Ordering {
72        match self.prefix.as_int().cmp(&other.prefix.as_int()) {
73            ord @ Ordering::Less | ord @ Ordering::Greater => ord,
74            Ordering::Equal => self.suffix.as_int().cmp(&other.suffix.as_int()),
75        }
76    }
77}
78
79impl PartialOrd for StorageSlotId {
80    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
81        Some(self.cmp(other))
82    }
83}
84
85impl Hash for StorageSlotId {
86    fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
87        self.suffix.inner().hash(state);
88        self.prefix.inner().hash(state);
89    }
90}
91
92impl Display for StorageSlotId {
93    /// Returns a big-endian, hex-encoded string of length 34, including the `0x` prefix.
94    ///
95    /// This means it encodes 16 bytes.
96    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
97        f.write_fmt(format_args!("0x{:032x}", self.as_u128()))
98    }
99}
100
101impl Serializable for StorageSlotId {
102    fn write_into<W: ByteWriter>(&self, target: &mut W) {
103        self.suffix.write_into(target);
104        self.prefix.write_into(target);
105    }
106}
107
108impl Deserializable for StorageSlotId {
109    fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
110        let suffix = Felt::read_from(source)?;
111        let prefix = Felt::read_from(source)?;
112        Ok(StorageSlotId::new(suffix, prefix))
113    }
114}
115
116// TESTS
117// ================================================================================================
118
119#[cfg(test)]
120mod tests {
121    use super::*;
122
123    #[test]
124    fn test_slot_id_as_u128() {
125        let suffix = 5;
126        let prefix = 3;
127        let slot_id = StorageSlotId::new(Felt::from(suffix as u32), Felt::from(prefix as u32));
128        assert_eq!(slot_id.as_u128(), (prefix << 64) + suffix);
129        assert_eq!(format!("{slot_id}"), "0x00000000000000030000000000000005");
130    }
131}