Skip to content

Commit

Permalink
cleanup
Browse files Browse the repository at this point in the history
  • Loading branch information
samalws-tob committed Jan 9, 2024
1 parent 7c8fdbc commit b78e6a7
Show file tree
Hide file tree
Showing 6 changed files with 28 additions and 7 deletions.
4 changes: 3 additions & 1 deletion lib/Echidna/Exec.hs
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,8 @@ execTxWithCov tx = do
-- TODO: no-op when pc is out-of-bounds. This shouldn't happen but
-- we observed this in some real-world scenarios. This is likely a
-- bug in another place, investigate.
-- ... this should be fixed now, since we use `codeContract` instead
-- of `contract` for everything; it may be safe to remove this check.
when (pc < VMut.length vec) $
VMut.read vec pc >>= \case
(_, depths, results) | depth < 64 && not (depths `testBit` depth) -> do
Expand All @@ -313,7 +315,7 @@ execTxWithCov tx = do
-- | Get the VM's current execution location
currentCovLoc vm = (vm.state.pc, fromMaybe 0 $ vmOpIx vm, length vm.frames)

-- | Get the current contract
-- | Get the current contract being executed
currentContract vm = fromMaybe (error "no contract information on coverage") $
vm ^? #env % #contracts % at vm.state.codeContract % _Just

Expand Down
4 changes: 2 additions & 2 deletions lib/Echidna/Transaction.hs
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,8 @@ genTx world txConf deployedContracts = do
genDict <- gets (.genDict)
sigMap <- getSignatures world.highSignatureMap world.lowSignatureMap
sender <- rElem' world.senders
mappedList <- liftIO $ mapM (toContractA env sigMap) (toList deployedContracts)
(dstAddr, dstAbis) <- rElem' $ Set.fromList $ catMaybes mappedList
contractAList <- liftIO $ mapM (toContractA env sigMap) (toList deployedContracts)
(dstAddr, dstAbis) <- rElem' $ Set.fromList $ catMaybes contractAList
solCall <- genInteractionsM genDict dstAbis
value <- genValue txConf.maxValue genDict.dictValues world.payableSigs solCall
ts <- (,) <$> genDelay txConf.maxTimeDelay genDict.dictValues
Expand Down
21 changes: 19 additions & 2 deletions lib/Echidna/Types/CodehashMap.hs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,15 @@ import EVM.Dapp (DappInfo, findSrc)
import EVM.Solidity (SolcContract(..))
import EVM.Types (Contract(..), W256)

-- | Map from contracts' codehashes to their "real" (compile-time) codehash.
-- This is relevant when the immutables solidity feature is used;
-- when this feature is not used, the map will just end up being an identity map.
-- `CodehashMap` is used in signature map and coverage map lookups.
type CodehashMap = IORef (Map W256 W256)

-- | Lookup a codehash in the `CodehashMap`.
-- In the case that it's not found, find the "real" (compile-time) codehash and add it to the map.
-- This is done using hevm's `findSrc` function.
lookupCodehash :: CodehashMap -> W256 -> Contract -> DappInfo -> IO W256
lookupCodehash chmap codehash contr dapp = do
chmapVal <- readIORef chmap
Expand All @@ -20,17 +27,26 @@ lookupCodehash chmap codehash contr dapp = do
atomicModifyIORef' chmap $ (, ()) . Map.insert codehash originalCodehash
pure originalCodehash

-- | Given a map from codehash to some values of type `a`, lookup a contract in the map using its codehash.
-- In current use, the `Map W256 a` will be either a `SignatureMap` or a `CoverageMap`.
-- Returns the "real" codehash, and the map entry if it is found.
lookupUsingCodehash :: CodehashMap -> Contract -> DappInfo -> Map W256 a -> IO (W256, Maybe a)
lookupUsingCodehash chmap contr dapp mapVal = do
lookupUsingCodehash chmap contr dapp mapVal =
ifNotFound codehash $ do
codehash' <- lookupCodehash chmap codehash contr dapp
ifNotFound codehash' $ pure (codehash', Nothing)
ifNotFound codehash' $
pure (codehash', Nothing)
where
codehash = forceWord contr.codehash
ifNotFound key notFoundCase = case Map.lookup key mapVal of
Nothing -> notFoundCase
Just val -> pure (key, Just val)

-- | Same as `lookupUsingCodehash`, except we add to the map if we don't find anything.
-- The `make` argument is the IO to generate a new element;
-- it is only run if nothing is found in the map.
-- In the case that `make` returns `Nothing`, the map will be unchanged.
-- Returns the map entry, if it is found or generated.
lookupUsingCodehashOrInsert :: CodehashMap -> Contract -> DappInfo -> IORef (Map W256 a) -> IO (Maybe a) -> IO (Maybe a)
lookupUsingCodehashOrInsert chmap contr dapp mapRef make = do
mapVal <- readIORef mapRef
Expand All @@ -42,6 +58,7 @@ lookupUsingCodehashOrInsert chmap contr dapp mapRef make = do
applyModification _ Nothing = pure Nothing
applyModification key (Just val) = atomicModifyIORef' mapRef $ modifyFn key val

-- Take care of multithreaded edge case
modifyFn key val oldMap = case Map.lookup key oldMap of
Just val' -> (oldMap, Just val')
Nothing -> (Map.insert key val oldMap, Just val)
2 changes: 1 addition & 1 deletion lib/Echidna/Types/Config.hs
Original file line number Diff line number Diff line change
Expand Up @@ -69,9 +69,9 @@ data Env = Env

, testsRef :: IORef [EchidnaTest]
, coverageRef :: IORef CoverageMap
, codehashMap :: CodehashMap
, corpusRef :: IORef Corpus

, codehashMap :: CodehashMap
, fetchContractCache :: IORef (Map Addr (Maybe Contract))
, fetchSlotCache :: IORef (Map Addr (Map W256 (Maybe W256)))
, chainId :: Maybe W256
Expand Down
3 changes: 2 additions & 1 deletion lib/Echidna/Types/Coverage.hs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ import EVM.Types (W256)

import Echidna.Types.Tx (TxResult)

-- | Map with the coverage information needed for fuzzing and source code printing
-- | Map with the coverage information needed for fuzzing and source code printing.
-- Indexed by contracts' "real" codehash; see `CodehashMap`.
type CoverageMap = Map W256 (IOVector CoverageInfo)

-- | Basic coverage information
Expand Down
1 change: 1 addition & 0 deletions lib/Echidna/Types/Signature.hs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ type SolCall = (FunctionName, [AbiValue])
-- | A contract is just an address with an ABI (for our purposes).
type ContractA = (Addr, NonEmpty SolSignature)

-- | Indexed by contracts' "real" codehash; see `CodehashMap`.
type SignatureMap = Map W256 (NonEmpty SolSignature)

knownBzzrPrefixes :: [ByteString]
Expand Down

0 comments on commit b78e6a7

Please sign in to comment.