use crate::{vm::evm::Halt, Config, Error};
use alloc::vec::Vec;
use core::ops::{ControlFlow, Range};
#[derive(Debug, Clone)]
pub struct Memory<T> {
data: Vec<u8>,
_phantom: core::marker::PhantomData<T>,
}
impl<T: Config> Memory<T> {
pub fn new() -> Self {
Self { data: Vec::with_capacity(4 * 1024), _phantom: core::marker::PhantomData }
}
pub fn slice(&self, range: Range<usize>) -> &[u8] {
if range.is_empty() {
return &[]
}
&self.data[range]
}
pub fn slice_mut(&mut self, offset: usize, len: usize) -> &mut [u8] {
&mut self.data[offset..offset + len]
}
pub fn size(&self) -> usize {
self.data.len()
}
pub fn resize(&mut self, offset: usize, len: usize) -> ControlFlow<Halt> {
let current_len = self.data.len();
let target_len = revm::interpreter::num_words(offset.saturating_add(len)) * 32;
if target_len > crate::limits::EVM_MEMORY_BYTES as usize {
log::debug!(target: crate::LOG_TARGET, "check memory bounds failed: offset={offset} target_len={target_len} current_len={current_len}");
return ControlFlow::Break(Error::<T>::OutOfGas.into());
}
if target_len > current_len {
self.data.resize(target_len, 0);
}
ControlFlow::Continue(())
}
pub fn set(&mut self, offset: usize, data: &[u8]) {
if !data.is_empty() {
self.data[offset..offset + data.len()].copy_from_slice(data);
}
}
pub fn set_data(&mut self, memory_offset: usize, data_offset: usize, len: usize, data: &[u8]) {
if data_offset >= data.len() {
self.slice_mut(memory_offset, len).fill(0);
return;
}
let data_end = core::cmp::min(data_offset + len, data.len());
let data_len = data_end - data_offset;
self.slice_mut(memory_offset, data_len)
.copy_from_slice(&data[data_offset..data_end]);
self.slice_mut(memory_offset + data_len, len - data_len).fill(0);
}
pub fn slice_len(&self, offset: usize, size: usize) -> &[u8] {
&self.data[offset..offset + size]
}
pub fn copy(&mut self, dst: usize, src: usize, len: usize) {
self.data.copy_within(src..src + len, dst);
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::tests::Test;
#[test]
fn test_memory_resize() {
let mut memory = Memory::<Test>::new();
assert_eq!(memory.size(), 0);
assert!(memory.resize(0, 100).is_continue());
assert_eq!(memory.size(), 128);
assert!(memory.resize(0, 50).is_continue());
assert_eq!(memory.size(), 128); }
#[test]
fn test_set_get() {
let mut memory = Memory::<Test>::new();
memory.data.resize(100, 0);
let data = b"Hello, World!";
memory.set(10, data);
assert_eq!(memory.slice(10..10 + data.len()), data);
}
#[test]
fn test_memory_copy() {
let mut memory = Memory::<Test>::new();
memory.data.resize(100, 0);
memory.set(0, b"Hello");
memory.set(10, b"World");
memory.copy(20, 0, 5);
assert_eq!(memory.slice(20..25), b"Hello");
assert_eq!(memory.slice(0..5), b"Hello"); }
#[test]
fn test_set_data() {
let mut memory = Memory::<Test>::new();
memory.data.resize(100, 0);
let source_data = b"Hello World";
memory.set_data(5, 0, 5, source_data);
assert_eq!(memory.slice(5..10), b"Hello");
memory.set_data(15, 6, 5, source_data);
assert_eq!(memory.slice(15..20), b"World");
}
}