refactor: name the failing arena explicitly in get_stack_trace - #1623
Conversation
|
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #1623 +/- ##
==========================================
+ Coverage 79.91% 79.94% +0.02%
==========================================
Files 461 461
Lines 80116 80138 +22
Branches 80116 80138 +22
==========================================
+ Hits 64023 64064 +41
+ Misses 13883 13865 -18
+ Partials 2210 2209 -1 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
|
/bench hardhat-ref=update-oz-scenario-pin |
|
⏳ EDR CI for this commit hasn't passed yet, so the regression benchmark was not started. Comment |
|
/bench |
|
⏳ EDR CI for this commit hasn't passed yet, so the regression benchmark was not started. Comment |
731e708 to
b446a04
Compare
There was a problem hiding this comment.
Pull request overview
Refactors stack-trace generation to explicitly identify the failing trace while treating preceding traces solely as deployed-code sources.
Changes:
- Adds
DeployedCodeand updatesget_stack_traceinputs and return type. - Updates provider, test runner, and invariant replay call sites.
- Handles invariant failures with no recorded EVM trace explicitly.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
crates/edr_solidity/src/solidity_stack_trace.rs |
Introduces the explicit stack-trace API. |
crates/edr_solidity_tests/src/runner.rs |
Selects failing traces at test-runner call sites. |
crates/foundry/evm/evm/src/executors/invariant/replay.rs |
Selects failing traces during invariant replay. |
crates/edr_provider/src/error.rs |
Adapts transaction failure handling to the new API. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
b446a04 to
2d909cc
Compare
2d909cc to
e22b52d
Compare
0e52072 to
c868758
Compare
c868758 to
97ca607
Compare
97ca607 to
ff06e01
Compare
Previously the failing arena was implicit: `get_stack_trace` folded over
an iterator and converted whichever arena came last, with a doc comment
('assumes last trace is the error one') carrying the whole contract.
Every other arena was walked only to seed the creation/runtime code maps.
Make that split explicit in the signature:
- `failing_trace`: the arena that is converted and analysed,
- `code_sources`: arenas walked only for their CREATE nodes, which
therefore never need recorded EVM steps,
- `deployed_code`: pre-computed creation/runtime code mappings, seeded
before the arenas are walked (replaces the runtime-code-only third
parameter; the provider now passes `DeployedCode { runtime: Some(..) }`).
`collect_stack_trace` requires the failing arena the same way: its callers
split it off `execution_traces` themselves, so the reasoning about whether
a failing arena was recorded lives at each call site.
One deliberate behavioural change falls out: an invariant campaign that
fails without recording any EVM call (e.g. an ABI error or too many
`vm.assume` rejects) now reports no stack trace, where it previously
pointed the stack-trace heuristics at the last *successful* setup arena
(`setUp()` has necessarily succeeded to reach invariant execution) and
produced a heuristic failure at best. The result's reason string already
explains such failures.
The stronger invariant — only the failing arena's steps are ever read —
is what allows later commits to strip steps from retained arenas.
ff06e01 to
af03cd9
Compare
get_stack_traceused to take one flat iterator of trace arenas and convert whichever came last, relying on a doc comment — "assumes last trace is the error one" — to carry the whole contract. Every arena before the last was only ever walked to collect the creation/runtime bytecode of deployed contracts, needed to decode the failing trace.This PR makes that split explicit in the signature:
failing_trace— the arena that is converted and analysed;code_sources— arenas walked only for their CREATE nodes, to map contract addresses to code;deployed_code— pre-computed address→code mappings, seeded before the arenas are walked. This replaces the previous third parameter, which could only seed runtime code; the provider now passesDeployedCode { runtime: Some(..) }with unchanged behaviour.The test runner's
collect_stack_tracehelper requires the failing arena the same way. Its callers split it offexecution_tracesthemselves, so the reasoning about whether a failing arena was recorded now lives at each call site, where it can actually be justified: the unit, table and fuzz sites run right after the failing call's arena was recorded under an active tracer; the one site where no arena may exist — an invariant campaign that failed before recording any EVM call — handles that case explicitly.Why
Two reasons:
-vvv+) rely on exactly that to strip steps from every retained arena.Behaviour change (one, deliberate)
An invariant campaign that fails without recording any EVM call (e.g. an ABI error, or too many
vm.assumerejects) now reports no stack trace. Previously the "last arena" fallback silently pointed the stack-trace heuristics at the last setup arena — a call that necessarily succeeded, since a failedsetUp()never reaches invariant execution — producing a heuristic failure at best. No arena describes such a failure; the test result'sreasonstring already explains it ("failed to set up invariant testing environment: …").Everything else is a pure refactor: same arenas walked in the same order, same seeding precedence (pre-computed code → code sources → failing trace, later wins).
Testing
cargo test -p edr_solidity_tests --test it(123 passing) — includingalways_mode_produces_stack_trace_for_failing_test, which exercises stack-trace generation through the unit, table, fuzz, invariant and invariant-campaign-failure paths.