Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/master' into dev-cov-exec-counts-2
Browse files Browse the repository at this point in the history
  • Loading branch information
elopez committed Aug 2, 2024
2 parents 989c708 + 182580e commit cde4695
Show file tree
Hide file tree
Showing 29 changed files with 218 additions and 165 deletions.
8 changes: 4 additions & 4 deletions .github/container-linux-static/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM alpine:3.18.4
FROM alpine:3.18.6
# Based on https://github.com/fpco/alpine-haskell-stack/blob/9.2.8v2/ghc-Dockerfile

RUN apk upgrade --no-cache &&\
Expand Down Expand Up @@ -36,12 +36,12 @@ RUN ln -s /usr/lib/libncurses.a /usr/lib/libtinfo.a
COPY stack-config.yaml /root/.stack/config.yaml

RUN cd /tmp && \
curl -sSLo /tmp/ghc.tar.xz https://downloads.haskell.org/~ghc/9.4.7/ghc-9.4.7-x86_64-alpine3_12-linux.tar.xz && \
curl -sSLo /tmp/ghc.tar.xz https://downloads.haskell.org/~ghc/9.6.5/ghc-9.6.5-x86_64-alpine3_12-linux.tar.xz && \
tar xf ghc.tar.xz && \
cd ghc-9.4.7-x86_64-unknown-linux && \
cd ghc-9.6.5-x86_64-unknown-linux && \
./configure --prefix=/usr/local && \
make install && \
rm -rf /tmp/ghc.tar.xz /tmp/ghc-9.4.7-x86_64-unknown-linux
rm -rf /tmp/ghc.tar.xz /tmp/ghc-9.6.5-x86_64-unknown-linux

