aurora_evm/core/
memory.rs1use super::prelude::*;
2use super::utils::USIZE_MAX;
3use crate::{ExitError, ExitFatal};
4use core::cmp::min;
5use core::ops::{BitAnd, Not};
6use primitive_types::{H256, U256};
7
8#[derive(Clone, Debug)]
11pub struct Memory {
12 data: Vec<u8>,
14 effective_len: usize,
16 limit: usize,
18}
19
20impl Memory {
21 #[must_use]
23 pub const fn new(limit: usize) -> Self {
24 Self {
25 data: Vec::new(),
26 effective_len: 0,
27 limit,
28 }
29 }
30
31 #[must_use]
33 pub const fn limit(&self) -> usize {
34 self.limit
35 }
36
37 #[must_use]
39 #[allow(clippy::missing_const_for_fn)]
41 pub fn len(&self) -> usize {
42 self.data.len()
43 }
44
45 #[must_use]
47 pub const fn effective_len(&self) -> usize {
48 self.effective_len
49 }
50
51 #[must_use]
53 #[allow(clippy::missing_const_for_fn)]
55 pub fn is_empty(&self) -> bool {
56 self.len() == 0
57 }
58
59 #[must_use]
61 pub const fn data(&self) -> &Vec<u8> {
62 &self.data
63 }
64
65 pub fn resize_offset(&mut self, offset: usize, len: usize) -> Result<(), ExitError> {
71 if len == 0 {
72 return Ok(());
73 }
74
75 offset
76 .checked_add(len)
77 .map_or(Err(ExitError::InvalidRange), |end| self.resize_end(end))
78 }
79
80 pub fn resize_end(&mut self, end: usize) -> Result<(), ExitError> {
85 if end > self.effective_len {
86 let new_end = next_multiple_of_32(end).ok_or(ExitError::InvalidRange)?;
87 self.effective_len = new_end;
88 }
89
90 Ok(())
91 }
92
93 #[must_use]
100 pub fn get(&self, mut offset: usize, size: usize) -> Vec<u8> {
101 if offset > self.data.len() {
102 offset = self.data.len();
103 }
104
105 let mut end = offset + size;
106 if end > self.data.len() {
107 end = self.data.len();
108 }
109
110 let mut ret = self.data[offset..end].to_vec();
111 ret.resize(size, 0);
112 ret
113 }
114
115 #[must_use]
117 pub fn get_h256(&self, offset: usize) -> H256 {
118 let mut ret = [0; 32];
119
120 let data_len = self.data.len();
121 if offset >= data_len {
122 return H256(ret);
123 }
124 let available_bytes = data_len - offset;
125 let count = 32.min(available_bytes);
126 ret[..count].copy_from_slice(&self.data[offset..offset + count]);
127
128 H256(ret)
129 }
130
131 pub fn set(
137 &mut self,
138 offset: usize,
139 value: &[u8],
140 target_size: usize,
141 ) -> Result<(), ExitFatal> {
142 if target_size == 0 {
143 return Ok(());
144 }
145
146 let end_offset = match offset.checked_add(target_size) {
147 Some(pos) if pos <= self.limit => pos,
148 _ => return Err(ExitFatal::NotSupported),
149 };
150
151 if self.data.len() < end_offset {
152 self.data.resize(end_offset, 0);
153 }
154
155 let copy_len = min(value.len(), target_size);
156 let dest_slice = &mut self.data[offset..end_offset];
157 if copy_len > 0 {
158 dest_slice[..copy_len].copy_from_slice(&value[..copy_len]);
159 }
160
161 if target_size > copy_len {
162 dest_slice[copy_len..].fill(0);
163 }
164
165 Ok(())
166 }
167
168 pub fn copy(
176 &mut self,
177 src_offset: usize,
178 dst_offset: usize,
179 length: usize,
180 ) -> Result<(), ExitFatal> {
181 if length == 0 {
183 return Ok(());
184 }
185
186 let offset = core::cmp::max(src_offset, dst_offset);
188 let offset_length = offset
189 .checked_add(length)
190 .ok_or_else(|| ExitFatal::Other(Cow::from("OverflowOnCopy")))?;
191 if offset_length > self.limit {
192 return Err(ExitFatal::Other(Cow::from("OutOfGasOnCopy")));
193 }
194
195 if self.data.len() < offset_length {
197 self.data.resize(offset_length, 0);
198 }
199
200 self.data
201 .copy_within(src_offset..src_offset + length, dst_offset);
202 Ok(())
203 }
204
205 pub fn copy_data(
216 &mut self,
217 memory_offset: usize,
218 data_offset: U256,
219 length: usize,
220 data: &[u8],
221 ) -> Result<(), ExitFatal> {
222 if length == 0 {
224 return Ok(());
225 }
226
227 let dest_end_offset = match memory_offset.checked_add(length) {
229 Some(pos) if pos <= self.limit => pos,
230 _ => return Err(ExitFatal::NotSupported), };
232
233 if self.data.len() < dest_end_offset {
236 self.data.resize(dest_end_offset, 0);
237 }
238
239 let dest_slice = &mut self.data[memory_offset..dest_end_offset];
243
244 if data_offset > USIZE_MAX {
246 dest_slice.fill(0);
247 return Ok(());
248 }
249 let data_offset = data_offset.as_usize();
250 if data_offset > data.len() {
251 dest_slice.fill(0);
252 return Ok(());
253 }
254 let actual_len = data.len() - data_offset;
256 let copy_len = min(actual_len, length);
258 if copy_len > 0 {
260 dest_slice[..copy_len].copy_from_slice(&data[data_offset..data_offset + copy_len]);
261 }
262 if length > copy_len {
263 dest_slice[copy_len..].fill(0);
264 }
265 Ok(())
266 }
267}
268
269#[inline]
271fn next_multiple_of_32(x: usize) -> Option<usize> {
272 let r = x.bitand(31).not().wrapping_add(1).bitand(31);
273 x.checked_add(r)
274}
275
276#[cfg(test)]
277mod tests {
278 use super::next_multiple_of_32;
279
280 #[test]
281 fn test_next_multiple_of_32() {
282 for i in 0..32 {
284 let x = i * 32;
285 assert_eq!(Some(x), next_multiple_of_32(x));
286 }
287
288 for x in 0..1024 {
290 if x % 32 == 0 {
291 continue;
292 }
293 let next_multiple = x + 32 - (x % 32);
294 assert_eq!(Some(next_multiple), next_multiple_of_32(x));
295 }
296
297 let last_multiple_of_32 = usize::MAX & !31;
299 for i in 0..63 {
300 let x = usize::MAX - i;
301 if x > last_multiple_of_32 {
302 assert_eq!(None, next_multiple_of_32(x));
303 } else {
304 assert_eq!(Some(last_multiple_of_32), next_multiple_of_32(x));
305 }
306 }
307 }
308}