From ea375a99dbafe0c2868fc5997124de4a4734c284 Mon Sep 17 00:00:00 2001 From: Sam Alws Date: Tue, 20 Aug 2024 15:38:55 -0400 Subject: [PATCH 1/4] Read assert locations and determinate if they were executed or not Co-authored-by: ggrieco-tob --- lib/Echidna.hs | 4 ++-- lib/Echidna/Output/Source.hs | 25 +++++++++++++++++++++++++ lib/Echidna/Solidity.hs | 5 ++++- lib/Echidna/SourceAnalysis/Slither.hs | 23 ++++++++++++++++++++++- src/Main.hs | 7 +++++-- src/test/Common.hs | 2 +- 6 files changed, 59 insertions(+), 7 deletions(-) diff --git a/lib/Echidna.hs b/lib/Echidna.hs index 64b84fe93..ab608fb5d 100644 --- a/lib/Echidna.hs +++ b/lib/Echidna.hs @@ -51,7 +51,7 @@ prepareContract -> BuildOutput -> Maybe ContractName -> Seed - -> IO (VM Concrete RealWorld, Env, GenDict) + -> IO (VM Concrete RealWorld, Env, GenDict, AssertMappingByContract) prepareContract cfg solFiles buildOutput selectedContract seed = do let solConf = cfg.solConf (Contracts contractMap) = buildOutput.contracts @@ -90,7 +90,7 @@ prepareContract cfg solFiles buildOutput selectedContract seed = do seed (returnTypes contracts) - pure (vm, env, dict) + pure (vm, env, dict, slitherInfo.asserts) loadInitialCorpus :: Env -> IO [(FilePath, [Tx])] loadInitialCorpus env = do diff --git a/lib/Echidna/Output/Source.hs b/lib/Echidna/Output/Source.hs index c6c3ab98f..45393c445 100644 --- a/lib/Echidna/Output/Source.hs +++ b/lib/Echidna/Output/Source.hs @@ -4,6 +4,7 @@ module Echidna.Output.Source where import Prelude hiding (writeFile) +import Control.Monad (unless) import Data.ByteString qualified as BS import Data.Foldable import Data.IORef (readIORef) @@ -31,6 +32,7 @@ import Echidna.Types.Campaign (CampaignConf(..)) import Echidna.Types.Config (Env(..), EConfig(..)) import Echidna.Types.Coverage (OpIx, unpackTxResults, CoverageMap, CoverageFileType (..)) import Echidna.Types.Tx (TxResult(..)) +import Echidna.SourceAnalysis.Slither (AssertMappingByContract, AssertLocation(..)) saveCoverages :: Env @@ -188,3 +190,26 @@ buildRuntimeLinesMap sc contracts = where srcMaps = concatMap (\c -> toList $ c.runtimeSrcmap <> c.creationSrcmap) contracts + +checkAssertionsCoverage + :: SourceCache + -> [SolcContract] + -> CoverageMap + -> AssertMappingByContract + -> IO () +checkAssertionsCoverage sc cs covMap assertMap = do + covLines <- srcMapCov sc covMap cs + let asserts = concat $ concatMap Map.elems $ Map.elems assertMap + mapM_ (checkAssertionReached covLines) asserts + +checkAssertionReached :: Map String (Map Int [TxResult]) -> AssertLocation -> IO () +checkAssertionReached covLines assert = + maybe + warnAssertNotReached checkCoverage + (Map.lookup assert.filenameAbsolute covLines) + where + checkCoverage coverage = let lineNumbers = Map.keys coverage in + unless ((head assert.assertLines) `elem` lineNumbers) warnAssertNotReached + warnAssertNotReached = + putStrLn $ "WARNING: assertion at file: " ++ assert.filenameRelative + ++ " starting at line: " ++ show (head assert.assertLines) ++ " was never reached" diff --git a/lib/Echidna/Solidity.hs b/lib/Echidna/Solidity.hs index b7e599e16..1b44914f8 100644 --- a/lib/Echidna/Solidity.hs +++ b/lib/Echidna/Solidity.hs @@ -342,7 +342,7 @@ mkWorld SolConf{sender, testMode} sigMap maybeContract slitherInfo contracts = let eventMap = Map.unions $ map (.eventMap) contracts payableSigs = filterResults maybeContract slitherInfo.payableFunctions - as = if isAssertionMode testMode then filterResults maybeContract slitherInfo.asserts else [] + as = if isAssertionMode testMode then filterResults maybeContract (getAssertFns <$> slitherInfo.asserts) else [] cs = if isDapptestMode testMode then [] else filterResults maybeContract slitherInfo.constantFunctions \\ as (highSignatureMap, lowSignatureMap) = prepareHashMaps cs as $ filterFallbacks slitherInfo.fallbackDefined slitherInfo.receiveDefined contracts sigMap @@ -352,6 +352,9 @@ mkWorld SolConf{sender, testMode} sigMap maybeContract slitherInfo contracts = , payableSigs , eventMap } + where + getAssertFns :: Map FunctionName [AssertLocation] -> [FunctionName] + getAssertFns fnToAsserts = map fst $ filter (not . null . snd) $ Map.toList fnToAsserts -- | This function is used to filter the lists of function names according to the supplied -- contract name (if any) and returns a list of hashes diff --git a/lib/Echidna/SourceAnalysis/Slither.hs b/lib/Echidna/SourceAnalysis/Slither.hs index cb60028bb..490578cf2 100644 --- a/lib/Echidna/SourceAnalysis/Slither.hs +++ b/lib/Echidna/SourceAnalysis/Slither.hs @@ -40,11 +40,32 @@ enhanceConstants si = enh (AbiString s) = makeArrayAbiValues s enh v = [v] +data AssertLocation = AssertLocation + { start :: Int + , filenameRelative :: String + , filenameAbsolute :: String + , assertLines :: [Int] + , startColumn :: Int + , endingColumn :: Int + } deriving (Show) + +type AssertMappingByContract = Map ContractName (Map FunctionName [AssertLocation]) + +instance FromJSON AssertLocation where + parseJSON = withObject "" $ \o -> do + start <- o.: "start" + filenameRelative <- o.: "filename_relative" + filenameAbsolute <- o.: "filename_absolute" + assertLines <- o.: "lines" + startColumn <- o.: "starting_column" + endingColumn <- o.: "ending_column" + pure AssertLocation {..} + -- we loose info on what constants are in which functions data SlitherInfo = SlitherInfo { payableFunctions :: Map ContractName [FunctionName] , constantFunctions :: Map ContractName [FunctionName] - , asserts :: Map ContractName [FunctionName] + , asserts :: AssertMappingByContract , constantValues :: Map ContractName (Map FunctionName [AbiValue]) , generationGraph :: Map ContractName (Map FunctionName [FunctionName]) , solcVersions :: [Version] diff --git a/src/Main.hs b/src/Main.hs index 9e1d68d49..1750a420d 100644 --- a/src/Main.hs +++ b/src/Main.hs @@ -62,7 +62,7 @@ main = withUtf8 $ withCP65001 $ do -- take the seed from config, otherwise generate a new one seed <- maybe (getRandomR (0, maxBound)) pure cfg.campaignConf.seed - (vm, env, dict) <- prepareContract cfg cliFilePath buildOutput cliSelectedContract seed + (vm, env, dict, asserts) <- prepareContract cfg cliFilePath buildOutput cliSelectedContract seed initialCorpus <- loadInitialCorpus env -- start ui and run tests @@ -70,6 +70,10 @@ main = withUtf8 $ withCP65001 $ do tests <- traverse readIORef env.testRefs + let contracts = Map.elems env.dapp.solcByName + coverage <- readIORef env.coverageRef + checkAssertionsCoverage buildOutput.sources contracts coverage asserts + Onchain.saveRpcCache env -- save corpus @@ -108,7 +112,6 @@ main = withUtf8 $ withCP65001 $ do Onchain.saveCoverageReport env runId -- save source coverage reports - let contracts = Map.elems env.dapp.solcByName saveCoverages env runId dir buildOutput.sources contracts if isSuccessful tests then exitSuccess else exitWith (ExitFailure 1) diff --git a/src/test/Common.hs b/src/test/Common.hs index 884e11384..86eed2b5d 100644 --- a/src/test/Common.hs +++ b/src/test/Common.hs @@ -94,7 +94,7 @@ runContract f selectedContract cfg workerType = do seed <- maybe (getRandomR (0, maxBound)) pure cfg.campaignConf.seed buildOutput <- compileContracts cfg.solConf (f :| []) - (vm, env, dict) <- prepareContract cfg (f :| []) buildOutput selectedContract seed + (vm, env, dict, _) <- prepareContract cfg (f :| []) buildOutput selectedContract seed (_stopReason, finalState) <- flip runReaderT env $ runWorker workerType (pure ()) vm dict 0 [] cfg.campaignConf.testLimit selectedContract From b9bb57236eaf4392cdf01d28423f1c22b0add07b Mon Sep 17 00:00:00 2001 From: Sam Alws Date: Wed, 21 Aug 2024 14:12:13 -0400 Subject: [PATCH 2/4] accomodate older versions of solc --- lib/Echidna/Output/Source.hs | 4 ++-- lib/Echidna/Solidity.hs | 5 +---- lib/Echidna/SourceAnalysis/Slither.hs | 19 ++++++++++++++++++- 3 files changed, 21 insertions(+), 7 deletions(-) diff --git a/lib/Echidna/Output/Source.hs b/lib/Echidna/Output/Source.hs index 45393c445..0a4050c6a 100644 --- a/lib/Echidna/Output/Source.hs +++ b/lib/Echidna/Output/Source.hs @@ -32,7 +32,7 @@ import Echidna.Types.Campaign (CampaignConf(..)) import Echidna.Types.Config (Env(..), EConfig(..)) import Echidna.Types.Coverage (OpIx, unpackTxResults, CoverageMap, CoverageFileType (..)) import Echidna.Types.Tx (TxResult(..)) -import Echidna.SourceAnalysis.Slither (AssertMappingByContract, AssertLocation(..)) +import Echidna.SourceAnalysis.Slither (AssertMappingByContract, AssertLocation(..), assertLocationList) saveCoverages :: Env @@ -199,7 +199,7 @@ checkAssertionsCoverage -> IO () checkAssertionsCoverage sc cs covMap assertMap = do covLines <- srcMapCov sc covMap cs - let asserts = concat $ concatMap Map.elems $ Map.elems assertMap + let asserts = concatMap assertLocationList $ Map.elems assertMap mapM_ (checkAssertionReached covLines) asserts checkAssertionReached :: Map String (Map Int [TxResult]) -> AssertLocation -> IO () diff --git a/lib/Echidna/Solidity.hs b/lib/Echidna/Solidity.hs index 1b44914f8..990309ee5 100644 --- a/lib/Echidna/Solidity.hs +++ b/lib/Echidna/Solidity.hs @@ -342,7 +342,7 @@ mkWorld SolConf{sender, testMode} sigMap maybeContract slitherInfo contracts = let eventMap = Map.unions $ map (.eventMap) contracts payableSigs = filterResults maybeContract slitherInfo.payableFunctions - as = if isAssertionMode testMode then filterResults maybeContract (getAssertFns <$> slitherInfo.asserts) else [] + as = if isAssertionMode testMode then filterResults maybeContract (assertFunctionList <$> slitherInfo.asserts) else [] cs = if isDapptestMode testMode then [] else filterResults maybeContract slitherInfo.constantFunctions \\ as (highSignatureMap, lowSignatureMap) = prepareHashMaps cs as $ filterFallbacks slitherInfo.fallbackDefined slitherInfo.receiveDefined contracts sigMap @@ -352,9 +352,6 @@ mkWorld SolConf{sender, testMode} sigMap maybeContract slitherInfo contracts = , payableSigs , eventMap } - where - getAssertFns :: Map FunctionName [AssertLocation] -> [FunctionName] - getAssertFns fnToAsserts = map fst $ filter (not . null . snd) $ Map.toList fnToAsserts -- | This function is used to filter the lists of function names according to the supplied -- contract name (if any) and returns a list of hashes diff --git a/lib/Echidna/SourceAnalysis/Slither.hs b/lib/Echidna/SourceAnalysis/Slither.hs index 490578cf2..f8f74f59b 100644 --- a/lib/Echidna/SourceAnalysis/Slither.hs +++ b/lib/Echidna/SourceAnalysis/Slither.hs @@ -2,6 +2,7 @@ module Echidna.SourceAnalysis.Slither where +import Control.Applicative ((<|>)) import Data.Aeson ((.:), (.:?), (.!=), eitherDecode, parseJSON, withEmbeddedJSON, withObject) import Data.Aeson.Types (FromJSON, Parser, Value(String)) import Data.ByteString.Base16 qualified as BS16 (decode) @@ -49,7 +50,20 @@ data AssertLocation = AssertLocation , endingColumn :: Int } deriving (Show) -type AssertMappingByContract = Map ContractName (Map FunctionName [AssertLocation]) +data ContractAssertMapping + = AssertFunctionList [FunctionName] + | AssertLocationList (Map FunctionName [AssertLocation]) + deriving (Show) + +type AssertMappingByContract = Map ContractName ContractAssertMapping + +assertFunctionList :: ContractAssertMapping -> [FunctionName] +assertFunctionList (AssertFunctionList l) = l +assertFunctionList (AssertLocationList m) = map fst $ filter (not . null . snd) $ Map.toList m + +assertLocationList :: ContractAssertMapping -> [AssertLocation] +assertLocationList (AssertFunctionList _) = [] +assertLocationList (AssertLocationList m) = concat $ Map.elems m instance FromJSON AssertLocation where parseJSON = withObject "" $ \o -> do @@ -61,6 +75,9 @@ instance FromJSON AssertLocation where endingColumn <- o.: "ending_column" pure AssertLocation {..} +instance FromJSON ContractAssertMapping where + parseJSON x = (AssertFunctionList <$> parseJSON x) <|> (AssertLocationList <$> parseJSON x) + -- we loose info on what constants are in which functions data SlitherInfo = SlitherInfo { payableFunctions :: Map ContractName [FunctionName] From 4405c100b8ea93519ff0afbe2c7f999cccc1b008 Mon Sep 17 00:00:00 2001 From: Sam Alws Date: Wed, 21 Aug 2024 15:53:27 -0400 Subject: [PATCH 3/4] cleanup --- lib/Echidna.hs | 2 +- lib/Echidna/Output/Source.hs | 13 ++++++++----- lib/Echidna/SourceAnalysis/Slither.hs | 17 +++++++++++------ 3 files changed, 20 insertions(+), 12 deletions(-) diff --git a/lib/Echidna.hs b/lib/Echidna.hs index ab608fb5d..184dc182c 100644 --- a/lib/Echidna.hs +++ b/lib/Echidna.hs @@ -51,7 +51,7 @@ prepareContract -> BuildOutput -> Maybe ContractName -> Seed - -> IO (VM Concrete RealWorld, Env, GenDict, AssertMappingByContract) + -> IO (VM Concrete RealWorld, Env, GenDict, AssertListingByContract) prepareContract cfg solFiles buildOutput selectedContract seed = do let solConf = cfg.solConf (Contracts contractMap) = buildOutput.contracts diff --git a/lib/Echidna/Output/Source.hs b/lib/Echidna/Output/Source.hs index 0a4050c6a..c397a4707 100644 --- a/lib/Echidna/Output/Source.hs +++ b/lib/Echidna/Output/Source.hs @@ -32,7 +32,7 @@ import Echidna.Types.Campaign (CampaignConf(..)) import Echidna.Types.Config (Env(..), EConfig(..)) import Echidna.Types.Coverage (OpIx, unpackTxResults, CoverageMap, CoverageFileType (..)) import Echidna.Types.Tx (TxResult(..)) -import Echidna.SourceAnalysis.Slither (AssertMappingByContract, AssertLocation(..), assertLocationList) +import Echidna.SourceAnalysis.Slither (AssertListingByContract, AssertLocation(..), assertLocationList) saveCoverages :: Env @@ -191,25 +191,28 @@ buildRuntimeLinesMap sc contracts = srcMaps = concatMap (\c -> toList $ c.runtimeSrcmap <> c.creationSrcmap) contracts +-- | Check that all assertions were hit, and log a warning if they weren't checkAssertionsCoverage :: SourceCache -> [SolcContract] -> CoverageMap - -> AssertMappingByContract + -> AssertListingByContract -> IO () checkAssertionsCoverage sc cs covMap assertMap = do covLines <- srcMapCov sc covMap cs let asserts = concatMap assertLocationList $ Map.elems assertMap mapM_ (checkAssertionReached covLines) asserts +-- | Helper function for `checkAssertionsCoverage` which checks a single assertion +-- and logs a warning if it wasn't hit checkAssertionReached :: Map String (Map Int [TxResult]) -> AssertLocation -> IO () checkAssertionReached covLines assert = maybe warnAssertNotReached checkCoverage (Map.lookup assert.filenameAbsolute covLines) - where + where checkCoverage coverage = let lineNumbers = Map.keys coverage in unless ((head assert.assertLines) `elem` lineNumbers) warnAssertNotReached warnAssertNotReached = - putStrLn $ "WARNING: assertion at file: " ++ assert.filenameRelative - ++ " starting at line: " ++ show (head assert.assertLines) ++ " was never reached" + putStrLn $ "WARNING: assertion at file: " ++ assert.filenameRelative + ++ " starting at line: " ++ show (head assert.assertLines) ++ " was never reached" diff --git a/lib/Echidna/SourceAnalysis/Slither.hs b/lib/Echidna/SourceAnalysis/Slither.hs index f8f74f59b..09d5fbdbf 100644 --- a/lib/Echidna/SourceAnalysis/Slither.hs +++ b/lib/Echidna/SourceAnalysis/Slither.hs @@ -50,18 +50,23 @@ data AssertLocation = AssertLocation , endingColumn :: Int } deriving (Show) -data ContractAssertMapping +-- | Assertion listing for a contract. +-- There are two possibilities because different solc's give different formats. +-- We either have a list of functions that have assertions, or a full listing of individual assertions. +data ContractAssertListing = AssertFunctionList [FunctionName] | AssertLocationList (Map FunctionName [AssertLocation]) deriving (Show) -type AssertMappingByContract = Map ContractName ContractAssertMapping +type AssertListingByContract = Map ContractName ContractAssertListing -assertFunctionList :: ContractAssertMapping -> [FunctionName] +-- | Get a list of functions that have assertions +assertFunctionList :: ContractAssertListing -> [FunctionName] assertFunctionList (AssertFunctionList l) = l assertFunctionList (AssertLocationList m) = map fst $ filter (not . null . snd) $ Map.toList m -assertLocationList :: ContractAssertMapping -> [AssertLocation] +-- | Get a list of assertions, or an empty list if we don't have enough info +assertLocationList :: ContractAssertListing -> [AssertLocation] assertLocationList (AssertFunctionList _) = [] assertLocationList (AssertLocationList m) = concat $ Map.elems m @@ -75,14 +80,14 @@ instance FromJSON AssertLocation where endingColumn <- o.: "ending_column" pure AssertLocation {..} -instance FromJSON ContractAssertMapping where +instance FromJSON ContractAssertListing where parseJSON x = (AssertFunctionList <$> parseJSON x) <|> (AssertLocationList <$> parseJSON x) -- we loose info on what constants are in which functions data SlitherInfo = SlitherInfo { payableFunctions :: Map ContractName [FunctionName] , constantFunctions :: Map ContractName [FunctionName] - , asserts :: AssertMappingByContract + , asserts :: AssertListingByContract , constantValues :: Map ContractName (Map FunctionName [AbiValue]) , generationGraph :: Map ContractName (Map FunctionName [FunctionName]) , solcVersions :: [Version] From d528bca259087302ac408d6079291396173ffbfe Mon Sep 17 00:00:00 2001 From: Sam Alws Date: Thu, 22 Aug 2024 11:17:18 -0400 Subject: [PATCH 4/4] add SlitherInfo to Env --- lib/Echidna.hs | 11 ++++++----- lib/Echidna/Output/Source.hs | 15 ++++++++------- lib/Echidna/Types/Config.hs | 2 ++ src/Main.hs | 7 +++---- src/test/Common.hs | 4 ++-- 5 files changed, 21 insertions(+), 18 deletions(-) diff --git a/lib/Echidna.hs b/lib/Echidna.hs index 184dc182c..115b7d8bf 100644 --- a/lib/Echidna.hs +++ b/lib/Echidna.hs @@ -51,7 +51,7 @@ prepareContract -> BuildOutput -> Maybe ContractName -> Seed - -> IO (VM Concrete RealWorld, Env, GenDict, AssertListingByContract) + -> IO (VM Concrete RealWorld, Env, GenDict) prepareContract cfg solFiles buildOutput selectedContract seed = do let solConf = cfg.solConf (Contracts contractMap) = buildOutput.contracts @@ -70,7 +70,7 @@ prepareContract cfg solFiles buildOutput selectedContract seed = do let world = mkWorld cfg.solConf signatureMap selectedContract slitherInfo contracts - env <- mkEnv cfg buildOutput tests world + env <- mkEnv cfg buildOutput tests world (Just slitherInfo) -- deploy contracts vm <- loadSpecified env mainContract contracts @@ -90,7 +90,7 @@ prepareContract cfg solFiles buildOutput selectedContract seed = do seed (returnTypes contracts) - pure (vm, env, dict, slitherInfo.asserts) + pure (vm, env, dict) loadInitialCorpus :: Env -> IO [(FilePath, [Tx])] loadInitialCorpus env = do @@ -113,8 +113,8 @@ loadInitialCorpus env = do pure $ persistedCorpus ++ ethenoCorpus -mkEnv :: EConfig -> BuildOutput -> [EchidnaTest] -> World -> IO Env -mkEnv cfg buildOutput tests world = do +mkEnv :: EConfig -> BuildOutput -> [EchidnaTest] -> World -> Maybe SlitherInfo -> IO Env +mkEnv cfg buildOutput tests world slitherInfo = do codehashMap <- newIORef mempty chainId <- maybe (pure Nothing) EVM.Fetch.fetchChainIdFrom cfg.rpcUrl eventQueue <- newChan @@ -128,4 +128,5 @@ mkEnv cfg buildOutput tests world = do let dapp = dappInfo "/" buildOutput pure $ Env { cfg, dapp, codehashMap, fetchContractCache, fetchSlotCache , chainId, eventQueue, coverageRef, corpusRef, testRefs, world + , slitherInfo } diff --git a/lib/Echidna/Output/Source.hs b/lib/Echidna/Output/Source.hs index c397a4707..6c491b91b 100644 --- a/lib/Echidna/Output/Source.hs +++ b/lib/Echidna/Output/Source.hs @@ -25,14 +25,14 @@ import System.Directory (createDirectoryIfMissing) import System.FilePath (()) import Text.Printf (printf) -import EVM.Dapp (srcMapCodePos) +import EVM.Dapp (srcMapCodePos, DappInfo(..)) import EVM.Solidity (SourceCache(..), SrcMap, SolcContract(..)) import Echidna.Types.Campaign (CampaignConf(..)) import Echidna.Types.Config (Env(..), EConfig(..)) import Echidna.Types.Coverage (OpIx, unpackTxResults, CoverageMap, CoverageFileType (..)) import Echidna.Types.Tx (TxResult(..)) -import Echidna.SourceAnalysis.Slither (AssertListingByContract, AssertLocation(..), assertLocationList) +import Echidna.SourceAnalysis.Slither (AssertLocation(..), assertLocationList, SlitherInfo(..)) saveCoverages :: Env @@ -194,13 +194,14 @@ buildRuntimeLinesMap sc contracts = -- | Check that all assertions were hit, and log a warning if they weren't checkAssertionsCoverage :: SourceCache - -> [SolcContract] - -> CoverageMap - -> AssertListingByContract + -> Env -> IO () -checkAssertionsCoverage sc cs covMap assertMap = do +checkAssertionsCoverage sc env = do + let + cs = Map.elems env.dapp.solcByName + asserts = maybe [] (concatMap assertLocationList . Map.elems . (.asserts)) env.slitherInfo + covMap <- readIORef env.coverageRef covLines <- srcMapCov sc covMap cs - let asserts = concatMap assertLocationList $ Map.elems assertMap mapM_ (checkAssertionReached covLines) asserts -- | Helper function for `checkAssertionsCoverage` which checks a single assertion diff --git a/lib/Echidna/Types/Config.hs b/lib/Echidna/Types/Config.hs index 62f4e7513..5026c62d3 100644 --- a/lib/Echidna/Types/Config.hs +++ b/lib/Echidna/Types/Config.hs @@ -12,6 +12,7 @@ import Data.Word (Word64) import EVM.Dapp (DappInfo) import EVM.Types (Addr, Contract, W256) +import Echidna.SourceAnalysis.Slither (SlitherInfo) import Echidna.SourceMapping (CodehashMap) import Echidna.Types.Campaign (CampaignConf, CampaignEvent) import Echidna.Types.Corpus (Corpus) @@ -73,6 +74,7 @@ data Env = Env , coverageRef :: IORef CoverageMap , corpusRef :: IORef Corpus + , slitherInfo :: Maybe SlitherInfo , codehashMap :: CodehashMap , fetchContractCache :: IORef (Map Addr (Maybe Contract)) , fetchSlotCache :: IORef (Map Addr (Map W256 (Maybe W256))) diff --git a/src/Main.hs b/src/Main.hs index 1750a420d..e6ea428da 100644 --- a/src/Main.hs +++ b/src/Main.hs @@ -62,7 +62,7 @@ main = withUtf8 $ withCP65001 $ do -- take the seed from config, otherwise generate a new one seed <- maybe (getRandomR (0, maxBound)) pure cfg.campaignConf.seed - (vm, env, dict, asserts) <- prepareContract cfg cliFilePath buildOutput cliSelectedContract seed + (vm, env, dict) <- prepareContract cfg cliFilePath buildOutput cliSelectedContract seed initialCorpus <- loadInitialCorpus env -- start ui and run tests @@ -70,9 +70,7 @@ main = withUtf8 $ withCP65001 $ do tests <- traverse readIORef env.testRefs - let contracts = Map.elems env.dapp.solcByName - coverage <- readIORef env.coverageRef - checkAssertionsCoverage buildOutput.sources contracts coverage asserts + checkAssertionsCoverage buildOutput.sources env Onchain.saveRpcCache env @@ -112,6 +110,7 @@ main = withUtf8 $ withCP65001 $ do Onchain.saveCoverageReport env runId -- save source coverage reports + let contracts = Map.elems env.dapp.solcByName saveCoverages env runId dir buildOutput.sources contracts if isSuccessful tests then exitSuccess else exitWith (ExitFailure 1) diff --git a/src/test/Common.hs b/src/test/Common.hs index 86eed2b5d..2eb400aaa 100644 --- a/src/test/Common.hs +++ b/src/test/Common.hs @@ -94,7 +94,7 @@ runContract f selectedContract cfg workerType = do seed <- maybe (getRandomR (0, maxBound)) pure cfg.campaignConf.seed buildOutput <- compileContracts cfg.solConf (f :| []) - (vm, env, dict, _) <- prepareContract cfg (f :| []) buildOutput selectedContract seed + (vm, env, dict) <- prepareContract cfg (f :| []) buildOutput selectedContract seed (_stopReason, finalState) <- flip runReaderT env $ runWorker workerType (pure ()) vm dict 0 [] cfg.campaignConf.testLimit selectedContract @@ -157,7 +157,7 @@ loadSolTests cfg buildOutput name = do world = World solConf.sender mempty Nothing [] eventMap mainContract <- selectMainContract solConf name contracts echidnaTests <- mkTests solConf mainContract - env <- mkEnv cfg buildOutput echidnaTests world + env <- mkEnv cfg buildOutput echidnaTests world Nothing vm <- loadSpecified env mainContract contracts pure (vm, env, echidnaTests)