RUN apk upgrade --no-cache &&\
apk add --no-cache \
Expand Down
2 changes: 1 addition & 1 deletion .github/container-linux-static/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@ This container is used as part of `.github/workflows/ci.yml` to produce
statically-linked amd64 linux builds of Echidna. It is based on the following
container produced by FP Complete and maintained in the
[`fpco/alpine-haskell-stack`](https://github.com/fpco/alpine-haskell-stack/tree/ghc927)
repository, and contains a few extra dependencies and configuration to make it
repository, and contains a few extra dependencies and configurations to make it
suitable for the GitHub Actions environment.
5 changes: 5 additions & 0 deletions .github/container-linux-static/stack-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
extra-include-dirs:
- /usr/include
extra-lib-dirs:
- /lib
- /usr/lib
6 changes: 3 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ on:

env:
# Tag for cache invalidation
CACHE_VERSION: v6
CACHE_VERSION: v7

jobs:
build:
Expand All @@ -22,7 +22,7 @@ jobs:
include:
- os: ubuntu-20.04
shell: bash
container: "{\"image\": \"elopeztob/alpine-haskell-stack-echidna:ghc-9.4.7\", \"options\": \"--user 1001\"}"
container: "{\"image\": \"elopeztob/alpine-haskell-stack-echidna:ghc-9.6.5\", \"options\": \"--user 1001\"}"
- os: macos-13 # x86_64 macOS
shell: bash
- os: windows-latest
Expand Down Expand Up @@ -65,7 +65,7 @@ jobs:
id: stack
if: matrix.container == ''
with:
ghc-version: '9.4'
ghc-version: '9.6'
enable-stack: true
stack-version: 'latest'

Expand Down
8 changes: 4 additions & 4 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ jobs:
uses: actions/checkout@v4

- name: Install Nix
uses: DeterminateSystems/nix-installer-action@v12
uses: DeterminateSystems/nix-installer-action@v13

- name: Configure Cachix
uses: cachix/cachix-action@v15
Expand Down Expand Up @@ -96,15 +96,15 @@ jobs:
merge-multiple: true

- name: Sign binaries
uses: sigstore/gh-action-sigstore-python@v2.1.1
uses: sigstore/gh-action-sigstore-python@v3.0.0
with:
inputs: ./echidna-*.tar.gz

- name: Create GitHub release and upload binaries
uses: softprops/[email protected].6
uses: softprops/[email protected].8
with:
draft: true
name: "Echidna ${{ needs.nixBuild.outputs.version }}"
files: |
./echidna-*.tar.gz
./echidna-*.tar.gz.sigstore
./echidna-*.tar.gz.sigstore.json
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,14 @@
## 2.2.4

* Initial TLOAD/TSTORE support (#1286)
* Initial symbolic execution implementation (experimental, #1216, #1251, #1285)
* New panel toggles in the UI (#1197)
* New gas/s metric (#1279)
* Improved logging (#1202, #1271, #1273, #1274, #1283, #1258, #1269)
* Performance improvements with multiple workers (#1228)
* Shrinking improvements (#1196, #1250, #1280)
* Improved configuration options (#1200, #1227, #1251)

## 2.2.3

* feat: add CLI commands for RPC URL and block number (#1194)
Expand Down
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ appreciate all contributions, including bug reports, feature suggestions,
tutorials/blog posts, and code improvements.

If you're unsure where to start, we recommend to join our [chat room](https://slack.empirehacking.nyc/)
(in the #ethereum channel) to discuss new ideas to improve this tool. You can also take a look to the [`help wanted`](https://github.com/crytic/echidna/issues?q=is%3Aissue+is%3Aopen+label%3A%22help+wanted%22)
(in the #ethereum channel) to discuss new ideas to improve this tool. You can also take a look at the [`help wanted`](https://github.com/crytic/echidna/issues?q=is%3Aissue+is%3Aopen+label%3A%22help+wanted%22)
issue labels.

## Bug reports and feature suggestions
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ Common causes for performance issues that we observed:
- Lazy data constructors that accumulate thunks
- Inefficient data structures used in hot paths

Checking for these is a good place to start. If you suspect some comuptation is too lazy and
Checking for these is a good place to start. If you suspect some computation is too lazy and
leaks memory, you can use `force` from `Control.DeepSeq` to make sure it gets evaluated.

## Limitations and known issues
Expand Down
6 changes: 3 additions & 3 deletions flake.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

70 changes: 50 additions & 20 deletions flake.nix
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
pkgs = nixpkgs.legacyPackages.${system};
# prefer musl on Linux, static glibc + threading does not work properly
# TODO: maybe only override it for echidna-redistributable?
pkgsStatic = if pkgs.stdenv.hostPlatform.isLinux then pkgs.pkgsMusl else pkgs;
pkgsStatic = if pkgs.stdenv.hostPlatform.isLinux then pkgs.pkgsStatic else pkgs;
# this is not perfect for development as it hardcodes solc to 0.5.7, test suite runs fine though
# would be great to integrate solc-select to be more flexible, improve this in future
solc = pkgs.stdenv.mkDerivation {
Expand Down Expand Up @@ -47,39 +47,61 @@

ncurses-static = pkgsStatic.ncurses.override { enableStatic = true; };

hevm = pkgs: pkgs.haskell.lib.dontCheck (
pkgs.haskellPackages.callCabal2nix "hevm" (pkgs.fetchFromGitHub {
hsPkgs = ps :
ps.haskellPackages.override {
overrides = hfinal: hprev: {
with-utf8 =
if (with ps.stdenv; hostPlatform.isDarwin && hostPlatform.isx86)
then ps.haskell.lib.compose.overrideCabal (_ : { extraLibraries = [ps.libiconv]; }) hprev.with-utf8
else hprev.with-utf8;
};
};

cc-workaround-nix-23138 =
pkgs.writeScriptBin "cc-workaround-nix-23138" ''
if [ "$1" = "--print-file-name" ] && [ "$2" = "c++" ]; then
echo c++
else
exec cc "$@"
fi
'';

hevm = pkgs: pkgs.lib.pipe ((hsPkgs pkgs).callCabal2nix "hevm" (pkgs.fetchFromGitHub {
owner = "trail-of-forks";
repo = "hevm";
rev = "2aa7b3e5fea0e0657fe44549ccefbb18f61eb024";
sha256 = "sha256-/9NMvSOzP0agJ1qEFDN/OQvV0DXRTN3AbntTAzPXbCw=";
}) { secp256k1 = pkgs.secp256k1; });
rev = "3aba82f06a2d1e0a4a4c26458f747a46dad0e7e2";
sha256 = "sha256-NXXhEqHTQEL2N9RhXa1eczIsQtIM3mvPfyWXlBXpxK4=";
}) { secp256k1 = pkgs.secp256k1; })
([
pkgs.haskell.lib.compose.dontCheck
] ++ pkgs.lib.optionals pkgs.stdenv.isDarwin [
(pkgs.haskell.lib.compose.appendConfigureFlag "--ghc-options=-pgml=${cc-workaround-nix-23138}/bin/cc-workaround-nix-23138")
]);

# FIXME: figure out solc situation, it conflicts with the one from
# solc-select that is installed with slither, disable tests in the meantime
echidna = pkgs: pkgs.haskell.lib.dontCheck (
with pkgs; lib.pipe
(haskellPackages.callCabal2nix "echidna" ./. { hevm = hevm pkgs; })
[
echidna = pkgs: with pkgs; lib.pipe
((hsPkgs pkgs).callCabal2nix "echidna" ./. { hevm = hevm pkgs; })
([
# FIXME: figure out solc situation, it conflicts with the one from
# solc-select that is installed with slither, disable tests in the meantime
haskell.lib.compose.dontCheck
(haskell.lib.compose.addTestToolDepends [ haskellPackages.hpack slither-analyzer solc ])
(haskell.lib.compose.disableCabalFlag "static")
] ++ pkgs.lib.optionals pkgs.stdenv.isDarwin [
(pkgs.haskell.lib.compose.appendConfigureFlag "--ghc-options=-pgml=${cc-workaround-nix-23138}/bin/cc-workaround-nix-23138")
]);

echidna-static = with pkgsStatic; lib.pipe
(echidna pkgsStatic)
[
(haskell.lib.compose.appendConfigureFlags
([
[
"--extra-lib-dirs=${stripDylib (gmp.override { withStatic = true; })}/lib"
"--extra-lib-dirs=${stripDylib secp256k1-static}/lib"
"--extra-lib-dirs=${stripDylib (libff.override { enableStatic = true; })}/lib"
"--extra-lib-dirs=${zlib.static}/lib"
"--extra-lib-dirs=${zlib.override { static = true; shared = false; }}/lib"
"--extra-lib-dirs=${stripDylib (libffi.overrideAttrs (_: { dontDisableStatic = true; }))}/lib"
"--extra-lib-dirs=${stripDylib (ncurses-static)}/lib"
] ++ (if stdenv.hostPlatform.isDarwin then [
"--extra-lib-dirs=${stripDylib (libiconv.override { enableStatic = true; })}/lib"
"--extra-lib-dirs=${stripDylib (libcxxabi)}/lib"
] else [])))
])
(haskell.lib.compose.enableCabalFlag "static")
];

Expand Down Expand Up @@ -108,10 +130,14 @@
# get the list of dynamic libs from otool and tidy the output
libs=$(${otool} -L $out/bin/echidna | tail -n +2 | sed 's/^[[:space:]]*//' | cut -d' ' -f1)
# get the path for libcxx
cxx=$(echo "$libs" | ${grep} '^/nix/store/.*-libcxx-')
cxx=$(echo "$libs" | ${grep} '^/nix/store/.*/libc++\.')
cxxabi=$(echo "$libs" | ${grep} '^/nix/store/.*/libc++abi\.')
iconv=$(echo "$libs" | ${grep} '^/nix/store/.*/libiconv\.')
# rewrite /nix/... library paths to point to /usr/lib
chmod 777 $out/bin/echidna
${install_name_tool} -change "$cxx" /usr/lib/libc++.1.dylib $out/bin/echidna
${install_name_tool} -change "$cxxabi" /usr/lib/libc++abi.dylib $out/bin/echidna
${install_name_tool} -change "$iconv" /usr/lib/libiconv.dylib $out/bin/echidna
# fix TERMINFO path in ncurses
${perl} -i -pe 's#(${ncurses-static}/share/terminfo)#"/usr/share/terminfo" . "\x0" x (length($1) - 19)#e' $out/bin/echidna
# check that no nix deps remain
Expand Down Expand Up @@ -145,7 +171,11 @@
devShell = with pkgs;
haskellPackages.shellFor {
packages = _: [ (echidna pkgs) ];
shellHook = "hpack";
shellHook = ''
hpack
'' + (if pkgs.stdenv.isDarwin then ''
cabal configure --ghc-options=-pgml=${cc-workaround-nix-23138}/bin/cc-workaround-nix-23138
'' else "");
buildInputs = [
solc
slither-analyzer
Expand Down
2 changes: 1 addition & 1 deletion lib/Echidna/ABI.hs
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ addChars c b = foldM withR b . enumFromTo 0 =<< rand where
addNulls :: MonadRandom m => ByteString -> m ByteString
addNulls = addChars $ pure 0

-- | Given a \"list-y\" structure with analogues of 'take', 'drop', and 'length',
-- | Given a \"list-y\" structure with analogs of 'take', 'drop', and 'length',
-- remove some elements at random.
shrinkWith
:: MonadRandom m
Expand Down
2 changes: 1 addition & 1 deletion lib/Echidna/Campaign.hs
Original file line number Diff line number Diff line change
Expand Up @@ -397,7 +397,7 @@ callseq vm txSeq = do

where
-- Given a list of transactions and a return typing rule, checks whether we
-- know the return type for each function called. If yes, tries to parse the
-- know the return type for each function called. If yes, try to parse the
-- return value as a value of that type. Returns a 'GenDict' style Map.
returnValues
:: [(Tx, VMResult Concrete RealWorld)]
Expand Down
7 changes: 4 additions & 3 deletions lib/Echidna/Exec.hs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import Data.Vector qualified as V
import Data.Vector.Unboxed.Mutable qualified as VMut
import System.Process (readProcessWithExitCode)

import EVM (bytecode, replaceCodeOfSelf, loadContract, exec1, vmOpIx)
import EVM (bytecode, replaceCodeOfSelf, loadContract, exec1, vmOpIx, clearTStorages)
import EVM.ABI
import EVM.Dapp (DappInfo)
import EVM.Exec (exec, vmForEthrunCreation)
Expand Down Expand Up @@ -55,7 +55,7 @@ classifyError = \case
StackLimitExceeded -> RevertE
StackUnderrun -> IllegalE
BadJumpDestination -> IllegalE
IllegalOverflow -> IllegalE
IllegalOverflow -> RevertE
_ -> UnknownE

-- | Extracts the 'Query' if there is one.
Expand Down Expand Up @@ -99,6 +99,7 @@ execTxWith executeTx tx = do
vmResult <- runFully
gasLeftAfterTx <- gets (.state.gas)
handleErrorsAndConstruction vmResult vmBeforeTx
fromEVM clearTStorages
pure (vmResult, gasLeftBeforeTx - gasLeftAfterTx)
where
runFully = do
Expand Down Expand Up @@ -132,7 +133,7 @@ execTxWith executeTx tx = do
fromEVM (continuation contract)
liftIO $ atomicWriteIORef cacheRef $ Map.insert addr (Just contract) cache
_ -> do
-- TODO: better error reporting in HEVM, when intermmittent
-- TODO: better error reporting in HEVM, when intermittent
-- network error then retry
liftIO $ atomicWriteIORef cacheRef $ Map.insert addr Nothing cache
logMsg $ "ERROR: Failed to fetch contract: " <> show q
Expand Down
2 changes: 1 addition & 1 deletion lib/Echidna/Mutator/Array.hs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ listMutators = fromList
-- | Mutate a list-like data structure using a list of mutators
mutateLL
:: (LL.ListLike f i, MonadRandom m)
-- | Required size for the mutated list-like value (or Nothing if there are no constrains)
-- | Required size for the mutated list-like value (or Nothing if there are no constraints)
=> Maybe Int
-- | Randomly generated list-like value to complement the mutated list, if it is
-- shorter than the requested size
Expand Down
2 changes: 1 addition & 1 deletion lib/Echidna/Onchain.hs
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ toFetchedContractData contract =
}

-- | Try to load the persisted RPC cache.
-- TODO: we use the corpus dir for now, think where to place it
-- TODO: we use the corpus dir for now, think about where to place it
loadRpcCache
:: EConfig
-> IO ( Map Addr (Maybe Contract)
Expand Down
2 changes: 1 addition & 1 deletion lib/Echidna/Output/Corpus.hs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ saveCorpusEvent env (_time, campaignEvent) = do

getEventInfo = \case
-- TODO: We save intermediate reproducers in separate directories.
-- This is to because there can be a lot of them and we want to skip
-- This is because there can be a lot of them and we want to skip
-- loading those on startup. Ideally, we should override the same file
-- with a better version of a reproducer, this is smaller or more optimized.
TestFalsified test -> Just ("reproducers-unshrunk", test.reproducer)
Expand Down
11 changes: 8 additions & 3 deletions lib/Echidna/Types/Campaign.hs
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@ module Echidna.Types.Campaign where
import Control.Concurrent (ThreadId)
import Data.Aeson
import Data.Map (Map)
import Data.Maybe (fromMaybe)
import Data.Text (Text)
import Data.Text qualified as T
import Data.Word (Word8, Word16)
import GHC.Conc (numCapabilities)

import Echidna.ABI (GenDict, emptyDict, encodeSig)
import Echidna.Types
Expand Down Expand Up @@ -211,9 +211,14 @@ defaultSymExecAskSMTIters :: Integer
defaultSymExecAskSMTIters = 1

-- | Get number of fuzzing workers (doesn't include sym exec worker)
-- Defaults to 1 if set to Nothing
-- Defaults to `N` if set to Nothing, where `N` is Haskell's -N value,
-- usually the number of cores, clamped between 1 and 4.
getNFuzzWorkers :: CampaignConf -> Int
getNFuzzWorkers conf = fromIntegral (fromMaybe 1 (conf.workers))
getNFuzzWorkers conf = maybe defaultN fromIntegral conf.workers
where
n = numCapabilities
maxN = max 1 n
defaultN = min 4 maxN -- capped at 4 by default

-- | Number of workers, including SymExec worker if there is one
getNWorkers :: CampaignConf -> Int
Expand Down
2 changes: 1 addition & 1 deletion lib/Echidna/Types/Coverage.hs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ type RevertQty = Word64

-- | Given good point coverage, count the number of unique points but
-- only considering the different instruction PCs (discarding the TxResult).
-- This is useful to report a coverage measure to the user
-- This is useful for reporting a coverage measure to the user
scoveragePoints :: CoverageMap -> IO Int
scoveragePoints cm = do
sum <$> mapM (V.foldl' countCovered 0) (Map.elems cm)
Expand Down
2 changes: 1 addition & 1 deletion lib/Echidna/Types/Solidity.hs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ instance Show SolException where
ConstructorArgs s -> "Constructor arguments are required: " ++ s
NoCryticCompile -> "crytic-compile not installed or not found in PATH. To install it, run:\n pip install crytic-compile"
InvalidMethodFilters f -> "Applying the filter " ++ show f ++ " to the methods produces an empty list. Are you filtering the correct functions using `filterFunctions` or fuzzing the correct contract?"
SetUpCallFailed -> "Calling the setUp() function failed (revert, out-of-gas, sending ether to an non-payable constructor, etc.)"
SetUpCallFailed -> "Calling the setUp() function failed (revert, out-of-gas, sending ether to a non-payable constructor, etc.)"
DeploymentFailed a t -> "Deploying the contract " ++ show a ++ " failed (revert, out-of-gas, sending ether to an non-payable constructor, etc.):\n" ++ unpack t
OutdatedSolcVersion v -> "Solc version " ++ toString v ++ " detected. Echidna doesn't support versions of solc before " ++ toString minSupportedSolcVersion ++ ". Please use a newer version."

Expand Down
2 changes: 1 addition & 1 deletion lib/Echidna/Types/Tx.hs
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,7 @@ catNoCalls (tx1:tx2:xs) =
_ -> tx1 : catNoCalls (tx2:xs)
where nc = tx1 { delay = (fst tx1.delay + fst tx2.delay, snd tx1.delay + snd tx2.delay) }

-- | Transform a VMResult into a more hash friendly sum type
-- | Transform a VMResult into a more hash-friendly sum type
getResult :: VMResult Concrete s -> TxResult
getResult = \case
VMSuccess b | forceBuf b == encodeAbiValue (AbiBool True) -> ReturnTrue
Expand Down
Loading

0 comments on commit cde4695

Please sign in to comment.