@@ -23,18 +23,18 @@ import Data.Aeson qualified as JSON
2323import Data.ByteString (ByteString )
2424import Data.ByteString qualified as BS
2525import Data.ByteString.Char8 qualified as Char8
26- import Data.Maybe (fromJust , fromMaybe , isJust , isNothing )
26+ import Data.Maybe (fromJust , isJust , isNothing )
2727import Data.Map.Strict qualified as Map
2828import Data.Text.IO qualified as T
2929import Data.Vector qualified as Vector
3030import Data.Word (Word8 , Word64 )
3131import GHC.Generics (Generic )
3232import GHC.IO.Exception (ExitCode (ExitSuccess ))
3333import Numeric (showHex )
34- import Paths_hevm qualified as Paths
35- import System.Directory ( removeFile )
36- import System.Environment ( lookupEnv )
37- import System.Process (readProcessWithExitCode )
34+ import System.Directory ( removeDirectoryRecursive )
35+ import System.FilePath ( (</>) )
36+ import System.IO.Temp ( getCanonicalTemporaryDirectory , createTempDirectory )
37+ import System.Process (readCreateProcessWithExitCode , proc , CreateProcess ( .. ) )
3838import Test.QuickCheck (elements )
3939import Test.QuickCheck.Instances.Text ()
4040import Test.QuickCheck.Instances.Natural ()
@@ -308,8 +308,8 @@ getHEVMRet contr txData gaslimitExec = do
308308 let (txn, evmEnv, contrAlloc, fromAddress, toAddress, _) = evmSetup contr txData gaslimitExec
309309 runCodeWithTrace Nothing evmEnv contrAlloc txn (LitAddr fromAddress) (LitAddr toAddress)
310310
311- getEVMToolRet :: OpContract -> ByteString -> Int -> IO (Maybe EVMToolResult )
312- getEVMToolRet contr txData gaslimitExec = do
311+ getEVMToolRet :: FilePath -> OpContract -> ByteString -> Int -> IO (Maybe EVMToolResult )
312+ getEVMToolRet evmDir contr txData gaslimitExec = do
313313 let (txn, evmEnv, contrAlloc, fromAddress, toAddress, sk) = evmSetup contr txData gaslimitExec
314314 txs = [EVM.Transaction. sign sk txn]
315315 walletAlloc = EVMToolAlloc { balance = 0x5ffd4878be161d74
@@ -318,24 +318,25 @@ getEVMToolRet contr txData gaslimitExec = do
318318 }
319319 alloc :: Map. Map Addr EVMToolAlloc
320320 alloc = Map. fromList ([ (fromAddress, walletAlloc), (toAddress, contrAlloc)])
321- JSON. encodeFile " txs.json" txs
322- JSON. encodeFile " alloc.json" alloc
323- JSON. encodeFile " env.json" evmEnv
324- (exitCode, evmtoolStdout, evmtoolStderr) <- readProcessWithExitCode " evm" [ " transition"
325- , " --state.fork" , " Cancun"
326- , " --input.alloc" , " alloc.json"
327- , " --input.env" , " env.json"
328- , " --input.txs" , " txs.json"
329- , " --output.alloc" , " alloc-out.json"
330- , " --trace.returndata=true"
331- , " --trace" , " trace.json"
332- , " --output.result" , " result.json"
333- ] " "
321+ JSON. encodeFile (evmDir </> " txs.json" ) txs
322+ JSON. encodeFile (evmDir </> " alloc.json" ) alloc
323+ JSON. encodeFile (evmDir </> " env.json" ) evmEnv
324+ let cmd = (proc " evm" [ " transition"
325+ , " --state.fork" , " Cancun"
326+ , " --input.alloc" , " alloc.json"
327+ , " --input.env" , " env.json"
328+ , " --input.txs" , " txs.json"
329+ , " --output.alloc" , " alloc-out.json"
330+ , " --trace.returndata=true"
331+ , " --trace" , " trace.json"
332+ , " --output.result" , " result.json"
333+ ]) { cwd = Just evmDir }
334+ (exitCode, evmtoolStdout, evmtoolStderr) <- readCreateProcessWithExitCode cmd " "
334335 when (exitCode /= ExitSuccess ) $ do
335336 putStrLn $ " evmtool exited with code " <> show exitCode
336337 putStrLn $ " evmtool stderr output:" <> show evmtoolStderr
337338 putStrLn $ " evmtool stdout output:" <> show evmtoolStdout
338- JSON. decodeFileStrict " result.json" :: IO (Maybe EVMToolResult )
339+ JSON. decodeFileStrict (evmDir </> " result.json" ) :: IO (Maybe EVMToolResult )
339340
340341-- Compares traces of evmtool (from go-ethereum) and HEVM
341342compareTraces :: [VMTrace ] -> [EVMToolTrace ] -> IO (Bool )
@@ -389,45 +390,34 @@ compareTraces hevmTrace evmTrace = go hevmTrace evmTrace
389390 putStrLn $ " Traces don't match. evmtool's trace is longer by:" <> (show b)
390391 pure False
391392
392- getTraceFileName :: EVMToolResult -> String
393- getTraceFileName evmtoolResult = traceFileName
393+ getTraceFileName :: FilePath -> EVMToolResult -> String
394+ getTraceFileName evmDir evmtoolResult = evmDir </> traceFileName
394395 where
395396 txName = ((evmtoolResult. receipts) !! 0 ). transactionHash
396397 traceFileName = " trace-0-" ++ txName ++ " .jsonl"
397398
398- getTraceOutput :: Maybe EVMToolResult -> IO (Maybe EVMToolTraceOutput )
399- getTraceOutput evmtoolResult =
399+ getTraceOutput :: FilePath -> Maybe EVMToolResult -> IO (Maybe EVMToolTraceOutput )
400+ getTraceOutput evmDir evmtoolResult =
400401 case evmtoolResult of
401402 Nothing -> pure Nothing
402403 Just res -> do
403- let traceFileName = getTraceFileName res
404+ let traceFileName = getTraceFileName evmDir res
404405 decodeTraceOutputHelper traceFileName
405406
406407decodeTraceOutputHelper :: String -> IO (Maybe EVMToolTraceOutput )
407408decodeTraceOutputHelper traceFileName = do
408- convertPath <- Paths. getDataFileName " test/scripts/convert_trace_to_json.sh"
409- maybeShellPath <- (fromMaybe " bash" ) <$> (lookupEnv " HEVM_SYSTEM_SHELL" )
410- let shellPath = if maybeShellPath == " " then " bash" else maybeShellPath
411- (exitcode, stdout, stderr) <- readProcessWithExitCode shellPath [convertPath, traceFileName] " "
412- case exitcode of
413- ExitSuccess -> do
414- -- putStrLn $ "Successfully converted trace to JSON: " <> (show stdout) <> " " <>
415- -- (show stderr) <> " " <> (show exitcode) <> " " <> (show traceFileName)
416- JSON. decodeFileStrict (traceFileName ++ " .json" ) :: IO (Maybe EVMToolTraceOutput )
417- _ -> do
418- putStrLn $ " Error converting trace! exit code:" <> (show exitcode)
419- putStrLn $ " stdout: " <> (show stdout)
420- putStrLn $ " stderr: " <> (show stderr)
421- pure Nothing
422-
423- deleteTraceOutputFiles :: Maybe EVMToolResult -> IO ()
424- deleteTraceOutputFiles evmtoolResult =
425- case evmtoolResult of
426- Nothing -> pure ()
427- Just res -> do
428- let traceFileName = getTraceFileName res
429- System.Directory. removeFile traceFileName
430- System.Directory. removeFile (traceFileName ++ " .json" )
409+ traceContents <- readFile traceFileName
410+ let traceLines = lines traceContents
411+ let (traces, outputLines) = splitAt (length traceLines - 1 ) traceLines
412+ let parsedTraces = map decodeString traces :: [Maybe EVMToolTrace ]
413+ let parsedOutput = decodeString (outputLines !! 0 ) :: Maybe EVMToolOutput
414+ if all isJust parsedTraces && isJust parsedOutput then
415+ pure $ Just $ EVMToolTraceOutput (map fromJust parsedTraces) (fromJust parsedOutput)
416+ else
417+ pure Nothing
418+ where
419+ decodeString :: (JSON. FromJSON a ) => String -> Maybe a
420+ decodeString = JSON. decodeStrict . Char8. pack
431421
432422-- | Takes a runtime code and calls it with the provided calldata
433423-- Uses evmtool's alloc and transaction to set up the VM correctly
@@ -875,9 +865,11 @@ tests = testGroup "contract-quickcheck-run"
875865
876866checkTraceAndOutputs :: App m => OpContract -> Int -> ByteString -> m ()
877867checkTraceAndOutputs contract gasLimit txData = do
878- evmtoolResult <- liftIO $ getEVMToolRet contract txData gasLimit
868+ tmpDir <- liftIO getCanonicalTemporaryDirectory
869+ evmDir <- liftIO $ createTempDirectory tmpDir " evm-trace"
870+ evmtoolResult <- liftIO $ getEVMToolRet evmDir contract txData gasLimit
879871 hevmRun <- getHEVMRet contract txData gasLimit
880- evmtoolTraceOutput <- fmap fromJust $ liftIO $ getTraceOutput evmtoolResult
872+ evmtoolTraceOutput <- fmap fromJust $ liftIO $ getTraceOutput evmDir evmtoolResult
881873 case hevmRun of
882874 (Right (expr, hevmTrace, hevmTraceResult)) -> liftIO $ do
883875 let
@@ -915,7 +907,7 @@ checkTraceAndOutputs contract gasLimit txData = do
915907 putStrLn $ " ret value computed via symb+conc : " <> (bsToHex (fromJust simplConcrExprRetval))
916908 assertEqual " Simplified, concretized expression must match evmtool's output." True False
917909 else do
918- putStrLn $ " Name of trace file: " <> (getTraceFileName $ fromJust evmtoolResult)
910+ putStrLn $ " Name of trace file: " <> (getTraceFileName evmDir $ fromJust evmtoolResult)
919911 putStrLn $ " HEVM result :" <> (show hevmTraceResult)
920912 T. putStrLn $ " HEVM result: " <> (formatBinary $ bssToBs hevmTraceResult. out)
921913 T. putStrLn $ " evm result : " <> (formatBinary $ bssToBs evmtoolTraceOutput. output. output)
@@ -928,13 +920,7 @@ checkTraceAndOutputs contract gasLimit txData = do
928920 -- putStrLn $ "output by evmtool is: '" <> bsToHex evmtoolTraceOutput.toOutput.output <> "'"
929921 traceOK <- compareTraces hevmTrace (evmtoolTraceOutput. trace)
930922 assertEqual " Traces and gas must match" traceOK True
931- liftIO $ do
932- System.Directory. removeFile " txs.json"
933- System.Directory. removeFile " alloc-out.json"
934- System.Directory. removeFile " alloc.json"
935- System.Directory. removeFile " result.json"
936- System.Directory. removeFile " env.json"
937- deleteTraceOutputFiles evmtoolResult
923+ liftIO $ removeDirectoryRecursive evmDir
938924
939925-- GasLimitInt
940926newtype GasLimitInt = GasLimitInt (Int )
0 commit comments