Skip to content

Commit cf55696

Browse files
rakitamattsseklkvr
authored
chore: bump revm dec 2024 (#246)
Revm Framework integration --------- Co-authored-by: Matthias Seitz <[email protected]> Co-authored-by: Arsenii Kulikov <[email protected]>
1 parent c847b12 commit cf55696

24 files changed

+829
-799
lines changed

Cargo.toml

+9-6
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ alloy-rpc-types-eth = "0.12"
3434
alloy-rpc-types-trace = "0.12"
3535
alloy-sol-types = "0.8"
3636
alloy-primitives = { version = "0.8", features = ["map"] }
37-
revm = { version = "19.0.0", default-features = false, features = ["std"] }
37+
revm = "20.0.0-alpha.5"
3838

3939
anstyle = { version = "1.0", optional = true }
4040
colorchoice = "1.0"
@@ -53,10 +53,13 @@ snapbox = { version = "0.6", features = ["term-svg"] }
5353

5454
[features]
5555
default = ["std"]
56-
std = ["alloy-primitives/std", "anstyle/std", "serde/std", "serde_json/std", "revm/std", "thiserror/std"]
56+
std = [
57+
"alloy-primitives/std",
58+
"anstyle/std",
59+
"serde/std",
60+
"serde_json/std",
61+
"revm/std",
62+
"thiserror/std",
63+
]
5764
serde = ["dep:serde", "revm/serde"]
5865
js-tracer = ["dep:boa_engine", "dep:boa_gc"]
59-
60-
[patch.crates-io]
61-
#alloy-rpc-types-eth = { git = "https://github.com/alloy-rs/alloy", rev = "cfb13aa" }
62-
#alloy-rpc-types-trace = { git = "https://github.com/alloy-rs/alloy", rev = "cfb13aa" }

src/access_list.rs

+28-21
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,15 @@ use alloy_primitives::{
55
};
66
use alloy_rpc_types_eth::{AccessList, AccessListItem};
77
use revm::{
8-
interpreter::{opcode, Interpreter},
9-
Database, EvmContext, Inspector,
8+
bytecode::opcode,
9+
context::JournalTr,
10+
context_interface::{ContextTr, Transaction},
11+
inspector::JournalExt,
12+
interpreter::{
13+
interpreter_types::{InputsTr, Jumps},
14+
Interpreter,
15+
},
16+
Inspector,
1017
};
1118

1219
/// An [Inspector] that collects touched accounts and storage slots.
@@ -65,67 +72,67 @@ impl AccessListInspector {
6572
/// top-level call.
6673
///
6774
/// Those include caller, callee and precompiles.
68-
fn collect_excluded_addresses<DB: Database>(&mut self, context: &EvmContext<DB>) {
69-
let from = context.env.tx.caller;
70-
let to = if let TxKind::Call(to) = context.env.tx.transact_to {
75+
fn collect_excluded_addresses<CTX: ContextTr<Journal: JournalExt>>(&mut self, context: &CTX) {
76+
let from = context.tx().caller();
77+
let to = if let TxKind::Call(to) = context.tx().kind() {
7178
to
7279
} else {
7380
// We need to exclude the created address if this is a CREATE frame.
7481
//
7582
// This assumes that caller has already been loaded but nonce was not increased yet.
76-
let nonce = context.journaled_state.account(from).info.nonce;
83+
let nonce = context.journal_ref().evm_state().get(&from).unwrap().info.nonce;
7784
from.create(nonce)
7885
};
79-
let precompiles = context.precompiles.addresses().copied();
86+
let precompiles = context.journal_ref().precompile_addresses().clone();
8087
self.excluded = [from, to].into_iter().chain(precompiles).collect();
8188
}
8289
}
8390

84-
impl<DB> Inspector<DB> for AccessListInspector
91+
impl<CTX> Inspector<CTX> for AccessListInspector
8592
where
86-
DB: Database,
93+
CTX: ContextTr<Journal: JournalExt>,
8794
{
8895
fn call(
8996
&mut self,
90-
context: &mut EvmContext<DB>,
97+
context: &mut CTX,
9198
_inputs: &mut revm::interpreter::CallInputs,
9299
) -> Option<revm::interpreter::CallOutcome> {
93100
// At the top-level frame, fill the excluded addresses
94-
if context.journaled_state.depth() == 0 {
101+
if context.journal().depth() == 0 {
95102
self.collect_excluded_addresses(context)
96103
}
97104
None
98105
}
99106

100107
fn create(
101108
&mut self,
102-
context: &mut EvmContext<DB>,
109+
context: &mut CTX,
103110
_inputs: &mut revm::interpreter::CreateInputs,
104111
) -> Option<revm::interpreter::CreateOutcome> {
105112
// At the top-level frame, fill the excluded addresses
106-
if context.journaled_state.depth() == 0 {
113+
if context.journal().depth() == 0 {
107114
self.collect_excluded_addresses(context)
108115
}
109116
None
110117
}
111118

112119
fn eofcreate(
113120
&mut self,
114-
context: &mut EvmContext<DB>,
121+
context: &mut CTX,
115122
_inputs: &mut revm::interpreter::EOFCreateInputs,
116123
) -> Option<revm::interpreter::CreateOutcome> {
117124
// At the top-level frame, fill the excluded addresses
118-
if context.journaled_state.depth() == 0 {
125+
if context.journal().depth() == 0 {
119126
self.collect_excluded_addresses(context)
120127
}
121128
None
122129
}
123130

124-
fn step(&mut self, interp: &mut Interpreter, _context: &mut EvmContext<DB>) {
125-
match interp.current_opcode() {
131+
fn step(&mut self, interp: &mut Interpreter, _context: &mut CTX) {
132+
match interp.bytecode.opcode() {
126133
opcode::SLOAD | opcode::SSTORE => {
127-
if let Ok(slot) = interp.stack().peek(0) {
128-
let cur_contract = interp.contract.target_address;
134+
if let Ok(slot) = interp.stack.peek(0) {
135+
let cur_contract = interp.input.target_address();
129136
self.access_list
130137
.entry(cur_contract)
131138
.or_default()
@@ -137,15 +144,15 @@ where
137144
| opcode::EXTCODESIZE
138145
| opcode::BALANCE
139146
| opcode::SELFDESTRUCT => {
140-
if let Ok(slot) = interp.stack().peek(0) {
147+
if let Ok(slot) = interp.stack.peek(0) {
141148
let addr = Address::from_word(B256::from(slot.to_be_bytes()));
142149
if !self.excluded.contains(&addr) {
143150
self.access_list.entry(addr).or_default();
144151
}
145152
}
146153
}
147154
opcode::DELEGATECALL | opcode::CALL | opcode::STATICCALL | opcode::CALLCODE => {
148-
if let Ok(slot) = interp.stack().peek(1) {
155+
if let Ok(slot) = interp.stack.peek(1) {
149156
let addr = Address::from_word(B256::from(slot.to_be_bytes()));
150157
if !self.excluded.contains(&addr) {
151158
self.access_list.entry(addr).or_default();

src/edge_cov.rs

+12-14
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,12 @@ use alloc::{vec, vec::Vec};
22
use alloy_primitives::{map::DefaultHashBuilder, Address, U256};
33
use core::hash::{BuildHasher, Hash, Hasher};
44
use revm::{
5+
bytecode::opcode::{self},
56
interpreter::{
6-
opcode::{self},
7+
interpreter_types::{InputsTr, Jumps},
78
Interpreter,
89
},
9-
Database, EvmContext, Inspector,
10+
Inspector,
1011
};
1112

1213
// This is the maximum number of edges that can be tracked. There is a tradeoff between performance
@@ -63,26 +64,23 @@ impl Default for EdgeCovInspector {
6364
}
6465
}
6566

66-
impl<DB> Inspector<DB> for EdgeCovInspector
67-
where
68-
DB: Database,
69-
{
70-
fn step(&mut self, interp: &mut Interpreter, _context: &mut EvmContext<DB>) {
71-
let address = interp.contract.target_address; // TODO track context for delegatecall?
72-
let current_pc = interp.program_counter();
67+
impl<CTX> Inspector<CTX> for EdgeCovInspector {
68+
fn step(&mut self, interp: &mut Interpreter, _context: &mut CTX) {
69+
let address = interp.input.target_address(); // TODO track context for delegatecall?
70+
let current_pc = interp.bytecode.pc();
7371

74-
match interp.current_opcode() {
72+
match interp.bytecode.opcode() {
7573
opcode::JUMP => {
7674
// unconditional jump
77-
if let Ok(jump_dest) = interp.stack().peek(0) {
75+
if let Ok(jump_dest) = interp.stack.peek(0) {
7876
self.store_hit(address, current_pc, jump_dest);
7977
}
8078
}
8179
opcode::JUMPI => {
82-
if let Ok(stack_value) = interp.stack().peek(0) {
83-
let jump_dest = if stack_value != U256::from(0) {
80+
if let Ok(stack_value) = interp.stack.peek(0) {
81+
let jump_dest = if !stack_value.is_zero() {
8482
// branch taken
85-
interp.stack().peek(1)
83+
interp.stack.peek(1)
8684
} else {
8785
// fall through
8886
Ok(U256::from(current_pc + 1))

src/opcode.rs

+55-41
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,12 @@ use alloc::string::ToString;
22
use alloy_primitives::map::HashMap;
33
use alloy_rpc_types_trace::opcode::OpcodeGas;
44
use revm::{
5+
bytecode::opcode::{self, OpCode},
56
interpreter::{
6-
opcode::{self, OpCode},
7+
interpreter_types::{Immediates, Jumps, LoopControl},
78
Interpreter,
89
},
9-
Database, EvmContext, Inspector,
10+
Inspector,
1011
};
1112

1213
/// An Inspector that counts opcodes and measures gas usage per opcode.
@@ -58,80 +59,81 @@ impl OpcodeGasInspector {
5859
}
5960
}
6061

61-
impl<DB> Inspector<DB> for OpcodeGasInspector
62-
where
63-
DB: Database,
64-
{
65-
fn step(&mut self, interp: &mut Interpreter, _context: &mut EvmContext<DB>) {
66-
let opcode_value = interp.current_opcode();
62+
impl<CTX> Inspector<CTX> for OpcodeGasInspector {
63+
fn step(&mut self, interp: &mut Interpreter, _context: &mut CTX) {
64+
let opcode_value = interp.bytecode.opcode();
6765
if let Some(opcode) = OpCode::new(opcode_value) {
6866
// keep track of opcode counts
6967
*self.opcode_counts.entry(opcode).or_default() += 1;
7068

7169
// keep track of the last opcode executed
72-
self.last_opcode_gas_remaining = Some((opcode, interp.gas().remaining()));
70+
self.last_opcode_gas_remaining = Some((opcode, interp.control.gas().remaining()));
7371
}
7472
}
7573

76-
fn step_end(&mut self, interp: &mut Interpreter, _context: &mut EvmContext<DB>) {
74+
fn step_end(&mut self, interp: &mut Interpreter, _context: &mut CTX) {
7775
// update gas usage for the last opcode
7876
if let Some((opcode, gas_remaining)) = self.last_opcode_gas_remaining.take() {
79-
let gas_cost = gas_remaining.saturating_sub(interp.gas().remaining());
77+
let gas_cost = gas_remaining.saturating_sub(interp.control.gas().remaining());
8078
*self.opcode_gas.entry(opcode).or_default() += gas_cost;
8179
}
8280
}
8381
}
8482

85-
/// Accepts [OpCode] and a slice of bytecode immediately after it and returns the size of immediate
83+
/// Accepts Bytecode that implements [Immediates] and returns the size of immediate
8684
/// value.
8785
///
8886
/// Primarily needed to handle a special case of RJUMPV opcode.
89-
pub fn immediate_size(op: OpCode, bytes_after: &[u8]) -> u8 {
90-
match op.get() {
91-
opcode::RJUMPV => {
92-
if bytes_after.is_empty() {
93-
return 0;
94-
}
95-
1 + (bytes_after[0] + 1) * 2
96-
}
97-
_ => op.info().immediate_size(),
87+
pub fn immediate_size(bytecode: &impl Immediates) -> u8 {
88+
let opcode = bytecode.read_u8();
89+
if opcode == opcode::RJUMPV {
90+
let vtable_size = bytecode.read_slice(2)[2];
91+
return 1 + (vtable_size + 1) * 2;
9892
}
93+
let Some(opcode) = OpCode::new(opcode) else { return 0 };
94+
opcode.info().immediate_size()
9995
}
10096

10197
#[cfg(test)]
10298
mod tests {
10399
use super::*;
104100
use revm::{
105-
db::{CacheDB, EmptyDB},
106-
interpreter::{opcode, Contract},
101+
bytecode::Bytecode,
102+
database::CacheDB,
103+
database_interface::EmptyDB,
104+
interpreter::{interpreter::ExtBytecode, InputsImpl, SharedMemory},
105+
primitives::{hardfork::SpecId, Bytes},
106+
Context, MainContext,
107107
};
108+
use std::{cell::RefCell, rc::Rc};
108109

109110
#[test]
110111
fn test_opcode_counter_inspector() {
111112
let mut opcode_counter = OpcodeGasInspector::new();
112-
let contract = Contract::default();
113-
let mut interpreter = Interpreter::new(contract, 10000, false);
114-
let db = CacheDB::new(EmptyDB::default());
115113

116-
let opcodes = [
117-
OpCode::new(opcode::ADD).unwrap(),
118-
OpCode::new(opcode::ADD).unwrap(),
119-
OpCode::new(opcode::ADD).unwrap(),
120-
OpCode::new(opcode::BYTE).unwrap(),
121-
];
114+
let opcodes = [opcode::ADD, opcode::ADD, opcode::ADD, opcode::BYTE];
115+
116+
let bytecode = Bytecode::new_raw(Bytes::from(opcodes));
117+
let mut interpreter = Interpreter::new(
118+
Rc::new(RefCell::new(SharedMemory::new())),
119+
ExtBytecode::new(bytecode),
120+
InputsImpl::default(),
121+
false,
122+
false,
123+
SpecId::LATEST,
124+
u64::MAX,
125+
);
126+
let db = CacheDB::new(EmptyDB::default());
122127

123-
for &opcode in &opcodes {
124-
interpreter.instruction_pointer = &opcode.get();
125-
opcode_counter.step(&mut interpreter, &mut EvmContext::new(db.clone()));
128+
let mut context = Context::mainnet().with_db(db);
129+
for _ in &opcodes {
130+
opcode_counter.step(&mut interpreter, &mut context);
126131
}
127132
}
128133

129134
#[test]
130135
fn test_with_variety_of_opcodes() {
131136
let mut opcode_counter = OpcodeGasInspector::new();
132-
let contract = Contract::default();
133-
let mut interpreter = Interpreter::new(contract, 2024, false);
134-
let db = CacheDB::new(EmptyDB::default());
135137

136138
let opcodes = [
137139
opcode::PUSH1,
@@ -142,9 +144,21 @@ mod tests {
142144
opcode::STOP,
143145
];
144146

145-
for opcode in opcodes.iter() {
146-
interpreter.instruction_pointer = opcode;
147-
opcode_counter.step(&mut interpreter, &mut EvmContext::new(db.clone()));
147+
let bytecode = Bytecode::new_raw(Bytes::from(opcodes));
148+
let mut interpreter = Interpreter::new(
149+
Rc::new(RefCell::new(SharedMemory::new())),
150+
ExtBytecode::new(bytecode),
151+
InputsImpl::default(),
152+
false,
153+
false,
154+
SpecId::LATEST,
155+
u64::MAX,
156+
);
157+
let db = CacheDB::new(EmptyDB::default());
158+
159+
let mut context = Context::mainnet().with_db(db);
160+
for _ in opcodes.iter() {
161+
opcode_counter.step(&mut interpreter, &mut context);
148162
}
149163
}
150164
}

src/tracing/arena.rs

+1
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ impl CallTraceArena {
9292
}
9393

9494
/// How to push a trace into the arena
95+
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
9596
pub(crate) enum PushTraceKind {
9697
/// This will _only_ push the trace into the arena.
9798
PushOnly,

0 commit comments

Comments
 (0)