argotorg / argotorg/hevm

costOfPrecompile crashes with internalError for recognized-but-unimplemented precompiles (0x0a-0x11, 0x100), bypassing the NonexistentPrecompile fallback

Open Beginner friendly
#1,084 0 comments 0 reactions 0 assignees View on GitHub
bug
Dominant language
Haskell
Stars
358
Forks
79
Avg merge
1d 1h
Merged PRs (30d)
6

Description

## Summary

`isPrecompileAddr'` was widened to recognize `0x01`–`0x11` plus `0x100` (Cancun KZG, EIP-2537 BLS12-381, P256VERIFY), but `costOfPrecompile` still only implements `0x1`–`0x9`. Because the gas cost is forced **before** `executePrecompile`'s address dispatch, any call to `0x0a`–`0x11`/`0x100` dies with an uncatchable `internalError` in gas calculation — and the graceful `NonexistentPrecompile` fallback that `executePrecompile` already contains for exactly this situation is unreachable.

Present on `main` today (and in `8da7ea44ebf5524dce65b14e70cee1a4413eb6f0`, which Echidna 2.3.2 ships). Downstream report with a real-world reproducer: https://github.com/crytic/echidna/issues/1590

## Details

`src/EVM.hs` (current `main`):

```haskell
isPrecompileAddr' :: Addr -> Bool
isPrecompileAddr' 0x100 = True
isPrecompileAddr' x = 0x0 < x && x <= 0x11
```

`executePrecompile` computes the cost up front:

```haskell
executePrecompile preCompileAddr gasCap inOffset inSize outOffset outSize xs = do
...
let cost = costOfPrecompile fees preCompileAddr input
notImplemented = whenSymbolicElse
(partial $ PrecompileMissing {..})
(vmError $ NonexistentPrecompile preCompileAddr) -- graceful, catchable
...
if not (enoughGas cost gasCap) then ... -- forces `cost` here
```

but `costOfPrecompile` is partial:

```haskell
costOfPrecompile (FeeSchedule {..}) precompileAddr input =
...
case precompileAddr of
0x1 -> 3000
...
0x9 -> ...
_ -> internalError $ "unimplemented precompiled contract " ++ show precompileAddr
```

So the `notImplemented`/`NonexistentPrecompile` path can never fire for the newly-recognized addresses — the process dies in the gas step instead.

## Impact

Any execution that touches `0x0a`–`0x11` or `0x100` hard-crashes the host process. This is a regression relative to `release/0.57.0` (`5ec225475d5ba9cda24c5fb303acb76c88412553`), where `isPrecompileAddr` stopped at `0x09` and such addresses behaved as ordinary (empty) accounts.

Real-world trigger: crytic-compile-style library linking conventionally deploys libraries at low addresses (`0x10`, `0x11`, …). Under Echidna 2.3.2 (which bundles this hevm), the first touch of a library deployed at `0x10` aborts the entire fuzzing campaign in seconds. Full evidence and logs in crytic/echidna#1590.

Note also that `isPrecompileAddr'` is not fork-gated, so there is no EVM-version configuration that avoids this — pre-Cancun/Pectra forks also treat `0x0a`–`0x11` as precompiles.

## Suggested fix

1. Make `costOfPrecompile` total over the recognized range (return `0` or a nominal cost for not-yet-implemented addresses) so the existing `NonexistentPrecompile` path fires — converting an uncatchable crash into an ordinary VM error. One-line-class change.
2. Longer term: gate `isPrecompileAddr'` on the active fork, and/or implement the EIP-2537 BLS precompiles (tracked in #939, Fusaka support, as far as I can tell).

Happy to test a candidate fix against the full Aave v4 target that triggered this (public repo, deterministic reproducer in the echidna issue).

Contributor guide

No contributing guide indexed for this repository

Research direction

Start in src/EVM.hs with costOfPrecompile and trace how executePrecompile forces its result before address dispatch. Make recognized but unimplemented addresses reach the existing NonexistentPrecompile path instead of internalError, then validate the behavior with the Aave v4 reproducer described in crytic/echidna#1590.

Written by the indexing model from the issue text.

Assessment

Tech stack
haskell
Domain
blockchain
Issue type
Bug
Difficulty
2/5
Estimated time
1-3 hours
Activity status
Quiet
Clarity
Clearly specified
Newbie friendliness
78/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.