{-# LANGUAGE DeriveAnyClass #-}
module EVM.Dev where
import System.Directory
import Prelude hiding (Word)
import EVM.Types
import EVM.Dapp
import EVM.Solidity
import EVM.UnitTest
import EVM.Symbolic
import EVM hiding (path)
import qualified EVM.Fetch
import qualified EVM.TTY
import qualified EVM.Emacs
import qualified EVM.Facts as Facts
import qualified EVM.Facts.Git as Git
import qualified EVM.Stepper
import qualified EVM.VMTest as VMTest
import Data.SBV hiding (Word)
import qualified Data.Aeson as JSON
import Options.Generic
import Data.SBV.Trans.Control
import Data.Maybe (fromMaybe)
import Control.Monad.State.Strict (execStateT)
import qualified Data.Map as Map
import qualified Data.ByteString.Lazy as LazyByteString
import qualified Data.ByteString as BS
import qualified Data.ByteString.Lazy.Char8 as B
import qualified Control.Monad.State.Class as State
import Control.Monad.State.Strict (runState, liftIO, StateT, get)
import Control.Lens hiding (op, passing)
import Control.Monad.Operational (ProgramViewT(..), ProgramView)
import qualified Control.Monad.Operational as Operational
loadDappInfo :: String -> String -> IO DappInfo
loadDappInfo :: String -> String -> IO DappInfo
loadDappInfo path :: String
path file :: String
file =
String -> IO DappInfo -> IO DappInfo
forall a. String -> IO a -> IO a
withCurrentDirectory String
path (IO DappInfo -> IO DappInfo) -> IO DappInfo -> IO DappInfo
forall a b. (a -> b) -> a -> b
$
String -> IO (Maybe (Map Text SolcContract, SourceCache))
readSolc String
file IO (Maybe (Map Text SolcContract, SourceCache))
-> (Maybe (Map Text SolcContract, SourceCache) -> IO DappInfo)
-> IO DappInfo
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>=
\case
Just (contractMap :: Map Text SolcContract
contractMap, sourcecache :: SourceCache
sourcecache) ->
DappInfo -> IO DappInfo
forall (f :: * -> *) a. Applicative f => a -> f a
pure (String -> Map Text SolcContract -> SourceCache -> DappInfo
dappInfo "." Map Text SolcContract
contractMap SourceCache
sourcecache)
_ ->
String -> IO DappInfo
forall a. HasCallStack => String -> a
error "nope, sorry"
ghciTest :: String -> String -> Maybe String -> IO [Bool]
ghciTest :: String -> String -> Maybe String -> IO [Bool]
ghciTest root :: String
root path :: String
path statePath :: Maybe String
statePath =
String -> IO [Bool] -> IO [Bool]
forall a. String -> IO a -> IO a
withCurrentDirectory String
root (IO [Bool] -> IO [Bool]) -> IO [Bool] -> IO [Bool]
forall a b. (a -> b) -> a -> b
$ do
VM -> VM
loadFacts <-
case Maybe String
statePath of
Nothing ->
(VM -> VM) -> IO (VM -> VM)
forall (f :: * -> *) a. Applicative f => a -> f a
pure VM -> VM
forall a. a -> a
id
Just repoPath :: String
repoPath -> do
Set Fact
facts <- RepoAt -> IO (Set Fact)
Git.loadFacts (String -> RepoAt
Git.RepoAt String
repoPath)
(VM -> VM) -> IO (VM -> VM)
forall (f :: * -> *) a. Applicative f => a -> f a
pure ((VM -> Set Fact -> VM) -> Set Fact -> VM -> VM
forall a b c. (a -> b -> c) -> b -> a -> c
flip VM -> Set Fact -> VM
Facts.apply Set Fact
facts)
TestVMParams
params <- Maybe Text -> IO TestVMParams
getParametersFromEnvironmentVariables Maybe Text
forall a. Maybe a
Nothing
let
opts :: UnitTestOptions
opts = UnitTestOptions :: (Query -> IO (EVM ()))
-> Maybe Int
-> Maybe Integer
-> Maybe Integer
-> Maybe State
-> Maybe Text
-> Text
-> Int
-> Maybe (Text, ByteString)
-> (VM -> VM)
-> DappInfo
-> TestVMParams
-> UnitTestOptions
UnitTestOptions
{ oracle :: Query -> IO (EVM ())
oracle = Query -> IO (EVM ())
EVM.Fetch.zero
, verbose :: Maybe Int
verbose = Maybe Int
forall a. Maybe a
Nothing
, maxIter :: Maybe Integer
maxIter = Maybe Integer
forall a. Maybe a
Nothing
, smtTimeout :: Maybe Integer
smtTimeout = Maybe Integer
forall a. Maybe a
Nothing
, smtState :: Maybe State
smtState = Maybe State
forall a. Maybe a
Nothing
, solver :: Maybe Text
solver = Maybe Text
forall a. Maybe a
Nothing
, match :: Text
match = ""
, fuzzRuns :: Int
fuzzRuns = 100
, replay :: Maybe (Text, ByteString)
replay = Maybe (Text, ByteString)
forall a. Maybe a
Nothing
, vmModifier :: VM -> VM
vmModifier = VM -> VM
loadFacts
, dapp :: DappInfo
dapp = DappInfo
emptyDapp
, testParams :: TestVMParams
testParams = TestVMParams
params
}
String -> IO (Maybe (Map Text SolcContract, SourceCache))
readSolc String
path IO (Maybe (Map Text SolcContract, SourceCache))
-> (Maybe (Map Text SolcContract, SourceCache) -> IO [Bool])
-> IO [Bool]
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>=
\case
Just (contractMap :: Map Text SolcContract
contractMap, _) -> do
let unitTests :: [(Text, [(Test, [AbiType])])]
unitTests = [SolcContract] -> [(Text, [(Test, [AbiType])])]
findAllUnitTests (Map Text SolcContract -> [SolcContract]
forall k a. Map k a -> [a]
Map.elems Map Text SolcContract
contractMap)
[(Bool, VM)]
results <- Symbolic [(Bool, VM)] -> IO [(Bool, VM)]
forall a. Symbolic a -> IO a
runSMT (Symbolic [(Bool, VM)] -> IO [(Bool, VM)])
-> Symbolic [(Bool, VM)] -> IO [(Bool, VM)]
forall a b. (a -> b) -> a -> b
$ QueryT IO [(Bool, VM)] -> Symbolic [(Bool, VM)]
forall (m :: * -> *) a. ExtractIO m => QueryT m a -> SymbolicT m a
query (QueryT IO [(Bool, VM)] -> Symbolic [(Bool, VM)])
-> QueryT IO [(Bool, VM)] -> Symbolic [(Bool, VM)]
forall a b. (a -> b) -> a -> b
$ ((Text, [(Test, [AbiType])]) -> QueryT IO [(Bool, VM)])
-> [(Text, [(Test, [AbiType])])] -> QueryT IO [(Bool, VM)]
forall (m :: * -> *) a b. Monad m => (a -> m [b]) -> [a] -> m [b]
concatMapM (UnitTestOptions
-> Map Text SolcContract
-> (Text, [(Test, [AbiType])])
-> QueryT IO [(Bool, VM)]
runUnitTestContract UnitTestOptions
opts Map Text SolcContract
contractMap) [(Text, [(Test, [AbiType])])]
unitTests
let (passing :: [Bool]
passing, _) = [(Bool, VM)] -> ([Bool], [VM])
forall a b. [(a, b)] -> ([a], [b])
unzip [(Bool, VM)]
results
[Bool] -> IO [Bool]
forall (f :: * -> *) a. Applicative f => a -> f a
pure [Bool]
passing
Nothing ->
String -> IO [Bool]
forall a. HasCallStack => String -> a
error ("Failed to read Solidity JSON for `" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
path String -> String -> String
forall a. [a] -> [a] -> [a]
++ "'")
runBCTest :: (String, VMTest.Case) -> IO Bool
runBCTest :: (String, Case) -> IO Bool
runBCTest (name :: String
name, x :: Case
x) = do
let vm0 :: VM
vm0 = Case -> VM
VMTest.vmForCase Case
x
String -> IO ()
putStr (String
name String -> String -> String
forall a. [a] -> [a] -> [a]
++ " ")
VM
out <-
StateT VM IO (Either Error Buffer) -> VM -> IO VM
forall (m :: * -> *) s a. Monad m => StateT s m a -> s -> m s
execStateT ((Query -> IO (EVM ()))
-> Stepper (Either Error Buffer)
-> StateT VM IO (Either Error Buffer)
forall a. (Query -> IO (EVM ())) -> Stepper a -> StateT VM IO a
EVM.Stepper.interpret Query -> IO (EVM ())
EVM.Fetch.zero Stepper (Either Error Buffer)
EVM.Stepper.execFully) VM
vm0
Bool
ok <- HasCallStack => Bool -> Case -> VM -> IO Bool
Bool -> Case -> VM -> IO Bool
VMTest.checkExpectation Bool
False Case
x VM
out
String -> IO ()
putStrLn (if Bool
ok then "ok" else "")
Bool -> IO Bool
forall (m :: * -> *) a. Monad m => a -> m a
return Bool
ok
ghciBCTest :: String -> IO ()
ghciBCTest :: String -> IO ()
ghciBCTest file :: String
file = do
let parser :: ByteString -> Either String (Map String Case)
parser = ByteString -> Either String (Map String Case)
VMTest.parseBCSuite
Either String (Map String Case)
parsed <- ByteString -> Either String (Map String Case)
parser (ByteString -> Either String (Map String Case))
-> IO ByteString -> IO (Either String (Map String Case))
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> String -> IO ByteString
LazyByteString.readFile String
file
case Either String (Map String Case)
parsed of
Left "No cases to check." -> String -> IO ()
putStrLn "no-cases ok"
Left err :: String
err -> String -> IO ()
forall a. Show a => a -> IO ()
print String
err
Right allTests :: Map String Case
allTests ->
((String, Case) -> IO Bool) -> [(String, Case)] -> IO ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_ (String, Case) -> IO Bool
runBCTest (Map String Case -> [(String, Case)]
forall k a. Map k a -> [(k, a)]
Map.toList Map String Case
allTests)
ghciTty :: String -> String -> Maybe String -> IO ()
ghciTty :: String -> String -> Maybe String -> IO ()
ghciTty root :: String
root path :: String
path statePath :: Maybe String
statePath =
String -> IO () -> IO ()
forall a. String -> IO a -> IO a
withCurrentDirectory String
root (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ do
VM -> VM
loadFacts <-
case Maybe String
statePath of
Nothing ->
(VM -> VM) -> IO (VM -> VM)
forall (f :: * -> *) a. Applicative f => a -> f a
pure VM -> VM
forall a. a -> a
id
Just repoPath :: String
repoPath -> do
Set Fact
facts <- RepoAt -> IO (Set Fact)
Git.loadFacts (String -> RepoAt
Git.RepoAt String
repoPath)
(VM -> VM) -> IO (VM -> VM)
forall (f :: * -> *) a. Applicative f => a -> f a
pure ((VM -> Set Fact -> VM) -> Set Fact -> VM -> VM
forall a b c. (a -> b -> c) -> b -> a -> c
flip VM -> Set Fact -> VM
Facts.apply Set Fact
facts)
TestVMParams
params <- Maybe Text -> IO TestVMParams
getParametersFromEnvironmentVariables Maybe Text
forall a. Maybe a
Nothing
let
testOpts :: UnitTestOptions
testOpts = UnitTestOptions :: (Query -> IO (EVM ()))
-> Maybe Int
-> Maybe Integer
-> Maybe Integer
-> Maybe State
-> Maybe Text
-> Text
-> Int
-> Maybe (Text, ByteString)
-> (VM -> VM)
-> DappInfo
-> TestVMParams
-> UnitTestOptions
UnitTestOptions
{ oracle :: Query -> IO (EVM ())
oracle = Query -> IO (EVM ())
EVM.Fetch.zero
, verbose :: Maybe Int
verbose = Maybe Int
forall a. Maybe a
Nothing
, maxIter :: Maybe Integer
maxIter = Maybe Integer
forall a. Maybe a
Nothing
, smtTimeout :: Maybe Integer
smtTimeout = Maybe Integer
forall a. Maybe a
Nothing
, smtState :: Maybe State
smtState = Maybe State
forall a. Maybe a
Nothing
, solver :: Maybe Text
solver = Maybe Text
forall a. Maybe a
Nothing
, match :: Text
match = ""
, fuzzRuns :: Int
fuzzRuns = 100
, replay :: Maybe (Text, ByteString)
replay = Maybe (Text, ByteString)
forall a. Maybe a
Nothing
, vmModifier :: VM -> VM
vmModifier = VM -> VM
loadFacts
, dapp :: DappInfo
dapp = DappInfo
emptyDapp
, testParams :: TestVMParams
testParams = TestVMParams
params
}
UnitTestOptions -> String -> String -> IO ()
EVM.TTY.main UnitTestOptions
testOpts String
root String
path
ghciEmacs :: IO ()
ghciEmacs :: IO ()
ghciEmacs =
IO ()
EVM.Emacs.main
foo :: IO ()
foo :: IO ()
foo = IO ()
ghciEmacs
data VMTrace =
VMTrace
{ VMTrace -> Int
pc :: Int
, VMTrace -> Int
op :: Int
, VMTrace -> [Word]
stack :: [Word]
, VMTrace -> Int
memSize :: Int
, VMTrace -> Int
depth :: Int
, VMTrace -> Word
gas :: Word
} deriving ((forall x. VMTrace -> Rep VMTrace x)
-> (forall x. Rep VMTrace x -> VMTrace) -> Generic VMTrace
forall x. Rep VMTrace x -> VMTrace
forall x. VMTrace -> Rep VMTrace x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall x. Rep VMTrace x -> VMTrace
$cfrom :: forall x. VMTrace -> Rep VMTrace x
Generic, [VMTrace] -> Encoding
[VMTrace] -> Value
VMTrace -> Encoding
VMTrace -> Value
(VMTrace -> Value)
-> (VMTrace -> Encoding)
-> ([VMTrace] -> Value)
-> ([VMTrace] -> Encoding)
-> ToJSON VMTrace
forall a.
(a -> Value)
-> (a -> Encoding)
-> ([a] -> Value)
-> ([a] -> Encoding)
-> ToJSON a
toEncodingList :: [VMTrace] -> Encoding
$ctoEncodingList :: [VMTrace] -> Encoding
toJSONList :: [VMTrace] -> Value
$ctoJSONList :: [VMTrace] -> Value
toEncoding :: VMTrace -> Encoding
$ctoEncoding :: VMTrace -> Encoding
toJSON :: VMTrace -> Value
$ctoJSON :: VMTrace -> Value
JSON.ToJSON)
data VMTraceResult =
VMTraceResult
{ VMTraceResult -> String
output :: String
, VMTraceResult -> Word
gasUsed :: Word
} deriving ((forall x. VMTraceResult -> Rep VMTraceResult x)
-> (forall x. Rep VMTraceResult x -> VMTraceResult)
-> Generic VMTraceResult
forall x. Rep VMTraceResult x -> VMTraceResult
forall x. VMTraceResult -> Rep VMTraceResult x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall x. Rep VMTraceResult x -> VMTraceResult
$cfrom :: forall x. VMTraceResult -> Rep VMTraceResult x
Generic, [VMTraceResult] -> Encoding
[VMTraceResult] -> Value
VMTraceResult -> Encoding
VMTraceResult -> Value
(VMTraceResult -> Value)
-> (VMTraceResult -> Encoding)
-> ([VMTraceResult] -> Value)
-> ([VMTraceResult] -> Encoding)
-> ToJSON VMTraceResult
forall a.
(a -> Value)
-> (a -> Encoding)
-> ([a] -> Value)
-> ([a] -> Encoding)
-> ToJSON a
toEncodingList :: [VMTraceResult] -> Encoding
$ctoEncodingList :: [VMTraceResult] -> Encoding
toJSONList :: [VMTraceResult] -> Value
$ctoJSONList :: [VMTraceResult] -> Value
toEncoding :: VMTraceResult -> Encoding
$ctoEncoding :: VMTraceResult -> Encoding
toJSON :: VMTraceResult -> Value
$ctoJSON :: VMTraceResult -> Value
JSON.ToJSON)
getOp :: VM -> Word8
getOp :: VM -> Word8
getOp vm :: VM
vm =
let i :: Int
i = VM
vm VM -> Getting Int VM Int -> Int
forall s a. s -> Getting a s a -> a
^. (FrameState -> Const Int FrameState) -> VM -> Const Int VM
Lens' VM FrameState
state ((FrameState -> Const Int FrameState) -> VM -> Const Int VM)
-> ((Int -> Const Int Int) -> FrameState -> Const Int FrameState)
-> Getting Int VM Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Int -> Const Int Int) -> FrameState -> Const Int FrameState
Lens' FrameState Int
EVM.pc
code' :: Buffer
code' = VM
vm VM -> Getting Buffer VM Buffer -> Buffer
forall s a. s -> Getting a s a -> a
^. (FrameState -> Const Buffer FrameState) -> VM -> Const Buffer VM
Lens' VM FrameState
state ((FrameState -> Const Buffer FrameState) -> VM -> Const Buffer VM)
-> ((Buffer -> Const Buffer Buffer)
-> FrameState -> Const Buffer FrameState)
-> Getting Buffer VM Buffer
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Buffer -> Const Buffer Buffer)
-> FrameState -> Const Buffer FrameState
Lens' FrameState Buffer
code
xs :: Buffer
xs = case Buffer
code' of
ConcreteBuffer xs' :: ByteString
xs' -> ByteString -> Buffer
ConcreteBuffer (Int -> ByteString -> ByteString
BS.drop Int
i ByteString
xs')
SymbolicBuffer xs' :: [SWord 8]
xs' -> [SWord 8] -> Buffer
SymbolicBuffer (Int -> [SWord 8] -> [SWord 8]
forall a. Int -> [a] -> [a]
drop Int
i [SWord 8]
xs')
in if Buffer -> Int
len Buffer
xs Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== 0 then 0
else case Buffer
xs of
ConcreteBuffer b :: ByteString
b -> ByteString -> Int -> Word8
BS.index ByteString
b 0
SymbolicBuffer b :: [SWord 8]
b -> WordN 8 -> Word8
forall a. FromSizedBV a => a -> FromSized a
fromSized (WordN 8 -> Word8) -> WordN 8 -> Word8
forall a b. (a -> b) -> a -> b
$ WordN 8 -> Maybe (WordN 8) -> WordN 8
forall a. a -> Maybe a -> a
fromMaybe (String -> WordN 8
forall a. HasCallStack => String -> a
error "unexpected symbolic code") (SWord 8 -> Maybe (WordN 8)
forall a. SymVal a => SBV a -> Maybe a
unliteral ([SWord 8]
b [SWord 8] -> Int -> SWord 8
forall a. [a] -> Int -> a
!! 0))
vmtrace :: VM -> VMTrace
vmtrace :: VM -> VMTrace
vmtrace vm :: VM
vm =
let
the :: (b -> VM -> Const a VM) -> ((a -> Const a a) -> b) -> a
the :: (b -> VM -> Const a VM) -> ((a -> Const a a) -> b) -> a
the f :: b -> VM -> Const a VM
f g :: (a -> Const a a) -> b
g = Getting a VM a -> VM -> a
forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view (b -> VM -> Const a VM
f (b -> VM -> Const a VM)
-> ((a -> Const a a) -> b) -> Getting a VM a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (a -> Const a a) -> b
g) VM
vm
memsize :: Int
memsize = ((FrameState -> Const Int FrameState) -> VM -> Const Int VM)
-> ((Int -> Const Int Int) -> FrameState -> Const Int FrameState)
-> Int
forall b a. (b -> VM -> Const a VM) -> ((a -> Const a a) -> b) -> a
the (FrameState -> Const Int FrameState) -> VM -> Const Int VM
Lens' VM FrameState
state (Int -> Const Int Int) -> FrameState -> Const Int FrameState
Lens' FrameState Int
memorySize
in VMTrace :: Int -> Int -> [Word] -> Int -> Int -> Word -> VMTrace
VMTrace { pc :: Int
pc = ((FrameState -> Const Int FrameState) -> VM -> Const Int VM)
-> ((Int -> Const Int Int) -> FrameState -> Const Int FrameState)
-> Int
forall b a. (b -> VM -> Const a VM) -> ((a -> Const a a) -> b) -> a
the (FrameState -> Const Int FrameState) -> VM -> Const Int VM
Lens' VM FrameState
state (Int -> Const Int Int) -> FrameState -> Const Int FrameState
Lens' FrameState Int
EVM.pc
, op :: Int
op = Word8 -> Int
forall a b. (Integral a, Num b) => a -> b
num (Word8 -> Int) -> Word8 -> Int
forall a b. (a -> b) -> a -> b
$ VM -> Word8
getOp VM
vm
, gas :: Word
gas = ((FrameState -> Const Word FrameState) -> VM -> Const Word VM)
-> ((Word -> Const Word Word)
-> FrameState -> Const Word FrameState)
-> Word
forall b a. (b -> VM -> Const a VM) -> ((a -> Const a a) -> b) -> a
the (FrameState -> Const Word FrameState) -> VM -> Const Word VM
Lens' VM FrameState
state (Word -> Const Word Word) -> FrameState -> Const Word FrameState
Lens' FrameState Word
EVM.gas
, memSize :: Int
memSize = Int
memsize
, depth :: Int
depth = 1 Int -> Int -> Int
forall a. Num a => a -> a -> a
+ [Frame] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length (Getting [Frame] VM [Frame] -> VM -> [Frame]
forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view Getting [Frame] VM [Frame]
Lens' VM [Frame]
frames VM
vm)
, stack :: [Word]
stack = [Word] -> [Word]
forall a. [a] -> [a]
reverse ([Word] -> [Word]) -> [Word] -> [Word]
forall a b. (a -> b) -> a -> b
$ SymWord -> Word
forceLit (SymWord -> Word) -> [SymWord] -> [Word]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ((FrameState -> Const [SymWord] FrameState)
-> VM -> Const [SymWord] VM)
-> (([SymWord] -> Const [SymWord] [SymWord])
-> FrameState -> Const [SymWord] FrameState)
-> [SymWord]
forall b a. (b -> VM -> Const a VM) -> ((a -> Const a a) -> b) -> a
the (FrameState -> Const [SymWord] FrameState)
-> VM -> Const [SymWord] VM
Lens' VM FrameState
state ([SymWord] -> Const [SymWord] [SymWord])
-> FrameState -> Const [SymWord] FrameState
Lens' FrameState [SymWord]
EVM.stack
}
vmres :: VM -> VMTraceResult
vmres :: VM -> VMTraceResult
vmres vm :: VM
vm =
let
gasUsed' :: Word
gasUsed' = Getting Word VM Word -> VM -> Word
forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view ((TxState -> Const Word TxState) -> VM -> Const Word VM
Lens' VM TxState
tx ((TxState -> Const Word TxState) -> VM -> Const Word VM)
-> ((Word -> Const Word Word) -> TxState -> Const Word TxState)
-> Getting Word VM Word
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Word -> Const Word Word) -> TxState -> Const Word TxState
Lens' TxState Word
txgaslimit) VM
vm Word -> Word -> Word
forall a. Num a => a -> a -> a
- Getting Word VM Word -> VM -> Word
forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view ((FrameState -> Const Word FrameState) -> VM -> Const Word VM
Lens' VM FrameState
state ((FrameState -> Const Word FrameState) -> VM -> Const Word VM)
-> ((Word -> Const Word Word)
-> FrameState -> Const Word FrameState)
-> Getting Word VM Word
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Word -> Const Word Word) -> FrameState -> Const Word FrameState
Lens' FrameState Word
EVM.gas) VM
vm
res :: ByteString
res = case Getting (Maybe VMResult) VM (Maybe VMResult)
-> VM -> Maybe VMResult
forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view Getting (Maybe VMResult) VM (Maybe VMResult)
Lens' VM (Maybe VMResult)
result VM
vm of
Just (VMSuccess out :: Buffer
out) -> Buffer -> ByteString
forceBuffer Buffer
out
Just (VMFailure (Revert out :: ByteString
out)) -> ByteString
out
_ -> ByteString
forall a. Monoid a => a
mempty
in VMTraceResult :: String -> Word -> VMTraceResult
VMTraceResult
{ output :: String
output = Int -> String -> String
forall a. Int -> [a] -> [a]
drop 2 (String -> String) -> String -> String
forall a b. (a -> b) -> a -> b
$ ByteStringS -> String
forall a. Show a => a -> String
show (ByteStringS -> String) -> ByteStringS -> String
forall a b. (a -> b) -> a -> b
$ ByteString -> ByteStringS
ByteStringS ByteString
res
, gasUsed :: Word
gasUsed = Word
gasUsed'
}
interpretWithTrace :: EVM.Fetch.Fetcher -> EVM.Stepper.Stepper a -> StateT VM IO a
interpretWithTrace :: (Query -> IO (EVM ())) -> Stepper a -> StateT VM IO a
interpretWithTrace fetcher :: Query -> IO (EVM ())
fetcher =
ProgramView Action a -> StateT VM IO a
forall a. ProgramView Action a -> StateT VM IO a
eval (ProgramView Action a -> StateT VM IO a)
-> (Stepper a -> ProgramView Action a)
-> Stepper a
-> StateT VM IO a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Stepper a -> ProgramView Action a
forall (instr :: * -> *) a. Program instr a -> ProgramView instr a
Operational.view
where
eval
:: ProgramView EVM.Stepper.Action a
-> StateT VM IO a
eval :: ProgramView Action a -> StateT VM IO a
eval (Return x :: a
x) = do
VM
vm <- StateT VM IO VM
forall s (m :: * -> *). MonadState s m => m s
get
IO () -> StateT VM IO ()
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> StateT VM IO ()) -> IO () -> StateT VM IO ()
forall a b. (a -> b) -> a -> b
$ ByteString -> IO ()
B.putStrLn (ByteString -> IO ()) -> ByteString -> IO ()
forall a b. (a -> b) -> a -> b
$ VMTraceResult -> ByteString
forall a. ToJSON a => a -> ByteString
JSON.encode (VMTraceResult -> ByteString) -> VMTraceResult -> ByteString
forall a b. (a -> b) -> a -> b
$ VM -> VMTraceResult
vmres VM
vm
a -> StateT VM IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure a
x
eval (action :: Action b
action :>>= k :: b -> ProgramT Action Identity a
k) = do
VM
vm <- StateT VM IO VM
forall s (m :: * -> *). MonadState s m => m s
get
case Action b
action of
EVM.Stepper.Run -> do
Getting (Maybe VMResult) VM (Maybe VMResult)
-> StateT VM IO (Maybe VMResult)
forall s (m :: * -> *) a. MonadState s m => Getting a s a -> m a
use Getting (Maybe VMResult) VM (Maybe VMResult)
Lens' VM (Maybe VMResult)
result StateT VM IO (Maybe VMResult)
-> (Maybe VMResult -> StateT VM IO a) -> StateT VM IO a
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
Just _ -> do
(Query -> IO (EVM ()))
-> ProgramT Action Identity a -> StateT VM IO a
forall a. (Query -> IO (EVM ())) -> Stepper a -> StateT VM IO a
interpretWithTrace Query -> IO (EVM ())
fetcher (b -> ProgramT Action Identity a
k b
VM
vm)
Nothing -> do
IO () -> StateT VM IO ()
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> StateT VM IO ()) -> IO () -> StateT VM IO ()
forall a b. (a -> b) -> a -> b
$ ByteString -> IO ()
B.putStrLn (ByteString -> IO ()) -> ByteString -> IO ()
forall a b. (a -> b) -> a -> b
$ VMTrace -> ByteString
forall a. ToJSON a => a -> ByteString
JSON.encode (VMTrace -> ByteString) -> VMTrace -> ByteString
forall a b. (a -> b) -> a -> b
$ VM -> VMTrace
vmtrace VM
vm
(VM -> ((), VM)) -> StateT VM IO ()
forall s (m :: * -> *) a. MonadState s m => (s -> (a, s)) -> m a
State.state (EVM () -> VM -> ((), VM)
forall s a. State s a -> s -> (a, s)
runState EVM ()
exec1)
(Query -> IO (EVM ()))
-> ProgramT Action Identity a -> StateT VM IO a
forall a. (Query -> IO (EVM ())) -> Stepper a -> StateT VM IO a
interpretWithTrace Query -> IO (EVM ())
fetcher (Stepper VM
EVM.Stepper.run Stepper VM
-> (VM -> ProgramT Action Identity a) -> ProgramT Action Identity a
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= b -> ProgramT Action Identity a
VM -> ProgramT Action Identity a
k)
EVM.Stepper.Exec -> do
Getting (Maybe VMResult) VM (Maybe VMResult)
-> StateT VM IO (Maybe VMResult)
forall s (m :: * -> *) a. MonadState s m => Getting a s a -> m a
use Getting (Maybe VMResult) VM (Maybe VMResult)
Lens' VM (Maybe VMResult)
result StateT VM IO (Maybe VMResult)
-> (Maybe VMResult -> StateT VM IO a) -> StateT VM IO a
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
Just r :: VMResult
r -> do
(Query -> IO (EVM ()))
-> ProgramT Action Identity a -> StateT VM IO a
forall a. (Query -> IO (EVM ())) -> Stepper a -> StateT VM IO a
interpretWithTrace Query -> IO (EVM ())
fetcher (b -> ProgramT Action Identity a
k b
VMResult
r)
Nothing -> do
IO () -> StateT VM IO ()
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> StateT VM IO ()) -> IO () -> StateT VM IO ()
forall a b. (a -> b) -> a -> b
$ ByteString -> IO ()
B.putStrLn (ByteString -> IO ()) -> ByteString -> IO ()
forall a b. (a -> b) -> a -> b
$ VMTrace -> ByteString
forall a. ToJSON a => a -> ByteString
JSON.encode (VMTrace -> ByteString) -> VMTrace -> ByteString
forall a b. (a -> b) -> a -> b
$ VM -> VMTrace
vmtrace VM
vm
(VM -> ((), VM)) -> StateT VM IO ()
forall s (m :: * -> *) a. MonadState s m => (s -> (a, s)) -> m a
State.state (EVM () -> VM -> ((), VM)
forall s a. State s a -> s -> (a, s)
runState EVM ()
exec1)
(Query -> IO (EVM ()))
-> ProgramT Action Identity a -> StateT VM IO a
forall a. (Query -> IO (EVM ())) -> Stepper a -> StateT VM IO a
interpretWithTrace Query -> IO (EVM ())
fetcher (Stepper VMResult
EVM.Stepper.exec Stepper VMResult
-> (VMResult -> ProgramT Action Identity a)
-> ProgramT Action Identity a
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= b -> ProgramT Action Identity a
VMResult -> ProgramT Action Identity a
k)
EVM.Stepper.Wait q :: Query
q ->
do EVM ()
m <- IO (EVM ()) -> StateT VM IO (EVM ())
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (Query -> IO (EVM ())
fetcher Query
q)
(VM -> ((), VM)) -> StateT VM IO ()
forall s (m :: * -> *) a. MonadState s m => (s -> (a, s)) -> m a
State.state (EVM () -> VM -> ((), VM)
forall s a. State s a -> s -> (a, s)
runState EVM ()
m) StateT VM IO () -> StateT VM IO a -> StateT VM IO a
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> (Query -> IO (EVM ()))
-> ProgramT Action Identity a -> StateT VM IO a
forall a. (Query -> IO (EVM ())) -> Stepper a -> StateT VM IO a
interpretWithTrace Query -> IO (EVM ())
fetcher (b -> ProgramT Action Identity a
k ())
EVM.Stepper.Ask _ ->
String -> StateT VM IO a
forall a. HasCallStack => String -> a
error "cannot make choices with this interpretWithTraceer"
EVM.Stepper.EVM m :: EVM b
m -> do
b
r <- (VM -> (b, VM)) -> StateT VM IO b
forall s (m :: * -> *) a. MonadState s m => (s -> (a, s)) -> m a
State.state (EVM b -> VM -> (b, VM)
forall s a. State s a -> s -> (a, s)
runState EVM b
m)
(Query -> IO (EVM ()))
-> ProgramT Action Identity a -> StateT VM IO a
forall a. (Query -> IO (EVM ())) -> Stepper a -> StateT VM IO a
interpretWithTrace Query -> IO (EVM ())
fetcher (b -> ProgramT Action Identity a
k b
r)