Skip to main content

hiero_sdk/hooks/
evm_hook_storage_update.rs

1use hiero_sdk_proto::services;
2
3use crate::hooks::EvmHookStorageSlot;
4use crate::{
5    FromProtobuf,
6    ToProtobuf,
7};
8
9/// A lambda storage update containing either a storage slot or mapping entries.
10#[derive(Debug, Clone, PartialEq, Eq)]
11pub enum EvmHookStorageUpdate {
12    StorageSlot(EvmHookStorageSlot),
13    MappingEntries(EvmHookMappingEntries),
14}
15
16#[derive(Debug, Clone, PartialEq, Eq)]
17pub struct EvmHookMappingEntries {
18    pub mapping_slot: Vec<u8>,
19    pub entries: Vec<EvmHookMappingEntry>,
20}
21
22#[derive(Debug, Clone, PartialEq, Eq)]
23pub struct EvmHookMappingEntry {
24    pub key: Option<Vec<u8>>,
25    pub value: Option<Vec<u8>>,
26    pub preimage: Option<Vec<u8>>,
27}
28
29impl EvmHookStorageUpdate {}
30
31impl EvmHookMappingEntries {
32    pub fn new(mapping_slot: Vec<u8>, entries: Vec<EvmHookMappingEntry>) -> Self {
33        Self { mapping_slot, entries }
34    }
35}
36
37impl EvmHookMappingEntry {
38    pub fn new(key: Option<Vec<u8>>, value: Option<Vec<u8>>) -> Self {
39        Self { key, value, preimage: None }
40    }
41
42    pub fn set_key(&mut self, key: Vec<u8>) -> &mut Self {
43        self.key = Some(key);
44        self.preimage = None; // Clear preimage since they're mutually exclusive
45        self
46    }
47
48    pub fn set_value(&mut self, value: Vec<u8>) -> &mut Self {
49        self.value = Some(value);
50        self
51    }
52
53    pub fn set_preimage(&mut self, preimage: Vec<u8>) -> &mut Self {
54        self.preimage = Some(preimage);
55        self.key = None; // Clear key since they're mutually exclusive
56        self
57    }
58}
59
60impl ToProtobuf for EvmHookStorageUpdate {
61    type Protobuf = services::EvmHookStorageUpdate;
62
63    fn to_protobuf(&self) -> Self::Protobuf {
64        match self {
65            Self::StorageSlot(slot) => services::EvmHookStorageUpdate {
66                update: Some(services::evm_hook_storage_update::Update::StorageSlot(
67                    slot.to_protobuf(),
68                )),
69            },
70            Self::MappingEntries(entries) => services::EvmHookStorageUpdate {
71                update: Some(services::evm_hook_storage_update::Update::MappingEntries(
72                    entries.to_protobuf(),
73                )),
74            },
75        }
76    }
77}
78
79impl FromProtobuf<services::EvmHookStorageUpdate> for EvmHookStorageUpdate {
80    fn from_protobuf(pb: services::EvmHookStorageUpdate) -> crate::Result<Self> {
81        match pb.update {
82            Some(services::evm_hook_storage_update::Update::StorageSlot(slot)) => {
83                Ok(Self::StorageSlot(EvmHookStorageSlot::from_protobuf(slot)?))
84            }
85            Some(services::evm_hook_storage_update::Update::MappingEntries(entries)) => {
86                Ok(Self::MappingEntries(EvmHookMappingEntries::from_protobuf(entries)?))
87            }
88            None => Err(crate::Error::basic_parse(
89                "EvmHookStorageUpdate must have either storage_slot or mapping_entries",
90            )),
91        }
92    }
93}
94
95impl ToProtobuf for EvmHookMappingEntries {
96    type Protobuf = services::EvmHookMappingEntries;
97
98    fn to_protobuf(&self) -> Self::Protobuf {
99        services::EvmHookMappingEntries {
100            mapping_slot: self.mapping_slot.clone(),
101            entries: self.entries.iter().map(|entry| entry.to_protobuf()).collect(),
102        }
103    }
104}
105
106impl FromProtobuf<services::EvmHookMappingEntries> for EvmHookMappingEntries {
107    fn from_protobuf(pb: services::EvmHookMappingEntries) -> crate::Result<Self> {
108        let entries = pb
109            .entries
110            .into_iter()
111            .map(EvmHookMappingEntry::from_protobuf)
112            .collect::<Result<Vec<_>, _>>()?;
113
114        Ok(Self { mapping_slot: pb.mapping_slot, entries })
115    }
116}
117
118impl ToProtobuf for EvmHookMappingEntry {
119    type Protobuf = services::EvmHookMappingEntry;
120
121    fn to_protobuf(&self) -> Self::Protobuf {
122        let entry_key = if let Some(key) = &self.key {
123            Some(services::evm_hook_mapping_entry::EntryKey::Key(key.clone()))
124        } else if let Some(preimage) = &self.preimage {
125            Some(services::evm_hook_mapping_entry::EntryKey::Preimage(preimage.clone()))
126        } else {
127            None
128        };
129
130        services::EvmHookMappingEntry { entry_key, value: self.value.clone().unwrap_or_default() }
131    }
132}
133
134impl FromProtobuf<services::EvmHookMappingEntry> for EvmHookMappingEntry {
135    fn from_protobuf(pb: services::EvmHookMappingEntry) -> crate::Result<Self> {
136        let (key, preimage) = match pb.entry_key {
137            Some(services::evm_hook_mapping_entry::EntryKey::Key(k)) => (Some(k), None),
138            Some(services::evm_hook_mapping_entry::EntryKey::Preimage(p)) => (None, Some(p)),
139            None => (None, None),
140        };
141
142        Ok(Self { key, value: if pb.value.is_empty() { None } else { Some(pb.value) }, preimage })
143    }
144}
145
146#[cfg(test)]
147mod tests {
148    use super::*;
149
150    #[test]
151    fn test_evm_hook_mapping_entry_creation() {
152        let entry = EvmHookMappingEntry::new(Some(vec![1, 2, 3]), Some(vec![4, 5, 6]));
153        assert_eq!(entry.key, Some(vec![1, 2, 3]));
154        assert_eq!(entry.value, Some(vec![4, 5, 6]));
155        assert_eq!(entry.preimage, None);
156    }
157
158    #[test]
159    fn test_evm_hook_mapping_entry_with_preimage() {
160        let mut entry = EvmHookMappingEntry::new(None, Some(vec![10, 11, 12]));
161        entry.set_preimage(vec![7, 8, 9]);
162        assert_eq!(entry.key, None);
163        assert_eq!(entry.preimage, Some(vec![7, 8, 9]));
164        assert_eq!(entry.value, Some(vec![10, 11, 12]));
165    }
166
167    #[test]
168    fn test_evm_hook_mapping_entry_setters() {
169        let mut entry = EvmHookMappingEntry::new(None, None);
170        entry.set_key(vec![7, 8, 9]).set_value(vec![10, 11, 12]);
171
172        assert_eq!(entry.key, Some(vec![7, 8, 9]));
173        assert_eq!(entry.value, Some(vec![10, 11, 12]));
174        assert_eq!(entry.preimage, None);
175    }
176
177    #[test]
178    fn test_evm_hook_mapping_entry_key_preimage_mutual_exclusion() {
179        let mut entry = EvmHookMappingEntry::new(Some(vec![1, 2, 3]), None);
180        assert_eq!(entry.key, Some(vec![1, 2, 3]));
181        assert_eq!(entry.preimage, None);
182
183        // Setting preimage should clear key
184        entry.set_preimage(vec![4, 5, 6]);
185        assert_eq!(entry.key, None);
186        assert_eq!(entry.preimage, Some(vec![4, 5, 6]));
187
188        // Setting key should clear preimage
189        entry.set_key(vec![7, 8, 9]);
190        assert_eq!(entry.key, Some(vec![7, 8, 9]));
191        assert_eq!(entry.preimage, None);
192    }
193
194    #[test]
195    fn test_evm_hook_mapping_entry_protobuf_roundtrip() {
196        let original = EvmHookMappingEntry::new(Some(vec![1, 2, 3]), Some(vec![4, 5, 6]));
197        let protobuf = original.to_protobuf();
198        let reconstructed = EvmHookMappingEntry::from_protobuf(protobuf).unwrap();
199
200        assert_eq!(original, reconstructed);
201    }
202}