pub mod opcodes;
use revm::interpreter::{
interpreter::num_words, interpreter_types::MemoryTr, Gas, InstructionResult,
};
#[inline]
pub const fn monad_memory_cost(num_words: usize) -> u64 {
(num_words as u64) >> 1
}
#[inline]
pub fn monad_resize_memory<Memory: MemoryTr>(
gas: &mut Gas,
memory: &mut Memory,
offset: usize,
len: usize,
) -> Result<(), InstructionResult> {
#[cfg(feature = "memory_limit")]
if memory.limit_reached(offset, len) {
return Err(InstructionResult::MemoryLimitOOG);
}
let new_num_words = num_words(offset.saturating_add(len));
if new_num_words > gas.memory().words_num {
return monad_resize_memory_cold(gas, memory, new_num_words);
}
Ok(())
}
#[cold]
#[inline(never)]
fn monad_resize_memory_cold<Memory: MemoryTr>(
gas: &mut Gas,
memory: &mut Memory,
new_num_words: usize,
) -> Result<(), InstructionResult> {
let total_cost = monad_memory_cost(new_num_words);
let delta =
unsafe { gas.memory_mut().set_words_num(new_num_words, total_cost).unwrap_unchecked() };
if !gas.record_regular_cost(delta) {
return Err(InstructionResult::MemoryOOG);
}
memory.resize(new_num_words * 32);
Ok(())
}
macro_rules! resize_memory_mip3 {
($interpreter:expr, $offset:expr, $len:expr) => {
resize_memory_mip3!($interpreter, $offset, $len, ())
};
($interpreter:expr, $offset:expr, $len:expr, $ret:expr) => {
if let Err(result) = $crate::memory::monad_resize_memory(
&mut $interpreter.gas,
&mut $interpreter.memory,
$offset,
$len,
) {
$interpreter.halt(result);
return $ret;
}
};
}
pub(crate) use resize_memory_mip3;
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_monad_memory_cost() {
assert_eq!(monad_memory_cost(0), 0);
assert_eq!(monad_memory_cost(1), 0);
assert_eq!(monad_memory_cost(2), 1);
assert_eq!(monad_memory_cost(10), 5);
assert_eq!(monad_memory_cost(262_144), 131_072);
}
#[test]
fn test_monad_memory_cost_is_linear() {
let cost_100 = monad_memory_cost(100);
let cost_200 = monad_memory_cost(200);
let cost_400 = monad_memory_cost(400);
assert_eq!(cost_200, cost_100 * 2);
assert_eq!(cost_400, cost_200 * 2);
}
#[test]
fn test_monad_vs_eth_memory_cost() {
let eth_cost = 3u64 * 262_144 + (262_144u64 * 262_144) / 512;
let monad_cost = monad_memory_cost(262_144);
assert_eq!(monad_cost, 131_072);
assert!(monad_cost < eth_cost);
}
}