Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Don't add reverts to corpus #1311

Closed
wants to merge 1 commit into from
Closed
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
27 changes: 23 additions & 4 deletions lib/Echidna/Campaign.hs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import Control.Monad.State.Strict
import Control.Monad.ST (RealWorld)
import Control.Monad.Trans (lift)
import Data.Binary.Get (runGetOrFail)
import Data.ByteString qualified as BS
import Data.ByteString.Lazy qualified as LBS
import Data.IORef (readIORef, atomicModifyIORef', writeIORef)
import Data.Foldable (foldlM)
Expand Down Expand Up @@ -345,12 +346,13 @@ callseq vm txSeq = do
-- If there is new coverage, add the transaction list to the corpus
newCoverage <- gets (.newCoverage)
when newCoverage $ do
isDappTest <- getIsDappTest
ncallseqs <- gets (.ncallseqs)
-- Even if this takes a bit of time, this is okay as finding new coverage
-- is expected to be infrequent in the long term
newSize <- liftIO $ atomicModifyIORef' env.corpusRef $ \corp ->
-- Corpus is a bit too lazy, force the evaluation to reduce the memory usage
let !corp' = force $ addToCorpus (ncallseqs + 1) results corp
let !corp' = force $ addToCorpus isDappTest (ncallseqs + 1) results corp
in (corp', corpusSize corp')

cov <- liftIO . readIORef =<< asks (.coverageRef)
Expand Down Expand Up @@ -418,11 +420,28 @@ callseq vm txSeq = do
_ -> Nothing
_ -> Nothing

-- | Check whether any current tests are dapp tests
getIsDappTest
:: (MonadIO m, MonadReader Env m)
=> m Bool
getIsDappTest =
let
isDappTest (AssertionTest dt _ _) = dt
isDappTest _ = False
in any (isDappTest . (.testType)) <$> (mapM (liftIO . readIORef) =<< asks (.testRefs))

-- | Add transactions to the corpus discarding reverted ones
addToCorpus :: Int -> [(Tx, (VMResult Concrete RealWorld, Gas))] -> Corpus -> Corpus
addToCorpus n res corpus =
addToCorpus :: Bool -> Int -> [(Tx, (VMResult Concrete RealWorld, Gas))] -> Corpus -> Corpus
addToCorpus isDappTest n res corpus =
if null rtxs then corpus else Set.insert (n, rtxs) corpus
where rtxs = fst <$> res
where
rtxs = fst <$> filter (not . isRevert . fst . snd) res
-- We want to filter out reverts, but not real assertion failures.
-- Reverts can be assertion failures if isDappTest is True.
-- The assumeMagicReturnCode logic is copied from checkDapptestAssertion (TODO refactor?)
isRevert (VMFailure (Revert (ConcreteBuf bs))) | isDappTest = BS.isSuffixOf assumeMagicReturnCode bs
isRevert (VMFailure (Revert _)) = True
isRevert _ = False

-- | Execute a transaction, capturing the PC and codehash of each instruction
-- executed, saving the transaction if it finds new coverage.
Expand Down