From a22cd918d04c03b8ee68764a127d398dc8cc3c02 Mon Sep 17 00:00:00 2001 From: Matthias Seitz Date: Mon, 3 Apr 2023 18:52:04 +0200 Subject: [PATCH] feat(rpc): add fourbyte inspector (#2093) --- crates/primitives/src/lib.rs | 3 + .../revm-inspectors/src/tracing/fourbyte.rs | 79 +++++++++++++++++++ .../revm/revm-inspectors/src/tracing/mod.rs | 2 + 3 files changed, 84 insertions(+) create mode 100644 crates/revm/revm-inspectors/src/tracing/fourbyte.rs diff --git a/crates/primitives/src/lib.rs b/crates/primitives/src/lib.rs index 7126e71d8c..bd6ac03b65 100644 --- a/crates/primitives/src/lib.rs +++ b/crates/primitives/src/lib.rs @@ -94,6 +94,9 @@ pub type StorageKey = H256; pub type StorageValue = U256; /// The ID of block/transaction transition (represents state transition) pub type TransitionId = u64; +/// Solidity contract functions are addressed using the first four byte of the Keccak-256 hash of +/// their signature +pub type Selector = [u8; 4]; pub use ethers_core::{ types as rpc, diff --git a/crates/revm/revm-inspectors/src/tracing/fourbyte.rs b/crates/revm/revm-inspectors/src/tracing/fourbyte.rs new file mode 100644 index 0000000000..ffebf976c5 --- /dev/null +++ b/crates/revm/revm-inspectors/src/tracing/fourbyte.rs @@ -0,0 +1,79 @@ +//! Fourbyte tracing inspector +//! +//! Solidity contract functions are addressed using the first four byte of the Keccak-256 hash of +//! their signature. Therefore when calling the function of a contract, the caller must send this +//! function selector as well as the ABI-encoded arguments as call data. +//! +//! The 4byteTracer collects the function selectors of every function executed in the lifetime of a +//! transaction, along with the size of the supplied call data. The result is a map of +//! SELECTOR-CALLDATASIZE to number of occurrences entries, where the keys are SELECTOR-CALLDATASIZE +//! and the values are number of occurrences of this key. For example: +//! +//! ```json +//! { +//! "0x27dc297e-128": 1, +//! "0x38cc4831-0": 2, +//! "0x524f3889-96": 1, +//! "0xadf59f99-288": 1, +//! "0xc281d19e-0": 1 +//! } +//! ``` +//! +//! See also + +use reth_primitives::{bytes::Bytes, hex, Selector}; +use reth_rpc_types::trace::geth::FourByteFrame; +use revm::{ + interpreter::{CallInputs, Gas, InstructionResult}, + Database, EVMData, Inspector, +}; +use std::collections::HashMap; + +/// Fourbyte tracing inspector that records all function selectors and their calldata sizes. +#[derive(Debug, Clone, Default)] +pub struct FourByteInspector { + /// The map of SELECTOR to number of occurrences entries + inner: HashMap<(Selector, usize), u64>, +} + +impl FourByteInspector { + /// Returns the map of SELECTOR to number of occurrences entries + pub fn inner(&self) -> &HashMap<(Selector, usize), u64> { + &self.inner + } +} + +impl Inspector for FourByteInspector +where + DB: Database, +{ + fn call( + &mut self, + _data: &mut EVMData<'_, DB>, + call: &mut CallInputs, + _is_static: bool, + ) -> (InstructionResult, Gas, Bytes) { + if call.input.len() >= 4 { + let selector = Selector::try_from(&call.input[..4]).expect("input is at least 4 bytes"); + let calldata_size = call.input[4..].len(); + *self.inner.entry((selector, calldata_size)).or_default() += 1; + } + + (InstructionResult::Continue, Gas::new(0), Bytes::new()) + } +} + +impl From for FourByteFrame { + fn from(value: FourByteInspector) -> Self { + FourByteFrame( + value + .inner + .into_iter() + .map(|((selector, calldata_size), count)| { + let key = format!("0x{}-{}", hex::encode(&selector[..]), calldata_size); + (key, count) + }) + .collect(), + ) + } +} diff --git a/crates/revm/revm-inspectors/src/tracing/mod.rs b/crates/revm/revm-inspectors/src/tracing/mod.rs index 0401ec47f4..8cda4a8002 100644 --- a/crates/revm/revm-inspectors/src/tracing/mod.rs +++ b/crates/revm/revm-inspectors/src/tracing/mod.rs @@ -17,10 +17,12 @@ use types::{CallTrace, CallTraceStep}; mod arena; mod builder; mod config; +mod fourbyte; mod types; mod utils; pub use builder::{geth::GethTraceBuilder, parity::ParityTraceBuilder}; pub use config::TracingInspectorConfig; +pub use fourbyte::FourByteInspector; /// An inspector that collects call traces. ///