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

feat: add op counter #24

Merged
merged 15 commits into from
Feb 14, 2024
87 changes: 87 additions & 0 deletions src/counter_op.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
use revm::{
interpreter::{opcode::OpCode, Interpreter},
Database, EvmContext, Inspector,
};
use std::collections::HashMap;

/// An Inspector that counts opcodes and measures gas usage per opcode.
#[derive(Default, Debug)]
DoTheBestToGetTheBest marked this conversation as resolved.
Show resolved Hide resolved
pub struct OpcodeCounterInspector {
/// Map of opcode counts per transaction.
pub opcode_counts: HashMap<OpCode, u64>,
/// Map of total gas used per opcode.
pub opcode_gas: HashMap<OpCode, u64>,
}

impl OpcodeCounterInspector {
/// Creates a new instance of the inspector.
pub fn new() -> Self {
OpcodeCounterInspector { opcode_counts: HashMap::new(), opcode_gas: HashMap::new() }
}

/// Returns the opcode counts collected during transaction execution.
pub const fn opcode_counts(&self) -> &HashMap<OpCode, u64> {
&self.opcode_counts
}

/// Returns the opcode gas usage collected during transaction execution.
pub const fn opcode_gas(&self) -> &HashMap<OpCode, u64> {
&self.opcode_gas
}
}

impl<DB> Inspector<DB> for OpcodeCounterInspector
where
DB: Database,
{
fn step(&mut self, interp: &mut Interpreter, _context: &mut EvmContext<DB>) {
let opcode_value = interp.current_opcode();
if let Some(opcode) = OpCode::new(opcode_value) {
*self.opcode_counts.entry(opcode).or_insert(0) += 1;

let gas_table =
revm::interpreter::instructions::opcode::spec_opcode_gas(_context.spec_id());
let opcode_gas_info = gas_table[opcode_value as usize];

let opcode_gas_cost = opcode_gas_info.get_gas() as u64;

*self.opcode_gas.entry(opcode).or_insert(0) += opcode_gas_cost;
}
}
}

#[cfg(test)]
mod tests {
use super::*;
use revm::{
db::{CacheDB, EmptyDB},
interpreter::{opcode, Contract, Interpreter},
EvmContext, Inspector,
};

#[test]
fn test_opcode_counter_inspector() {
let mut opcode_counter = OpcodeCounterInspector::new();
let contract = Box::<Contract>::default();
let mut interpreter = Interpreter::new(contract, 10000, false);
let db = CacheDB::new(EmptyDB::default());

let opcodes = [
OpCode::new(opcode::ADD).unwrap(),
OpCode::new(opcode::ADD).unwrap(),
OpCode::new(opcode::ADD).unwrap(),
OpCode::new(opcode::BYTE).unwrap(),
];

for &opcode in &opcodes {
interpreter.instruction_pointer = &opcode.get();
opcode_counter.step(&mut interpreter, &mut EvmContext::new(db.clone()));
}

let opcode_counts = opcode_counter.opcode_counts();
println!("Opcode Counts: {:?}", opcode_counts);

let opcode_gas = opcode_counter.opcode_gas();
println!("Opcode Gas Usage: {:?}", opcode_gas);
}
}
14 changes: 13 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,32 @@
//! - `js-tracer`: Enables a JavaScript tracer implementation. This pulls in extra dependencies
//! (such as `boa`, `tokio` and `serde_json`).

#![doc = include_str!("../README.md")]
#![doc(
html_logo_url = "https://raw.githubusercontent.com/paradigmxyz/reth/main/assets/reth-docs.png",
html_favicon_url = "https://avatars0.githubusercontent.com/u/97369466?s=256",
issue_tracker_base_url = "https://github.com/paradigmxyz/reth/issues/"
)]
#![warn(
missing_copy_implementations,
missing_debug_implementations,
missing_docs,
unreachable_pub,
clippy::missing_const_for_fn,
rustdoc::all
)]
#![cfg_attr(not(test), warn(unused_crate_dependencies))]
#![deny(unused_must_use, rust_2018_idioms)]
#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))]

/// An inspector implementation for an EIP2930 Accesslist
pub mod access_list;

/// implementation of an opcode counter for the EVM.
pub mod counter_op;
DoTheBestToGetTheBest marked this conversation as resolved.
Show resolved Hide resolved
/// An inspector stack abstracting the implementation details of
/// each inspector and allowing to hook on block/transaction execution,
/// used in the main RETH executor.
pub mod stack;

/// An inspector for recording traces
pub mod tracing;