Skip to content

Commit a31c5f8

Browse files
Update hevm to 9ba5e52fc7ec7ae6f7f3a25d5ee426625d2aa9d (#1487)
* Update `hevm` to `9ba5e52fc7ec7ae6f7f3a25d5ee426625d2aa9d` * CLAUDE.md: document import order * tree-wide: sort imports * Fix symbolic tests after hevm update * update the fetching code for the new hevm * improved rpc fetching --------- Co-authored-by: gustavo-grieco <gustavo.grieco+github@gmail.com>
1 parent 6c3fe00 commit a31c5f8

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

56 files changed

+299
-295
lines changed

CLAUDE.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,27 @@ cabal --enable-profiling run echidna -- contract.sol +RTS -p -s
7272
- Main config types in `lib/Echidna/Types/Config.hs`
7373
- Supports campaign, UI, transaction, and Solidity-specific settings
7474

75+
## Code Style
76+
77+
### Import Organization
78+
Imports should be organized into three groups, separated by blank lines, with imports **alphabetically ordered** within each group:
79+
80+
1. **System and 3rd-party imports**: Standard library and external dependencies (alphabetically ordered)
81+
2. **EVM imports**: Modules from `hevm` (e.g., `EVM.*`, `EVM.Types.*`) (alphabetically ordered)
82+
3. **Echidna imports**: Internal modules from this project (e.g., `Echidna.*`) (alphabetically ordered)
83+
84+
Example:
85+
```haskell
86+
import Control.Monad (when)
87+
import Data.Text (Text)
88+
89+
import EVM (VM)
90+
import EVM.Types (Addr)
91+
92+
import Echidna.ABI (genAbiCall)
93+
import Echidna.Types.Campaign (Campaign)
94+
```
95+
7596
## Important Development Notes
7697

7798
- The project uses GHC2021 language standard with several extensions enabled

flake.nix

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,8 @@
5454
(pkgs.haskellPackages.callCabal2nix "hevm" (pkgs.fetchFromGitHub {
5555
owner = "ethereum";
5656
repo = "hevm";
57-
rev = "0d9e2744903d160b175cd9e727660b493d9fac6f";
58-
sha256 = "sha256-SYqhjlvGKdWf55JjGZ8BPFtXqbkL81os5FB9j4Nj40A=";
57+
rev = "9ba5e52fc7ec7ae6f7f3a25d5ee426625d2aa9d3";
58+
sha256 = "sha256-5ZWsXtmZsMw2el4cuR9T+qrySTra6Lcaty/RrLOQ2hU=";
5959
}) { secp256k1 = pkgs.secp256k1; })
6060
([
6161
pkgs.haskell.lib.compose.dontCheck

lib/Echidna.hs

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,41 +3,40 @@ module Echidna where
33
import Control.Concurrent (newChan)
44
import Control.Monad.Catch (MonadThrow(..))
55
import Control.Monad.IO.Class (liftIO)
6-
import Control.Monad.ST (RealWorld)
76
import Data.IORef (newIORef)
87
import Data.List (find, nub)
98
import Data.List.NonEmpty (NonEmpty)
109
import Data.List.NonEmpty qualified as NE
1110
import Data.Map.Strict qualified as Map
1211
import Data.Maybe (mapMaybe)
1312
import Data.Set qualified as Set
13+
import Data.Text qualified as T
1414
import System.FilePath ((</>))
15+
import System.IO (stderr, hPutStrLn)
1516

1617
import EVM (cheatCode)
1718
import EVM.ABI (AbiValue(AbiAddress))
1819
import EVM.Dapp (dappInfo)
20+
import EVM.Effects (TTY(..), ReadConfig(..), defaultConfig)
1921
import EVM.Fetch qualified
2022
import EVM.Solidity (BuildOutput(..), Contracts(Contracts), Method(..), Mutability(..), SolcContract(..))
2123
import EVM.Types hiding (Env)
22-
import EVM.Effects (TTY(..), ReadConfig(..), defaultConfig)
23-
import Data.Text qualified as T
24-
import System.IO (stderr, hPutStrLn)
2524

2625
import Echidna.ABI
2726
import Echidna.Onchain as Onchain
2827
import Echidna.Output.Corpus
29-
import Echidna.SourceMapping (findSrcForReal)
30-
import Echidna.SourceAnalysis.Slither
3128
import Echidna.Solidity
29+
import Echidna.SourceAnalysis.Slither
30+
import Echidna.SourceMapping (findSrcForReal)
3231
import Echidna.SymExec.Symbolic (forceAddr)
3332
import Echidna.Types.Campaign
3433
import Echidna.Types.Config
3534
import Echidna.Types.Random
35+
import Echidna.Types.Signature (ContractName)
3636
import Echidna.Types.Solidity
37+
import Echidna.Types.Test (EchidnaTest)
3738
import Echidna.Types.Tx
3839
import Echidna.Types.World
39-
import Echidna.Types.Test (EchidnaTest)
40-
import Echidna.Types.Signature (ContractName)
4140

4241
-- | This function is used to prepare, process, compile and initialize smart contracts for testing.
4342
-- It takes:
@@ -56,7 +55,7 @@ prepareContract
5655
-> BuildOutput
5756
-> Maybe ContractName
5857
-> Seed
59-
-> IO (VM Concrete RealWorld, Env, GenDict)
58+
-> IO (VM Concrete, Env, GenDict)
6059
prepareContract cfg solFiles buildOutput selectedContract seed = do
6160
let solConf = cfg.solConf
6261
(Contracts contractMap) = buildOutput.contracts

lib/Echidna/ABI.hs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,19 +7,19 @@ import Data.Binary.Put (runPut, putWord32be)
77
import Data.BinaryWord (unsignedWord)
88
import Data.Bits (bit)
99
import Data.Bool (bool)
10-
import Data.ByteString.Lazy as BSLazy (toStrict)
1110
import Data.ByteString (ByteString)
1211
import Data.ByteString qualified as BS
12+
import Data.ByteString.Lazy as BSLazy (toStrict)
1313
import Data.DoubleWord (Int256, Word256)
1414
import Data.Foldable (toList)
15-
import Data.Map (Map)
16-
import Data.Map qualified as Map
17-
import Data.Set (Set)
18-
import Data.Set qualified as Set
1915
import Data.List (intercalate)
2016
import Data.List.NonEmpty (NonEmpty)
2117
import Data.List.NonEmpty qualified as NE
18+
import Data.Map (Map)
19+
import Data.Map qualified as Map
2220
import Data.Maybe (fromMaybe, catMaybes)
21+
import Data.Set (Set)
22+
import Data.Set qualified as Set
2323
import Data.Text (Text)
2424
import Data.Text qualified as T
2525
import Data.Text.Encoding (encodeUtf8)

lib/Echidna/Campaign.hs

Lines changed: 19 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -11,16 +11,15 @@ import Control.Monad.Random.Strict (MonadRandom, RandT, evalRandT)
1111
import Control.Monad.Reader (MonadReader, asks, liftIO, ask)
1212
import Control.Monad.State.Strict
1313
(MonadState(..), StateT(..), gets, MonadIO, modify')
14-
import Control.Monad.ST (RealWorld)
1514
import Control.Monad.Trans (lift)
1615
import Data.Binary.Get (runGetOrFail)
1716
import Data.ByteString.Lazy qualified as LBS
18-
import Data.IORef (readIORef, atomicModifyIORef', writeIORef)
1917
import Data.Foldable (foldlM)
18+
import Data.IORef (readIORef, atomicModifyIORef', writeIORef)
2019
import Data.List qualified as List
2120
import Data.List.NonEmpty qualified as NEList
22-
import Data.Map qualified as Map
2321
import Data.Map (Map, (\\))
22+
import Data.Map qualified as Map
2423
import Data.Maybe (isJust, mapMaybe, fromJust)
2524
import Data.Set (Set)
2625
import Data.Set qualified as Set
@@ -32,8 +31,8 @@ import System.Random (mkStdGen)
3231
import EVM (cheatCode)
3332
import EVM.ABI (getAbi, AbiType(AbiAddressType, AbiTupleType), AbiValue(AbiAddress, AbiTuple), abiValueType)
3433
import EVM.Dapp (DappInfo(..))
35-
import EVM.Types hiding (Env, Frame(state), Gas)
3634
import EVM.Solidity (SolcContract(..), Method(..))
35+
import EVM.Types hiding (Env, Frame(state), Gas)
3736

3837
import Echidna.ABI
3938
import Echidna.Events (extractEventValues)
@@ -42,15 +41,15 @@ import Echidna.Mutator.Corpus
4241
import Echidna.Shrink (shrinkTest)
4342
import Echidna.Solidity (chooseContract)
4443
import Echidna.SymExec.Common (extractTxs, extractErrors)
45-
import Echidna.SymExec.Symbolic (forceAddr)
4644
import Echidna.SymExec.Exploration (exploreContract, getTargetMethodFromTx, getRandomTargetMethod)
45+
import Echidna.SymExec.Symbolic (forceAddr)
4746
import Echidna.SymExec.Verification (verifyMethod, isSuitableToVerifyMethod)
4847
import Echidna.Test
4948
import Echidna.Transaction
5049
import Echidna.Types.Campaign
50+
import Echidna.Types.Config
5151
import Echidna.Types.Corpus (Corpus, corpusSize)
5252
import Echidna.Types.Coverage (coverageStats)
53-
import Echidna.Types.Config
5453
import Echidna.Types.Random (rElem)
5554
import Echidna.Types.Signature (FunctionName)
5655
import Echidna.Types.Test
@@ -73,7 +72,7 @@ isSuccessful =
7372
-- contain minimized corpus without sequences that didn't increase the coverage.
7473
replayCorpus
7574
:: (MonadIO m, MonadThrow m, MonadRandom m, MonadReader Env m, MonadState WorkerState m)
76-
=> VM Concrete RealWorld -- ^ VM to start replaying from
75+
=> VM Concrete -- ^ VM to start replaying from
7776
-> [(FilePath, [Tx])] -- ^ corpus to replay
7877
-> m ()
7978
replayCorpus vm txSeqs =
@@ -93,7 +92,7 @@ runWorker
9392
=> WorkerType
9493
-> StateT WorkerState m ()
9594
-- ^ Callback to run after each state update (for instrumentation)
96-
-> VM Concrete RealWorld -- ^ Initial VM state
95+
-> VM Concrete -- ^ Initial VM state
9796
-> GenDict -- ^ Generation dictionary
9897
-> Int -- ^ Worker id starting from 0
9998
-> [(FilePath, [Tx])]
@@ -110,7 +109,7 @@ runSymWorker
110109
:: (MonadIO m, MonadThrow m, MonadReader Env m)
111110
=> StateT WorkerState m ()
112111
-- ^ Callback to run after each state update (for instrumentation)
113-
-> VM Concrete RealWorld -- ^ Initial VM state
112+
-> VM Concrete -- ^ Initial VM state
114113
-> GenDict -- ^ Generation dictionary
115114
-> Int -- ^ Worker id starting from 0
116115
-> [(FilePath, [Tx])]
@@ -324,7 +323,7 @@ runFuzzWorker
324323
:: (MonadIO m, MonadThrow m, MonadReader Env m)
325324
=> StateT WorkerState m ()
326325
-- ^ Callback to run after each state update (for instrumentation)
327-
-> VM Concrete RealWorld -- ^ Initial VM state
326+
-> VM Concrete -- ^ Initial VM state
328327
-> GenDict -- ^ Generation dictionary
329328
-> Int -- ^ Worker id starting from 0
330329
-> [(FilePath, [Tx])]
@@ -454,9 +453,9 @@ randseq deployedContracts = do
454453
-- Returns resulting VM, as well as whether any new coverage was found.
455454
callseq
456455
:: (MonadIO m, MonadThrow m, MonadRandom m, MonadReader Env m, MonadState WorkerState m)
457-
=> VM Concrete RealWorld
456+
=> VM Concrete
458457
-> [Tx]
459-
-> m (VM Concrete RealWorld, Bool)
458+
-> m (VM Concrete, Bool)
460459
callseq vm txSeq = do
461460
env <- ask
462461
-- First, we figure out whether we need to execute with or without coverage
@@ -524,7 +523,7 @@ callseq vm txSeq = do
524523
-- know the return type for each function called. If yes, try to parse the
525524
-- return value as a value of that type. Returns a 'GenDict' style Map.
526525
returnValues
527-
:: [(Tx, VMResult Concrete RealWorld)]
526+
:: [(Tx, VMResult Concrete)]
528527
-> (FunctionName -> Maybe AbiType)
529528
-> Map AbiType (Set AbiValue)
530529
returnValues txResults returnTypeOf =
@@ -555,7 +554,7 @@ callseq vm txSeq = do
555554
getTupleVector _ = error "Not a tuple!"
556555

557556
-- | Add transactions to the corpus, discarding reverted ones
558-
addToCorpus :: Int -> [(Tx, VMResult Concrete RealWorld)] -> Corpus -> Corpus
557+
addToCorpus :: Int -> [(Tx, VMResult Concrete)] -> Corpus -> Corpus
559558
addToCorpus n res corpus =
560559
if null rtxs then corpus else Set.insert (n, rtxs) corpus
561560
where rtxs = fst <$> res
@@ -564,8 +563,8 @@ callseq vm txSeq = do
564563
-- executed, saving the transaction if it finds new coverage.
565564
execTxOptC
566565
:: (MonadIO m, MonadReader Env m, MonadState WorkerState m, MonadThrow m)
567-
=> VM Concrete RealWorld -> Tx
568-
-> m (VMResult Concrete RealWorld, VM Concrete RealWorld)
566+
=> VM Concrete -> Tx
567+
-> m (VMResult Concrete, VM Concrete)
569568
execTxOptC vm tx = do
570569
((res, grew), vm') <- runStateT (execTxWithCov tx) vm
571570
when grew $ do
@@ -581,10 +580,10 @@ execTxOptC vm tx = do
581580
-- of transactions, constantly checking if we've solved any tests.
582581
evalSeq
583582
:: (MonadIO m, MonadThrow m, MonadRandom m, MonadReader Env m, MonadState WorkerState m)
584-
=> VM Concrete RealWorld -- ^ Initial VM
585-
-> (VM Concrete RealWorld -> Tx -> m (result, VM Concrete RealWorld))
583+
=> VM Concrete -- ^ Initial VM
584+
-> (VM Concrete -> Tx -> m (result, VM Concrete))
586585
-> [Tx]
587-
-> m ([(Tx, result)], VM Concrete RealWorld)
586+
-> m ([(Tx, result)], VM Concrete)
588587
evalSeq vm0 execFunc = go vm0 [] where
589588
go vm executedSoFar toExecute = do
590589
-- NOTE: we do reverse here because we build up this list by prepending,
@@ -627,7 +626,7 @@ findFailedTests = do
627626
-- | Update an open test after checking if it is falsified by the 'reproducer'
628627
updateOpenTest
629628
:: (MonadIO m, MonadThrow m, MonadRandom m, MonadReader Env m, MonadState WorkerState m)
630-
=> VM Concrete RealWorld -- ^ VM after applying potential reproducer
629+
=> VM Concrete -- ^ VM after applying potential reproducer
631630
-> [Tx] -- ^ potential reproducer
632631
-> EchidnaTest
633632
-> m (Maybe EchidnaTest)

lib/Echidna/Config.hs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ import Data.Set qualified as Set
1313
import Data.Text (isPrefixOf)
1414
import Data.Yaml qualified as Y
1515

16-
import EVM.Types (VM(..), W256)
1716
import EVM.Solvers (Solver(..))
17+
import EVM.Types (VM(..), W256)
1818

1919
import Echidna.Mutator.Corpus (defaultMutationConsts)
2020
import Echidna.Test

lib/Echidna/Deploy.hs

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,28 +15,27 @@ import Data.Text.Encoding (encodeUtf8)
1515
import EVM.Solidity
1616
import EVM.Types hiding (Env)
1717

18-
import Echidna.Exec (execTx, execTxWithCov)
1918
import Echidna.Events (extractEvents)
19+
import Echidna.Exec (execTx, execTxWithCov)
2020
import Echidna.Types.Campaign (CampaignConf(..))
2121
import Echidna.Types.Config (Env(..), EConfig(..))
2222
import Echidna.Types.Solidity (SolException(..))
2323
import Echidna.Types.Tx (createTx, unlimitedGasPerBlock)
24-
import Control.Monad.ST (RealWorld)
2524

2625
deployContracts
2726
:: (MonadIO m, MonadReader Env m, MonadThrow m)
2827
=> [(Addr, SolcContract)]
2928
-> Addr
30-
-> VM Concrete RealWorld
31-
-> m (VM Concrete RealWorld)
29+
-> VM Concrete
30+
-> m (VM Concrete)
3231
deployContracts cs = deployBytecodes' $ map (\(a, c) -> (a, c.creationCode)) cs
3332

3433
deployBytecodes
3534
:: (MonadIO m, MonadReader Env m, MonadThrow m)
3635
=> [(Addr, Text)]
3736
-> Addr
38-
-> VM Concrete RealWorld
39-
-> m (VM Concrete RealWorld)
37+
-> VM Concrete
38+
-> m (VM Concrete)
4039
deployBytecodes cs = deployBytecodes' $
4140
(\(a, bc) ->
4241
(a, fromRight (error ("invalid b16 decoding of: " ++ show bc)) $ BS16.decode $ encodeUtf8 bc)
@@ -47,8 +46,8 @@ deployBytecodes'
4746
:: (MonadIO m, MonadReader Env m, MonadThrow m)
4847
=> [(Addr, ByteString)]
4948
-> Addr
50-
-> VM Concrete RealWorld
51-
-> m (VM Concrete RealWorld)
49+
-> VM Concrete
50+
-> m (VM Concrete)
5251
deployBytecodes' cs src initialVM = foldM deployOne initialVM cs
5352
where
5453
deployOne vm (dst, bytecode) = do

lib/Echidna/Events.hs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ type Events = [Text]
3535
emptyEvents :: TreePos Empty a
3636
emptyEvents = fromForest []
3737

38-
extractEvents :: Bool -> DappInfo -> VM Concrete s -> Events
38+
extractEvents :: Bool -> DappInfo -> VM Concrete -> Events
3939
extractEvents decodeErrors dappInfo vm =
4040
let forest = traceForest vm
4141
in maybeToList (decodeRevert decodeErrors vm)
@@ -78,7 +78,7 @@ extractEvents decodeErrors dappInfo vm =
7878
_ -> Nothing
7979

8080
-- | Extract all non‑indexed event values emitted between two VM states.
81-
extractEventValues :: DappInfo -> VM Concrete s -> VM Concrete s -> Map AbiType (Set AbiValue)
81+
extractEventValues :: DappInfo -> VM Concrete -> VM Concrete -> Map AbiType (Set AbiValue)
8282
extractEventValues dappInfo vm vm' =
8383
let
8484
oldLogs = vm.logs
@@ -113,7 +113,7 @@ maybeContractNameFromCodeHash info codeHash = contractToName <$> maybeContract
113113
where maybeContract = snd <$> Map.lookup codeHash info.solcByHash
114114
contractToName c = contractNamePart c.contractName
115115

116-
decodeRevert :: Bool -> VM Concrete s -> Maybe Text
116+
decodeRevert :: Bool -> VM Concrete -> Maybe Text
117117
decodeRevert decodeErrors vm =
118118
case vm.result of
119119
Just (VMFailure (Revert (ConcreteBuf bs))) -> decodeRevertMsg decodeErrors bs

0 commit comments

Comments
 (0)