Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions lib/Echidna/Types/Agent.hs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,27 @@ data Agent
, stateRef :: IORef WorkerState
}

-- | Construct a fuzzing agent with an explicit state publication reference.
--
-- Keeping the reference as an argument lets timeout-triggered auxiliary passes
-- use a throwaway reference instead of overwriting the reporting state.
mkFuzzerAgent
:: VM Concrete
-> GenDict
-> Int
-> IORef WorkerState
-> [(FilePath, [Tx])]
-> Int
-> Agent
mkFuzzerAgent vm dict workerId stateRef initialCorpus testLimit =
FuzzerAgent { fuzzerId = workerId
, initialVm = vm
, initialDict = dict
, initialCorpus
, testLimit
, stateRef
}

-- | The worker id this agent runs as. There is at most one symbolic worker and
-- it is always worker 0.
workerIdOf :: Agent -> WorkerId
Expand Down
18 changes: 6 additions & 12 deletions lib/Echidna/UI.hs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ import Echidna.Output.Corpus (saveCorpusEvent)
import Echidna.Output.JSON qualified
import Echidna.Server (runSSEServer)
import Echidna.SourceAnalysis.Slither (isEmptySlitherInfo)
import Echidna.Types.Agent (Agent(..), workerTypeOf)
import Echidna.Types.Agent (Agent(..), mkFuzzerAgent, workerTypeOf)
import Echidna.Types.Campaign
import Echidna.Types.Config
import Echidna.Types.Corpus qualified as Corpus
Expand Down Expand Up @@ -249,17 +249,10 @@ ui vm dict initialCorpus cliSelectedContract = do
spawnWorker env testLimit corpusChunk workerId = do
stateRef <- newIORef initialWorkerState

let fuzzerAgent corpus limit =
FuzzerAgent { fuzzerId = workerId
, initialVm = vm
, initialDict = dict
, initialCorpus = corpus
, testLimit = limit
, stateRef
}
let fuzzerAgent = mkFuzzerAgent vm dict workerId

agent = case workerIDToType env.cfg.campaignConf workerId of
FuzzWorker -> fuzzerAgent corpusChunk testLimit
FuzzWorker -> fuzzerAgent stateRef corpusChunk testLimit
SymbolicWorker ->
SymbolicAgent { initialVm = vm
, initialDict = dict
Expand All @@ -286,8 +279,9 @@ ui vm dict initialCorpus cliSelectedContract = do
case stopReason of
TimeLimitReached | workerType == FuzzWorker -> do
tests <- traverse readIORef env.testRefs
when (any needsShrinking tests) $ void $
runAgent (fuzzerAgent [] 0) env
when (any needsShrinking tests) $ do
shrinkStateRef <- newIORef initialWorkerState
void $ runAgent (fuzzerAgent shrinkStateRef [] 0) env
_ -> pure ()

time <- liftIO getTimestamp
Expand Down
4 changes: 3 additions & 1 deletion src/test/Spec.hs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import System.Directory (withCurrentDirectory)
import Test.Tasty (defaultMain, testGroup)
import Tests.ABIv2 (abiv2Tests)
import Tests.Agent (agentTests)
import Tests.Assertion (assertionTests)
import Tests.Cheat (cheatTests)
import Tests.Compile (compilationTests)
Expand All @@ -20,7 +21,8 @@ import Tests.Values (valuesTests)
main :: IO ()
main = withCurrentDirectory "./tests/solidity" . defaultMain $
testGroup "Echidna"
[ configTests
[ agentTests
, configTests
, compilationTests
, seedTests
, integrationTests
Expand Down
17 changes: 17 additions & 0 deletions src/test/Tests/Agent.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
module Tests.Agent (agentTests) where

import Data.IORef (newIORef)
import Test.Tasty (TestTree, testGroup)
import Test.Tasty.HUnit (assertBool, testCase)

import Echidna.Types.Agent (mkFuzzerAgent, stateRefOf)
import Echidna.Types.Campaign (initialWorkerState)

agentTests :: TestTree
agentTests = testGroup "Agent tests"
[ testCase "fuzzer agent uses the supplied state reference" $ do
stateRef <- newIORef initialWorkerState
let agent = mkFuzzerAgent undefined undefined 0 stateRef [] 0
assertBool "agent must publish through the supplied reference" $
stateRefOf agent == stateRef
]