Skip to content

feat: track EXTCODEHASH, EXTCODESIZE, EXTCODECOPY in UsedStateEVMInspector#913

Open
0xMars42 wants to merge 1 commit intoflashbots:developfrom
0xMars42:feat/extcode-tracking
Open

feat: track EXTCODEHASH, EXTCODESIZE, EXTCODECOPY in UsedStateEVMInspector#913
0xMars42 wants to merge 1 commit intoflashbots:developfrom
0xMars42:feat/extcode-tracking

Conversation

@0xMars42
Copy link
Copy Markdown

@0xMars42 0xMars42 commented Apr 5, 2026

Summary

Closes #58

Tracks EXTCODEHASH, EXTCODESIZE, and EXTCODECOPY opcodes in UsedStateEVMInspector, completing the coverage of state-reading opcodes started in #161.

Without this, the parallel builder cannot detect conflicts between a transaction that reads a contract's code (e.g. isContract() check via EXTCODESIZE) and another that creates or destroys a contract at the same address (via CREATE2/SELFDESTRUCT). These transactions could be placed in separate conflict groups and executed in the wrong order.

Changes

evm_inspector.rs Added read_code_addresses: HashSet<Address> to UsedStateTrace. The three opcodes are intercepted in step() by reading the target address from stack[0] before execution, same pattern as BALANCE.

groups.rs Added code_reads to GroupData and group_code_reads index to ConflictFinder. Two new conflict checks:

  • code_read x code_write: tx reads code of an address another tx creates/destroys
  • code_write x code_read: tx creates/destroys a contract another tx reads code from

MevTest.sol Added testReadCode(address) which executes extcodehash and extcodesize in inline assembly.

Notes

  • Reverted transactions: like read_slot_values and read_balances, code reads from reverted transactions are still recorded. This may produce false-positive conflicts (grouping transactions that don't actually conflict), but never false negatives. Safe by design.
  • Performance: the overhead is a HashSet::insert per EXTCODE* opcode occurrence. The step() callback was already instrumented this adds a match arm, not a new callback.

Known limitations

  • EXTCODECOPY shares the same interception logic as the other two (address at stack[0]) but has no dedicated Solidity test function. The three opcodes are handled in a single match arm.
  • A transfer to a non-existent address changes the result of EXTCODEHASH (from 0x00 to keccak256("")). Detecting this conflict would require crossing balance_writes with code_reads, which adds complexity for a very rare edge case. Left as a future improvement.

Tests

  • test_read_code: verifies read_code_addresses is populated when calling testReadCode on both a contract (MevTest) and an empty address (Dummy)
  • two_code_reads_no_conflict: two code reads on the same address don't conflict
  • code_read_and_creation_conflict: EXTCODEHASH + CREATE on same address = conflict
  • code_read_and_destruction_conflict: EXTCODEHASH + SELFDESTRUCT on same address = conflict
  • creation_then_code_read_conflict: CREATE first, then EXTCODEHASH = conflict (reverse direction)
  • destruction_then_code_read_conflict: SELFDESTRUCT first, then EXTCODEHASH = conflict (reverse direction)

I have completed the following steps:

  • Run make lint
  • Run make test
  • Added tests (if applicable)

@0xMars42 0xMars42 requested review from ZanCorDX and dvush as code owners April 5, 2026 13:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat: improve UsedStateEVMInspector by adding other op-codes that read or write

1 participant