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

Wrap fetch exceptions #971

Merged
merged 1 commit into from Mar 7, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
19 changes: 16 additions & 3 deletions lib/Echidna/Exec.hs
Expand Up @@ -6,7 +6,7 @@ module Echidna.Exec where

import Control.Lens
import Control.Monad (when)
import Control.Monad.Catch (MonadThrow(..))
import Control.Monad.Catch (MonadThrow(..), catchAll, SomeException)
import Control.Monad.State.Strict (MonadState(get, put), execState, runStateT, MonadIO(liftIO))
import Control.Monad.Reader (MonadReader, asks)
import Data.IORef (readIORef, atomicWriteIORef)
Expand Down Expand Up @@ -111,7 +111,7 @@ execTxWith l onErr executeTx tx = do
getRpcUrl >>= \case
Just rpcUrl -> do
rpcBlock <- getRpcBlock
ret <- liftIO $ EVM.Fetch.fetchContractFrom rpcBlock rpcUrl addr
ret <- liftIO $ safeFetchContractFrom rpcBlock rpcUrl addr
case ret of
-- TODO: fix hevm to not return an empty contract in case of an error
Just contract | contract._contractcode /= EVM.RuntimeCode (EVM.ConcreteRuntimeCode "") -> do
Expand Down Expand Up @@ -153,7 +153,7 @@ execTxWith l onErr executeTx tx = do
getRpcUrl >>= \case
Just rpcUrl -> do
rpcBlock <- getRpcBlock
ret <- liftIO $ EVM.Fetch.fetchSlotFrom rpcBlock rpcUrl addr slot
ret <- liftIO $ safeFetchSlotFrom rpcBlock rpcUrl addr slot
case ret of
Just value -> do
l %= execState (continuation value)
Expand Down Expand Up @@ -188,12 +188,25 @@ execTxWith l onErr executeTx tx = do
getRpcUrl = liftIO $ do
val <- lookupEnv "ECHIDNA_RPC_URL"
pure (Text.pack <$> val)

getRpcBlock = liftIO $ do
-- TODO: Is the latest block a good default? It makes fuzzing hard to
-- reproduce. Rethink this.
val <- lookupEnv "ECHIDNA_RPC_BLOCK"
pure $ maybe EVM.Fetch.Latest EVM.Fetch.BlockNumber (val >>= readMaybe)

-- TODO: temporary solution, handle errors gracefully
safeFetchContractFrom rpcBlock rpcUrl addr =
catchAll
(EVM.Fetch.fetchContractFrom rpcBlock rpcUrl addr)
(\(_e :: SomeException) -> pure $ Just emptyAccount)

-- TODO: temporary solution, handle errors gracefully
safeFetchSlotFrom rpcBlock rpcUrl addr slot =
catchAll
(EVM.Fetch.fetchSlotFrom rpcBlock rpcUrl addr slot)
(\(_e :: SomeException) -> pure $ Just 0)

-- | Handles reverts, failures and contract creations that might be the result
-- (`vmResult`) of executing transaction `tx`.
handleErrorsAndConstruction vmResult vmBeforeTx = case (vmResult, tx.call) of
Expand Down