Skip to content

Commit

Permalink
Upgrade hevm to upstream main
Browse files Browse the repository at this point in the history
Commit 8eaf59c3753f50067551edd2b907acc5d528d115

Includes fixes and new cheatcodes.
  • Loading branch information
elopez committed Oct 1, 2024
1 parent b54afcd commit 31a177d
Show file tree
Hide file tree
Showing 7 changed files with 51 additions and 9 deletions.
4 changes: 2 additions & 2 deletions flake.nix
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,8 @@
hevm = pkgs: pkgs.lib.pipe ((hsPkgs pkgs).callCabal2nix "hevm" (pkgs.fetchFromGitHub {
owner = "ethereum";
repo = "hevm";
rev = "c779777d18c8ff60867f009d434b44ce08188e01";
sha256 = "sha256-JnJUZ9AxhxTP+TBMThksh0D4R6KFdzjgu1+fBeBERws=";
rev = "8eaf59c3753f50067551edd2b907acc5d528d115";
sha256 = "sha256-lyqNdZaxvRQSbExGoJkAiW5gjeBPrck7LcbIYl4Q3J4=";
}) { secp256k1 = pkgs.secp256k1; })
([
pkgs.haskell.lib.compose.dontCheck
Expand Down
15 changes: 12 additions & 3 deletions lib/Echidna/Exec.hs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ import Data.Maybe (fromMaybe, fromJust)
import Data.Text qualified as T
import Data.Vector qualified as V
import Data.Vector.Unboxed.Mutable qualified as VMut
import System.Process (readProcessWithExitCode)
import System.Environment (lookupEnv, getEnvironment)
import System.Process qualified as P

import EVM (bytecode, replaceCodeOfSelf, loadContract, exec1, vmOpIx, clearTStorages)
import EVM.ABI
Expand Down Expand Up @@ -178,13 +179,21 @@ execTxWith executeTx tx = do
runFully -- resume execution

-- Execute a FFI call
Just (PleaseDoFFI (cmd : args) continuation) -> do
(_, stdout, _) <- liftIO $ readProcessWithExitCode cmd args ""
Just (PleaseDoFFI (cmd : args) envs continuation) -> do
existingEnv <- liftIO getEnvironment
let mergedEnv = Map.toList $ Map.union envs $ Map.fromList existingEnv
let process = (P.proc cmd args) { P.env = Just mergedEnv }
(_, stdout, _) <- liftIO $ P.readCreateProcessWithExitCode process ""
let encodedResponse = encodeAbiValue $
AbiTuple (V.fromList [AbiBytesDynamic . hexText . T.pack $ stdout])
fromEVM (continuation encodedResponse)
runFully

Just (PleaseReadEnv var continuation) -> do
value <- liftIO $ lookupEnv var
fromEVM (continuation $ fromMaybe "" value)
runFully -- resume execution

-- No queries to answer, the tx is fully executed and the result is final
_ -> pure vmResult

Expand Down
4 changes: 2 additions & 2 deletions lib/Echidna/Test.hs
Original file line number Diff line number Diff line change
Expand Up @@ -271,12 +271,12 @@ checkAssertionEvent = any (T.isPrefixOf "AssertionFailed(")

checkSelfDestructedTarget :: Addr -> DappInfo -> VM Concrete RealWorld -> TestValue
checkSelfDestructedTarget addr _ vm =
let selfdestructs' = vm.tx.substate.selfdestructs
let selfdestructs' = vm.tx.subState.selfdestructs
in BoolValue $ LitAddr addr `notElem` selfdestructs'

checkAnySelfDestructed :: DappInfo -> VM Concrete RealWorld -> TestValue
checkAnySelfDestructed _ vm =
BoolValue $ null vm.tx.substate.selfdestructs
BoolValue $ null vm.tx.subState.selfdestructs

checkPanicEvent :: T.Text -> Events -> Bool
checkPanicEvent n = any (T.isPrefixOf ("Panic(" <> n <> ")"))
Expand Down
2 changes: 1 addition & 1 deletion lib/Echidna/Transaction.hs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ import Echidna.Types.World (World(..))
import Echidna.Types.Campaign

hasSelfdestructed :: VM Concrete s -> Addr -> Bool
hasSelfdestructed vm addr = LitAddr addr `elem` vm.tx.substate.selfdestructs
hasSelfdestructed vm addr = LitAddr addr `elem` vm.tx.subState.selfdestructs

-- | If half a tuple is zero, make both halves zero. Useful for generating
-- delays, since block number only goes up with timestamp
Expand Down
2 changes: 2 additions & 0 deletions src/test/Tests/Cheat.hs
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,6 @@ cheatTests =
testGroup "Cheatcodes Tests"
[ testContract' "cheat/ffi.sol" (Just "TestFFI") (Just (> solcV (0,6,0))) (Just "cheat/ffi.yaml") False FuzzWorker
[ ("echidna_ffi passed", solved "echidna_ffi") ]
, testContract' "cheat/ffi2.sol" (Just "TestFFI") (Just (> solcV (0,6,0))) (Just "cheat/ffi.yaml") False FuzzWorker
[ ("echidna_ffi passed", solved "echidna_ffi") ]
]
2 changes: 1 addition & 1 deletion stack.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ packages:

extra-deps:
- git: https://github.com/ethereum/hevm.git
commit: c779777d18c8ff60867f009d434b44ce08188e01
commit: 8eaf59c3753f50067551edd2b907acc5d528d115

- smt2-parser-0.1.0.1@sha256:1e1a4565915ed851c13d1e6b8bb5185cf5d454da3b43170825d53e221f753d77,1421
- spawn-0.3@sha256:b91e01d8f2b076841410ae284b32046f91471943dc799c1af77d666c72101f02,1162
Expand Down
31 changes: 31 additions & 0 deletions tests/solidity/cheat/ffi2.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
pragma experimental ABIEncoderV2;

interface Hevm {
function setEnv(string calldata, string calldata) external;
function ffi(string[] calldata) external returns (bytes memory);
}

contract TestFFI {
address constant HEVM_ADDRESS = 0x7109709ECfa91a80626fF3989D68f67F5b1DD12D;

bytes32 hehe;

function foo(int x) external {
// ABI encoded "gm", as a string
Hevm(HEVM_ADDRESS).setEnv("ECHIDNA_FOO_BAR", "0x00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000002676d000000000000000000000000000000000000000000000000000000000000");

string[] memory inputs = new string[](3);
inputs[0] = "sh";
inputs[1] = "-c";
inputs[2] = "printf '%s' \"$ECHIDNA_FOO_BAR\"";

bytes memory res = Hevm(HEVM_ADDRESS).ffi(inputs);

(string memory output) = abi.decode(res, (string));
hehe = keccak256(bytes(output));
}

function echidna_ffi() public returns (bool){
return hehe != keccak256("gm");
}
}

0 comments on commit 31a177d

Please sign in to comment.