stratus/eth/primitives/
slot_index.rs

1use std::fmt::Display;
2use std::io::Read;
3
4use alloy_primitives::FixedBytes;
5use alloy_primitives::U256;
6use alloy_primitives::keccak256;
7use display_json::DebugAsJson;
8#[cfg(test)]
9use fake::Dummy;
10#[cfg(test)]
11use fake::Faker;
12
13#[derive(DebugAsJson, Clone, Copy, Default, Hash, Eq, PartialEq, PartialOrd, Ord, serde::Serialize, serde::Deserialize)]
14pub struct SlotIndex(pub U256);
15
16impl SlotIndex {
17    pub const ZERO: SlotIndex = SlotIndex(U256::ZERO);
18    pub const ONE: SlotIndex = SlotIndex(U256::ONE);
19
20    /// Computes the mapping index of a key.
21    pub fn to_mapping_index(&self, key: Vec<u8>) -> SlotIndex {
22        // populate self to bytes
23        let slot_index_bytes: [u8; 32] = self.0.to_be_bytes();
24
25        // populate key to bytes
26        let mut key_bytes = [0u8; 32];
27        let _ = key.take(32).read(&mut key_bytes[32usize.saturating_sub(key.len())..32]);
28
29        // populate value to be hashed to bytes
30        let mut mapping_index_bytes = [0u8; 64];
31        mapping_index_bytes[0..32].copy_from_slice(&key_bytes);
32        mapping_index_bytes[32..64].copy_from_slice(&slot_index_bytes);
33
34        let hashed_bytes = keccak256(mapping_index_bytes);
35        Self::from(hashed_bytes)
36    }
37}
38
39#[cfg(test)]
40impl Dummy<Faker> for SlotIndex {
41    fn dummy_with_rng<R: rand::Rng + ?Sized>(_: &Faker, rng: &mut R) -> Self {
42        Self(U256::random_with(rng))
43    }
44}
45
46impl Display for SlotIndex {
47    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
48        write!(f, "{:#x}", self.0)
49    }
50}
51
52// -----------------------------------------------------------------------------
53// Conversions: Other -> Self
54// -----------------------------------------------------------------------------
55
56impl From<U256> for SlotIndex {
57    fn from(value: U256) -> Self {
58        Self(value)
59    }
60}
61
62impl From<[u8; 32]> for SlotIndex {
63    fn from(value: [u8; 32]) -> Self {
64        Self(U256::from_be_bytes(value))
65    }
66}
67
68impl From<[u64; 4]> for SlotIndex {
69    fn from(value: [u64; 4]) -> Self {
70        Self(U256::from_limbs(value))
71    }
72}
73
74impl From<FixedBytes<32>> for SlotIndex {
75    fn from(value: FixedBytes<32>) -> Self {
76        Self::from(value.0)
77    }
78}
79
80// -----------------------------------------------------------------------------
81// Tests
82// -----------------------------------------------------------------------------
83
84#[cfg(test)]
85mod tests {
86    use hex_literal::hex;
87
88    use crate::eth::primitives::SlotIndex;
89
90    #[test]
91    fn slot_index_to_mapping_index() {
92        let address = hex!("3c44cdddb6a900fa2b585dd299e03d12fa4293bc").to_vec();
93        let hashed = SlotIndex::ZERO.to_mapping_index(address);
94        assert_eq!(hashed.to_string(), "0x215be5d23550ceb1beff54fb579a765903ba2ccc85b6f79bcf9bda4e8cb86034");
95    }
96}