feat: add revm-inspectors crate and accesslist inspector (#1529)

This commit is contained in:
Matthias Seitz
2023-02-24 02:06:15 +01:00
committed by GitHub
parent 8299ca6fd6
commit 6d138daa11
12 changed files with 187 additions and 8 deletions

18
Cargo.lock generated
View File

@ -4851,6 +4851,24 @@ dependencies = [
"reth-interfaces", "reth-interfaces",
"reth-primitives", "reth-primitives",
"reth-provider", "reth-provider",
"reth-revm-primitives",
"revm",
]
[[package]]
name = "reth-revm-inspectors"
version = "0.1.0"
dependencies = [
"hashbrown 0.13.2",
"reth-primitives",
"revm",
]
[[package]]
name = "reth-revm-primitives"
version = "0.1.0"
dependencies = [
"reth-primitives",
"revm", "revm",
] ]

View File

@ -17,6 +17,8 @@ members = [
"crates/net/downloaders", "crates/net/downloaders",
"crates/primitives", "crates/primitives",
"crates/revm", "crates/revm",
"crates/revm/revm-primitives",
"crates/revm/revm-inspectors",
"crates/rlp", "crates/rlp",
"crates/rlp/rlp-derive", "crates/rlp/rlp-derive",
"crates/rpc/ipc", "crates/rpc/ipc",

View File

@ -11,5 +11,6 @@ description = "reth specific revm utilities"
reth-primitives = { path = "../primitives" } reth-primitives = { path = "../primitives" }
reth-interfaces = { path = "../interfaces" } reth-interfaces = { path = "../interfaces" }
reth-provider = { path = "../storage/provider" } reth-provider = { path = "../storage/provider" }
reth-revm-primitives = { path = "./revm-primitives" }
revm = { version = "3.0.0"} revm = { version = "3.0.0"}

View File

@ -0,0 +1,15 @@
[package]
name = "reth-revm-inspectors"
version = "0.1.0"
edition = "2021"
license = "MIT OR Apache-2.0"
repository = "https://github.com/paradigmxyz/reth"
description = "revm inspector implementations used by reth"
[dependencies]
# reth
reth-primitives = { path = "../../primitives" }
revm = { version = "3.0.0" }
# remove from reth and reexport from revm
hashbrown = "0.13"

View File

@ -0,0 +1,108 @@
use hashbrown::{HashMap, HashSet};
use reth_primitives::{AccessList, AccessListItem, Address, H256};
use revm::{
interpreter::{opcode, InstructionResult, Interpreter},
Database, EVMData, Inspector,
};
/// An [Inspector] that collects touched accounts and storage slots.
///
/// This can be used to construct an [AccessList] for a transaction via `eth_createAccessList`
#[derive(Default, Debug)]
pub struct AccessListInspector {
/// All addresses that should be excluded from the final accesslist
excluded: HashSet<Address>,
/// All addresses and touched slots
access_list: HashMap<Address, HashSet<H256>>,
}
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: Vec<Address>,
) -> Self {
AccessListInspector {
excluded: vec![from, to].iter().chain(precompiles.iter()).copied().collect(),
access_list: access_list
.0
.iter()
.map(|v| (v.address, v.storage_keys.iter().copied().collect()))
.collect(),
}
}
/// Returns list of addresses and storage keys used by the transaction. It gives you the list of
/// addresses and storage keys that were touched during execution.
pub fn into_access_list(self) -> AccessList {
let items = self.access_list.into_iter().map(|(address, slots)| AccessListItem {
address,
storage_keys: slots.into_iter().collect(),
});
AccessList(items.collect())
}
/// Returns list of addresses and storage keys used by the transaction. It gives you the list of
/// addresses and storage keys that were touched during execution.
pub fn access_list(&self) -> AccessList {
let items = self.access_list.iter().map(|(address, slots)| AccessListItem {
address: *address,
storage_keys: slots.iter().copied().collect(),
});
AccessList(items.collect())
}
}
impl<DB> Inspector<DB> for AccessListInspector
where
DB: Database,
{
fn step(
&mut self,
interpreter: &mut Interpreter,
_data: &mut EVMData<'_, DB>,
_is_static: bool,
) -> InstructionResult {
let pc = interpreter.program_counter();
let op = interpreter.contract.bytecode.bytecode()[pc];
match op {
opcode::SLOAD | opcode::SSTORE => {
if let Ok(slot) = interpreter.stack().peek(0) {
let cur_contract = interpreter.contract.address;
self.access_list
.entry(cur_contract)
.or_default()
.insert(H256::from(slot.to_be_bytes()));
}
}
opcode::EXTCODECOPY |
opcode::EXTCODEHASH |
opcode::EXTCODESIZE |
opcode::BALANCE |
opcode::SELFDESTRUCT => {
if let Ok(slot) = interpreter.stack().peek(0) {
let addr: Address = H256::from(slot.to_be_bytes()).into();
if !self.excluded.contains(&addr) {
self.access_list.entry(addr).or_default();
}
}
}
opcode::DELEGATECALL | opcode::CALL | opcode::STATICCALL | opcode::CALLCODE => {
if let Ok(slot) = interpreter.stack().peek(1) {
let addr: Address = H256::from(slot.to_be_bytes()).into();
if !self.excluded.contains(&addr) {
self.access_list.entry(addr).or_default();
}
}
}
_ => (),
}
InstructionResult::Continue
}
}

View File

@ -0,0 +1,11 @@
#![warn(missing_docs, unreachable_pub, unused_crate_dependencies)]
#![deny(unused_must_use, rust_2018_idioms)]
#![doc(test(
no_crate_inject,
attr(deny(warnings, rust_2018_idioms), allow(dead_code, unused_variables))
))]
//! revm [Inspector](revm::Inspector) implementations
/// An inspector implementation for an EIP2930 Accesslist
pub mod access_list;

View File

@ -0,0 +1,13 @@
[package]
name = "reth-revm-primitives"
version = "0.1.0"
edition = "2021"
license = "MIT OR Apache-2.0"
repository = "https://github.com/paradigmxyz/reth"
description = "core reth specific revm utilities"
[dependencies]
# reth
reth-primitives = { path = "../../primitives" }
revm = { version = "3.0.0" }

View File

@ -0,0 +1,17 @@
#![warn(missing_docs, unreachable_pub, unused_crate_dependencies)]
#![deny(unused_must_use, rust_2018_idioms)]
#![doc(test(
no_crate_inject,
attr(deny(warnings, rust_2018_idioms), allow(dead_code, unused_variables))
))]
//! revm utils and implementations specific to reth.
pub mod config;
/// Helpers for configuring revm [Env](revm::primitives::Env)
pub mod env;
/// Helpers for type compatibility between reth and revm types
mod compat;
pub use compat::*;

View File

@ -7,14 +7,8 @@
//! revm utils and implementations specific to reth. //! revm utils and implementations specific to reth.
pub mod config;
/// Contains glue code for integrating reth database into revm's [Database](revm::Database). /// Contains glue code for integrating reth database into revm's [Database](revm::Database).
pub mod database; pub mod database;
/// Helpers for configuring revm [Env](revm::primitives::Env) /// reexport for convenience
pub mod env; pub use reth_revm_primitives::*;
/// Helpers for type compatibility between reth and revm types
mod compat;
pub use compat::*;