Skip to content

Commit

Permalink
chore: reuse unmodified step memory (#7385)
Browse files Browse the repository at this point in the history
* chore: only record changed memory

* chore: only record changed memory

* chore: use returndata Bytes

* clippy

* clippy
  • Loading branch information
mattsse authored Mar 12, 2024
1 parent 46889b1 commit b2f9346
Show file tree
Hide file tree
Showing 4 changed files with 63 additions and 4 deletions.
21 changes: 19 additions & 2 deletions crates/evm/core/src/debug.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use crate::opcodes;
use alloy_primitives::{Address, Bytes, U256};
use revm::interpreter::OpCode;
use revm_inspectors::tracing::types::CallKind;
Expand Down Expand Up @@ -168,11 +169,11 @@ pub struct DebugStep {
/// Stack *prior* to running the associated opcode
pub stack: Vec<U256>,
/// Memory *prior* to running the associated opcode
pub memory: Vec<u8>,
pub memory: Bytes,
/// Calldata *prior* to running the associated opcode
pub calldata: Bytes,
/// Returndata *prior* to running the associated opcode
pub returndata: Vec<u8>,
pub returndata: Bytes,
/// Opcode to be executed
pub instruction: Instruction,
/// Optional bytes that are being pushed onto the stack
Expand Down Expand Up @@ -210,6 +211,11 @@ impl DebugStep {
self.instruction.to_string()
}
}

/// Returns `true` if the opcode modifies memory.
pub fn opcode_modifies_memory(&self) -> bool {
self.instruction.opcode().and_then(OpCode::new).map_or(false, opcodes::modifies_memory)
}
}

#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
Expand Down Expand Up @@ -249,3 +255,14 @@ impl Display for Instruction {
}
}
}

impl Instruction {
/// Returns the opcode of the instruction, if it is an opcode.
#[inline]
pub fn opcode(&self) -> Option<u8> {
match self {
Instruction::OpCode(op) => Some(*op),
_ => None,
}
}
}
1 change: 1 addition & 0 deletions crates/evm/core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ pub mod constants;
pub mod debug;
pub mod decode;
pub mod fork;
pub mod opcodes;
pub mod opts;
pub mod snapshot;
pub mod utils;
25 changes: 25 additions & 0 deletions crates/evm/core/src/opcodes.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
//! Opcode utils

use revm::interpreter::OpCode;

/// Returns true if the opcode modifies memory.
/// <https://bluealloy.github.io/revm/crates/interpreter/memory.html#opcodes>
/// <https://github.com/crytic/evm-opcodes>
#[inline]
pub const fn modifies_memory(opcode: OpCode) -> bool {
matches!(
opcode,
OpCode::EXTCODECOPY |
OpCode::MLOAD |
OpCode::MSTORE |
OpCode::MSTORE8 |
OpCode::MCOPY |
OpCode::CODECOPY |
OpCode::CALLDATACOPY |
OpCode::RETURNDATACOPY |
OpCode::CALL |
OpCode::CALLCODE |
OpCode::DELEGATECALL |
OpCode::STATICCALL
)
}
20 changes: 18 additions & 2 deletions crates/evm/evm/src/inspectors/debugger.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,12 +72,28 @@ impl<DB: DatabaseExt> Inspector<DB> for Debugger {
interp.gas.refunded() as u64,
);

// if the previous opcode does __not__ modify memory, we can reuse the memory of
// that step
let memory = self.arena.arena[self.head]
.steps
.last()
.and_then(|step| {
if !step.opcode_modifies_memory() {
// reuse the memory from the previous step, because its opcode did not modify
// memory
Some(step.memory.clone())
} else {
None
}
})
.unwrap_or_else(|| interp.shared_memory.context_memory().to_vec().into());

self.arena.arena[self.head].steps.push(DebugStep {
pc,
stack: interp.stack().data().clone(),
memory: interp.shared_memory.context_memory().to_vec(),
memory,
calldata: interp.contract().input.clone(),
returndata: interp.return_data_buffer.to_vec(),
returndata: interp.return_data_buffer.clone(),
instruction: Instruction::OpCode(op),
push_bytes,
total_gas_used,
Expand Down

0 comments on commit b2f9346

Please sign in to comment.