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

fix issue where libraries would get loaded at extreme timestamps and block numbers, also switch to the new hevm stripBytecodeMetadata #510

Merged
merged 3 commits into from
Sep 24, 2020
Merged
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
15 changes: 10 additions & 5 deletions examples/solidity/basic/library.sol
Original file line number Diff line number Diff line change
@@ -1,23 +1,28 @@
library Test{
library Test {
struct Storage{
bool flag;
}

function set(Storage storage st) public{
function set(Storage storage st) public{
st.flag = true;
}

}

contract Contract{
contract Contract {
using Test for Test.Storage;
Test.Storage st;

function set() public{
function set() public{
st.set();
}

function echidna_library_call() external view returns (bool) {
function echidna_library_call() external view returns (bool) {
return (!st.flag);
}

function echidna_valid_timestamp() external view returns (bool) {
require(block.timestamp >= 1524785992 && block.number >= 4370000);
return (block.timestamp <= 1524785992 + 100 weeks && block.number < 4370000 + 10000000);
}
}
16 changes: 0 additions & 16 deletions lib/Echidna/ABI.hs
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,14 @@

module Echidna.ABI where

import Codec.CBOR.Read (deserialiseFromBytes)
import Codec.CBOR.Term (decodeTerm)
import Control.Lens
import Control.Monad (join, liftM2, liftM3, foldM, replicateM)
import Control.Monad.Catch (MonadThrow(..))
import Control.Monad.State.Class (MonadState, gets)
import Control.Monad.State (evalStateT)
import Control.Monad.Random.Strict (MonadRandom, getRandom, getRandoms, getRandomR, uniformMay)
import Data.Binary.Get (runGet, getWord16be)
import Data.Bool (bool)
import Data.ByteString (ByteString)
import Data.ByteString.Lazy (fromStrict)
import Data.Either (isRight)
import Data.Foldable (toList)
import Data.Has (Has(..))
import Data.Hashable (Hashable(..))
Expand Down Expand Up @@ -308,14 +303,3 @@ genAbiCallM abi = genWithDict (fmap toList . view wholeCalls) (traverse $ traver
genInteractionsM :: (MonadState x m, Has GenDict x, MonadRandom m, MonadThrow m)
=> NE.NonEmpty SolSignature -> m SolCall
genInteractionsM l = genAbiCallM =<< rElem l

-- | Given a solc bytecode strip off the metadata from the end
stripBytecodeMetadata :: ByteString -> ByteString
stripBytecodeMetadata bc
| BS.length cl /= 2 = bc
| BS.length h >= cl' && (isRight . deserialiseFromBytes decodeTerm $ fromStrict cbor) = bc'
| otherwise = bc
where l = BS.length bc
(h, cl) = BS.splitAt (l - 2) bc
cl' = fromIntegral . runGet getWord16be . fromStrict $ cl
(bc', cbor) = BS.splitAt (BS.length h - cl') h
13 changes: 9 additions & 4 deletions lib/Echidna/Exec.hs
Original file line number Diff line number Diff line change
Expand Up @@ -11,20 +11,20 @@ import Control.Lens
import Control.Monad.Catch (Exception, MonadThrow(..))
import Control.Monad.State.Strict (MonadState, execState)
import Data.Has (Has(..))
import Data.Map.Strict (Map)
import Data.Map.Strict (Map, fromList)
import Data.Maybe (fromMaybe)
import Data.Set (Set)
import EVM
import EVM.Op (Op(..))
import EVM.Exec (exec)
import EVM.Exec (exec, vmForEthrunCreation)
import EVM.Solidity (stripBytecodeMetadata)

import qualified Data.ByteString as BS
import qualified Data.Map as M
import qualified Data.Set as S

import Echidna.ABI (stripBytecodeMetadata)
import Echidna.Transaction
import Echidna.Types.Tx (TxCall(..), Tx, TxResult(..), call, dst)
import Echidna.Types.Tx (TxCall(..), Tx, TxResult(..), call, dst, initialTimestamp, initialBlockNumber)

-- | Broad categories of execution failures: reversions, illegal operations, and ???.
data ErrorClass = RevertE | IllegalE | UnknownE
Expand Down Expand Up @@ -123,3 +123,8 @@ traceCoverage = do
v <- use hasLens
let c = v ^. state . code
hasLens <>= [readOp (BS.index c $ v ^. state . pc) c]

initialVM :: VM
initialVM = vmForEthrunCreation mempty & block . timestamp .~ initialTimestamp
& block . number .~ initialBlockNumber
& env . contracts .~ fromList [] -- fixes weird nonce issues
10 changes: 4 additions & 6 deletions lib/Echidna/RPC.hs
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,14 @@ import Control.Monad.Reader.Class (MonadReader(..))
import Control.Monad.State.Strict (MonadState, execStateT, runStateT, get, put)
import Data.Aeson (FromJSON(..), (.:), withObject, eitherDecodeFileStrict)
import Data.Binary.Get (runGetOrFail)
import Data.ByteString.Char8 (ByteString, empty)
import Data.ByteString.Char8 (ByteString)
import Data.Has (Has(..))
import Data.Map (fromList)
import Data.Maybe (maybe)
import Data.Text.Encoding (encodeUtf8)
import EVM
import EVM.ABI (AbiType(..), getAbi)
import EVM.Concrete (w256)
import EVM.Exec (exec, vmForEthrunCreation)
import EVM.Exec (exec)
import EVM.Types (Addr, W256)
import Text.Read (readMaybe)

Expand Down Expand Up @@ -88,10 +87,9 @@ loadEthenoBatch ts fp = do
(Left e) -> throwM $ EthenoException e
(Right (ethenoInit :: [Etheno])) -> do
-- Execute contract creations and initial transactions,
let blank = vmForEthrunCreation empty & env . contracts .~ fromList []
initVM = foldM (execEthenoTxs ts) Nothing ethenoInit
let initVM = foldM (execEthenoTxs ts) Nothing ethenoInit

(addr, vm') <- runStateT initVM blank
(addr, vm') <- runStateT initVM initialVM
case addr of
Nothing -> throwM $ EthenoException "Could not find a contract with echidna tests"
Just a -> execStateT (liftSH . loadContract $ a) vm'
Expand Down
17 changes: 9 additions & 8 deletions lib/Echidna/Solidity.hs
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ import System.Process (StdStream(..), readCreateProcessWithExitCode,
import System.IO (openFile, IOMode(..))
import System.Exit (ExitCode(..))
import System.Directory (findExecutable)
import Echidna.ABI (encodeSig, hashSig, stripBytecodeMetadata, fallback)
import Echidna.Exec (execTx)
import Echidna.ABI (encodeSig, hashSig, fallback)
import Echidna.Exec (execTx, initialVM)
import Echidna.RPC (loadEthenoBatch)
import Echidna.Types.Signature (FunctionHash, SolSignature, SignatureMap)
import Echidna.Types.Tx (TxConf, TxCall(..), Tx(..), initialTimestamp, initialBlockNumber)
Expand All @@ -43,8 +43,7 @@ import Echidna.Processor
import EVM hiding (contracts)
import qualified EVM (contracts)
import EVM.ABI
import EVM.Exec (vmForEthrunCreation)
import EVM.Solidity hiding (stripBytecodeMetadata)
import EVM.Solidity
import EVM.Types (Addr)
import EVM.Concrete (w256)

Expand Down Expand Up @@ -163,7 +162,7 @@ loadLibraries :: (MonadIO m, MonadThrow m, MonadReader x m, Has SolConf x)
=> [SolcContract] -> Addr -> Addr -> VM -> m VM
loadLibraries [] _ _ vm = return vm
loadLibraries (l:ls) la d vm = loadLibraries ls (la + 1) d =<< loadRest
where loadRest = execStateT (execTx $ Tx (SolCreate $ l ^. creationCode) d la 8000030 0 0 (initialTimestamp, initialBlockNumber)) vm
where loadRest = execStateT (execTx $ Tx (SolCreate $ l ^. creationCode) d la 8000030 0 0 (0, 0)) vm

-- | Generate a string to use as argument in solc to link libraries starting from addrLibrary
linkLibraries :: [String] -> String
Expand Down Expand Up @@ -200,7 +199,7 @@ loadSpecified name cs = do
unless q . putStrLn $ "Analyzing contract: " <> c ^. contractName . unpacked

-- Local variables
(SolConf ca d ads bala balc pref _ _ libs _ fp ma ch bm fs) <- view hasLens
SolConf ca d ads bala balc pref _ _ libs _ fp ma ch bm fs <- view hasLens

-- generate the complete abi mapping
let bc = c ^. creationCode
Expand All @@ -219,7 +218,9 @@ loadSpecified name cs = do

-- Set up initial VM, either with chosen contract or Etheno initialization file
-- need to use snd to add to ABI dict
blank' <- maybe (pure (vmForEthrunCreation bc)) (loadEthenoBatch (fst <$> tests)) fp
blank' <- maybe (pure initialVM)
(loadEthenoBatch $ fst <$> tests)
fp
let blank = populateAddresses (NE.toList ads |> d) bala blank'
& env . EVM.contracts %~ sans 0x3be95e4159a131e56a84657c4ad4d43ec7cd865d -- fixes weird nonce issues

Expand All @@ -235,7 +236,7 @@ loadSpecified name cs = do
Just (t,_) -> throwM $ TestArgsFound t -- Test args check
Nothing -> do
vm <- loadLibraries ls addrLibrary d blank
let transaction = unless (isJust fp) $ void . execTx $ Tx (SolCreate bc) d ca 8000030 0 (w256 $ fromInteger balc) (initialTimestamp, initialBlockNumber)
let transaction = unless (isJust fp) $ void . execTx $ Tx (SolCreate bc) d ca 8000030 0 (w256 $ fromInteger balc) (0, 0)
vm' <- execStateT transaction vm
case currentContract vm' of
Just _ -> return (vm', neFuns, fst <$> tests, abiMapping)
Expand Down
1 change: 1 addition & 0 deletions lib/Echidna/Transaction.hs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import Data.Maybe (catMaybes)
import EVM hiding (value)
import EVM.ABI (abiCalldata, abiValueType)
import EVM.Concrete (Word(..), w256)
import EVM.Solidity (stripBytecodeMetadata)
import EVM.Types (Addr)

import qualified System.Directory as SD
Expand Down
1 change: 0 additions & 1 deletion package.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ dependencies:
- brick <= 0.46
- base16-bytestring
- bytestring
- cborg
- containers
- data-dword
- data-has
Expand Down
2 changes: 2 additions & 0 deletions src/test/Tests/Integration.hs
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,8 @@ integrationTests = testGroup "Solidity Integration Testing"
[ ("echidna_balance failed", passed "echidna_balance") ]
, testContract "basic/library.sol" (Just "basic/library.yaml")
[ ("echidna_library_call failed", solved "echidna_library_call") ]
, testContract "basic/library.sol" (Just "basic/library.yaml")
[ ("echidna_valid_timestamp failed", passed "echidna_valid_timestamp") ]
, testContract "basic/fallback.sol" Nothing
[ ("echidna_fallback failed", solved "echidna_fallback") ]
, testContract "basic/darray.sol" Nothing
Expand Down