Skip to content

Commit

Permalink
feat: simplify AccessListInspector API (#256)
Browse files Browse the repository at this point in the history
Right now caller is required to provide `AccessListInspector` with the
list of precompiles which is unnecessary and requires caller to peek
into EVM internals. Besides making API more complex this also results in
reth not excluding p256 OP precompile when preparing access list
https://github.com/paradigmxyz/reth/blob/890507a98adef94b3970312ef796eb40f87206df/crates/rpc/rpc-eth-api/src/helpers/call.rs#L430-L431

This PR changes `AccessListInspector` to obtain `from`, `to` and
`precompiles` from the top-level frame and not requiring caller to
provide anything
  • Loading branch information
klkvr authored Jan 24, 2025
1 parent 1d5b19d commit f7e6249
Showing 1 changed file with 64 additions and 8 deletions.
72 changes: 64 additions & 8 deletions src/access_list.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use alloc::collections::BTreeSet;
use alloy_primitives::{
map::{HashMap, HashSet},
Address, B256,
Address, TxKind, B256,
};
use alloy_rpc_types_eth::{AccessList, AccessListItem};
use revm::{
Expand All @@ -20,18 +20,19 @@ pub struct AccessListInspector {
access_list: HashMap<Address, BTreeSet<B256>>,
}

impl From<AccessList> for AccessListInspector {
fn from(access_list: AccessList) -> Self {
Self::new(access_list)
}
}

impl AccessListInspector {
/// Creates a new inspector instance
///
/// The `access_list` is the provided access list from the call request
pub fn new(
access_list: AccessList,
from: Address,
to: Address,
precompiles: impl IntoIterator<Item = Address>,
) -> Self {
pub fn new(access_list: AccessList) -> Self {
Self {
excluded: [from, to].into_iter().chain(precompiles).collect(),
excluded: Default::default(),
access_list: access_list
.0
.into_iter()
Expand Down Expand Up @@ -59,12 +60,67 @@ impl AccessListInspector {
});
AccessList(items.collect())
}

/// Collects addresses which should be excluded from the access list. Must be called before the
/// top-level call.
///
/// Those include caller, callee and precompiles.
fn collect_excluded_addresses<DB: Database>(&mut self, context: &EvmContext<DB>) {
let from = context.env.tx.caller;
let to = if let TxKind::Call(to) = context.env.tx.transact_to {
to
} else {
// We need to exclude the created address if this is a CREATE frame.
//
// This assumes that caller has already been loaded but nonce was not increased yet.
let nonce = context.journaled_state.account(from).info.nonce;
from.create(nonce)
};
let precompiles = context.precompiles.addresses().copied();
self.excluded = [from, to].into_iter().chain(precompiles).collect();
}
}

impl<DB> Inspector<DB> for AccessListInspector
where
DB: Database,
{
fn call(
&mut self,
context: &mut EvmContext<DB>,
_inputs: &mut revm::interpreter::CallInputs,
) -> Option<revm::interpreter::CallOutcome> {
// At the top-level frame, fill the excluded addresses
if context.journaled_state.depth() == 0 {
self.collect_excluded_addresses(context)
}
None
}

fn create(
&mut self,
context: &mut EvmContext<DB>,
_inputs: &mut revm::interpreter::CreateInputs,
) -> Option<revm::interpreter::CreateOutcome> {
// At the top-level frame, fill the excluded addresses
if context.journaled_state.depth() == 0 {
self.collect_excluded_addresses(context)
}
None
}

fn eofcreate(
&mut self,
context: &mut EvmContext<DB>,
_inputs: &mut revm::interpreter::EOFCreateInputs,
) -> Option<revm::interpreter::CreateOutcome> {
// At the top-level frame, fill the excluded addresses
if context.journaled_state.depth() == 0 {
self.collect_excluded_addresses(context)
}
None
}

fn step(&mut self, interp: &mut Interpreter, _context: &mut EvmContext<DB>) {
match interp.current_opcode() {
opcode::SLOAD | opcode::SSTORE => {
Expand Down

0 comments on commit f7e6249

Please sign in to comment.