1use hiero_sdk_proto::services;
2
3use crate::hooks::EvmHookStorageSlot;
4use crate::{
5 FromProtobuf,
6 ToProtobuf,
7};
8
9#[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; 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; 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 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 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}