Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

perf: use ArrayVec for collecting push bytes #7397

Merged
merged 2 commits into from
Mar 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,7 @@ alloy-rlp = "0.3.3"
solang-parser = "=0.3.3"

## misc
arrayvec = "0.7"
base64 = "0.22"
chrono = { version = "0.4", default-features = false, features = ["clock", "std"] }
color-eyre = "0.6"
Expand Down
1 change: 1 addition & 0 deletions crates/evm/core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ revm = { workspace = true, default-features = false, features = [
] }
revm-inspectors.workspace = true

arrayvec.workspace = true
auto_impl = "1"
derive_more.workspace = true
eyre = "0.6"
Expand Down
22 changes: 17 additions & 5 deletions crates/evm/core/src/debug.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use crate::opcodes;
use alloy_primitives::{Address, Bytes, U256};
use arrayvec::ArrayVec;
use revm::interpreter::OpCode;
use revm_inspectors::tracing::types::CallKind;
use serde::{Deserialize, Serialize};
Expand Down Expand Up @@ -176,8 +177,10 @@ pub struct DebugStep {
pub returndata: Bytes,
/// Opcode to be executed
pub instruction: Instruction,
/// Optional bytes that are being pushed onto the stack
pub push_bytes: Option<Vec<u8>>,
/// Optional bytes that are being pushed onto the stack.
/// Empty if the opcode is not a push or PUSH0.
#[serde(serialize_with = "hex::serialize", deserialize_with = "deserialize_arrayvec_hex")]
pub push_bytes: ArrayVec<u8, 32>,
/// The program counter at this step.
///
/// Note: To map this step onto source code using a source map, you must convert the program
Expand All @@ -195,7 +198,7 @@ impl Default for DebugStep {
calldata: Default::default(),
returndata: Default::default(),
instruction: Instruction::OpCode(revm::interpreter::opcode::INVALID),
push_bytes: None,
push_bytes: Default::default(),
pc: 0,
total_gas_used: 0,
}
Expand All @@ -205,8 +208,8 @@ impl Default for DebugStep {
impl DebugStep {
/// Pretty print the step's opcode
pub fn pretty_opcode(&self) -> String {
if let Some(push_bytes) = &self.push_bytes {
format!("{}(0x{})", self.instruction, hex::encode(push_bytes))
if !self.push_bytes.is_empty() {
format!("{}(0x{})", self.instruction, hex::encode(&self.push_bytes))
} else {
self.instruction.to_string()
}
Expand Down Expand Up @@ -266,3 +269,12 @@ impl Instruction {
}
}
}

fn deserialize_arrayvec_hex<'de, D: serde::Deserializer<'de>>(
deserializer: D,
) -> Result<ArrayVec<u8, 32>, D::Error> {
let bytes: Vec<u8> = hex::deserialize(deserializer)?;
let mut array = ArrayVec::new();
array.try_extend_from_slice(&bytes).map_err(serde::de::Error::custom)?;
Ok(array)
}
1 change: 1 addition & 0 deletions crates/evm/evm/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ revm-inspectors.workspace = true

itertools.workspace = true

arrayvec.workspace = true
eyre = "0.6"
hex.workspace = true
parking_lot = "0.12"
Expand Down
36 changes: 15 additions & 21 deletions crates/evm/evm/src/inspectors/debugger.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use alloy_primitives::Address;
use arrayvec::ArrayVec;
use foundry_common::{ErrorExt, SELECTOR_LEN};
use foundry_evm_core::{
backend::DatabaseExt,
Expand Down Expand Up @@ -56,36 +57,29 @@ impl<DB: DatabaseExt> Inspector<DB> for Debugger {
let opcode_info = &opcode_infos[op as usize];

// Extract the push bytes
let push_size = if opcode_info.is_push() { (op - opcode::PUSH1 + 1) as usize } else { 0 };
let push_bytes = match push_size {
0 => None,
n => {
let start = pc + 1;
let end = start + n;
Some(interp.contract.bytecode.bytecode()[start..end].to_vec())
}
};
let push_size = if opcode_info.is_push() { (op - opcode::PUSH0) as usize } else { 0 };
let push_bytes = (push_size > 0).then(|| {
let start = pc + 1;
let end = start + push_size;
let slice = &interp.contract.bytecode.bytecode()[start..end];
assert!(slice.len() <= 32);
let mut array = ArrayVec::new();
array.try_extend_from_slice(slice).unwrap();
array
});

let total_gas_used = gas_used(
ecx.spec_id(),
interp.gas.limit().saturating_sub(interp.gas.remaining()),
interp.gas.refunded() as u64,
);

// if the previous opcode does __not__ modify memory, we can reuse the memory of
// that step
// Reuse the memory from the previous step if the previous opcode did not modify it.
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
}
})
.filter(|step| !step.opcode_modifies_memory())
.map(|step| step.memory.clone())
.unwrap_or_else(|| interp.shared_memory.context_memory().to_vec().into());

self.arena.arena[self.head].steps.push(DebugStep {
Expand All @@ -95,7 +89,7 @@ impl<DB: DatabaseExt> Inspector<DB> for Debugger {
calldata: interp.contract().input.clone(),
returndata: interp.return_data_buffer.clone(),
instruction: Instruction::OpCode(op),
push_bytes,
push_bytes: push_bytes.unwrap_or_default(),
total_gas_used,
});
}
Expand Down
Loading