Conversation
…pruning Summary: - add event execution profiling in Rust via EventExecutionProfile and contract_events_with_profile - keep contract_events_with_stats API and extend extraction stats (selector pruning and runtime counters) - add src/bin/events_debug.rs for single-contract deep profiling (hot JUMPI PCs, queue/branch metrics) - prune event exploration selectors by state mutability (skip view/pure selectors; keep payable/nonpayable) - wire Python interface stats updates and type stubs for event_selectors_with_stats Validation: - cargo test --lib events:: -- --nocapture (10 passed) - cargo test --lib --features python -- --nocapture (34 passed) - cargo run --release --bin events_debug -- --code-file benchmark/results/row96.hex --iters 3 --warmup 1 --profile --top-pc 8 -> code_len=11099, events=7, selectors pruned 35 -> 15, avg=475.282ms (min=435.249, max=510.231) - release benchmark (first 20 contracts): total=2.39s, avg=119.14ms/contract, recall=0.9254, precision=1.0000
There was a problem hiding this comment.
Pull request overview
This pull request adds event selector extraction functionality to the evmole library with performance optimizations including multiple caching strategies and adaptive execution rounds. The implementation adds a new events module that performs symbolic execution on EVM bytecode to discover LOG operations and extract their event selectors (topic0 values).
Changes:
- Adds new
eventsmodule with sophisticated event extraction algorithm including static analysis, dynamic execution with path exploration, and multiple optimization strategies (mutability-based pruning, static dead-end detection, log reachability analysis) - Adds Python bindings for event extraction with statistics tracking via
event_selectors_with_stats()and integration into thecontract_info()API - Adds debug binary
events_debugfor profiling and testing event extraction performance
Reviewed changes
Copilot reviewed 5 out of 6 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| src/lib.rs | Exports new event-related types and functions from the events module |
| src/interface_py.rs | Adds Python bindings for event extraction, including PyEventExtractionStats class and event_selectors_with_stats function; updates contract_info to support events parameter |
| src/events/mod.rs | Core implementation of event extraction algorithm with caching, pruning, and profiling capabilities (1902 lines) |
| src/events/calldata.rs | Implements CallData trait for event extraction with minimal calldata simulation |
| src/bin/events_debug.rs | Debug binary for benchmarking and profiling event extraction with detailed statistics output |
| evmole.pyi | Adds Python type stubs for EventExtractionStats class and event-related parameters |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| if events { | ||
| args = args.with_events(); | ||
| } |
There was a problem hiding this comment.
The code calls args.with_events() but this method doesn't exist in the ContractInfoArgs struct (defined in src/contract_info.rs). The struct needs to be updated with a need_events field and a with_events() method. Additionally, the Contract struct should have an events field, and the contract_info() function should populate it when requested.
| if events { | |
| args = args.with_events(); | |
| } |
| /// Checks if a 32-byte value looks like a keccak256 hash (event selector). | ||
| fn is_plausible_event_hash(val: &[u8; 32]) -> bool { | ||
| if val == &[0u8; 32] { | ||
| return false; | ||
| } | ||
| if val[..6] == [0u8; 6] { | ||
| return false; | ||
| } | ||
| if val[26..] == [0u8; 6] { | ||
| return false; | ||
| } | ||
| let mut zero_run = 0u8; | ||
| let mut ff_run = 0u8; | ||
| for &b in val { | ||
| if b == 0 { | ||
| zero_run += 1; | ||
| if zero_run >= 4 { | ||
| return false; | ||
| } | ||
| } else { | ||
| zero_run = 0; | ||
| } | ||
| if b == 0xff { | ||
| ff_run += 1; | ||
| if ff_run >= 4 { | ||
| return false; | ||
| } | ||
| } else { | ||
| ff_run = 0; | ||
| } | ||
| } | ||
| true | ||
| } |
There was a problem hiding this comment.
The is_plausible_event_hash function has hardcoded indices (e.g., val[..6], val[26..]) that check for improbable patterns in event hashes. While these heuristics may be effective, consider adding comments explaining why these specific indices and patterns were chosen, as they appear to be based on empirical observations rather than formal requirements. This would help maintainability and future adjustments.
- default to context-aware selector entry; direct entry is now opt-in via EVMOLE_ENABLE_DIRECT_ENTRY - keep external call-result labels through VM ops and use them at JUMPI for targeted fork retention - add static topic0 supplement pass (strict default, configurable via env) - add VM label propagation tests Validation: - cargo test --lib events:: - cargo test --lib evm::vm::tests:: - bench (20, default): recall=0.9925 precision=1.0000 TP=133 FP=0 FN=1 elapsed=0.891s - bench (100, default): recall=0.9946 precision=0.9946 TP=555 FP=3 FN=3 elapsed=3.875s - bench (20, aggressive static): recall=1.0000 precision=0.9116 TP=134 FP=13 FN=0 elapsed=0.869s
|
You need to add 'events' to benchmark/ (specifically to the 'etherscan' and 'evmole-rs' providers) and check the success rate on the largest1k/random50k datasets. P.S. As I remember, Codex can understand the benchmark structure even on older models and add new tests to it. |
No description provided.