module EVM.Exec where

import EVM
import EVM.Concrete (createAddress)
import EVM.Types
import EVM.Expr (litAddr)

import qualified EVM.FeeSchedule as FeeSchedule

import Control.Lens
import Control.Monad.Trans.State.Strict (get, State)
import Data.ByteString (ByteString)
import Data.Maybe (isNothing)


ethrunAddress :: Addr
ethrunAddress :: Addr
ethrunAddress = Word160 -> Addr
Addr Word160
0x00a329c0648769a73afac7f9381e08fb43dbea72

vmForEthrunCreation :: ByteString -> VM
vmForEthrunCreation :: ByteString -> VM
vmForEthrunCreation ByteString
creationCode =
  (VMOpts -> VM
makeVm forall a b. (a -> b) -> a -> b
$ VMOpts
    { $sel:vmoptContract:VMOpts :: Contract
vmoptContract = ContractCode -> Contract
initialContract (ByteString -> Expr 'Buf -> ContractCode
InitCode ByteString
creationCode forall a. Monoid a => a
mempty)
    , $sel:vmoptCalldata:VMOpts :: (Expr 'Buf, [Prop])
vmoptCalldata = forall a. Monoid a => a
mempty
    , $sel:vmoptValue:VMOpts :: Expr 'EWord
vmoptValue = (W256 -> Expr 'EWord
Lit W256
0)
    , $sel:vmoptStorageBase:VMOpts :: StorageBase
vmoptStorageBase = StorageBase
Concrete
    , $sel:vmoptAddress:VMOpts :: Addr
vmoptAddress = Addr -> W256 -> Addr
createAddress Addr
ethrunAddress W256
1
    , $sel:vmoptCaller:VMOpts :: Expr 'EWord
vmoptCaller = Addr -> Expr 'EWord
litAddr Addr
ethrunAddress
    , $sel:vmoptOrigin:VMOpts :: Addr
vmoptOrigin = Addr
ethrunAddress
    , $sel:vmoptCoinbase:VMOpts :: Addr
vmoptCoinbase = Addr
0
    , $sel:vmoptNumber:VMOpts :: W256
vmoptNumber = W256
0
    , $sel:vmoptTimestamp:VMOpts :: Expr 'EWord
vmoptTimestamp = (W256 -> Expr 'EWord
Lit W256
0)
    , $sel:vmoptBlockGaslimit:VMOpts :: Word64
vmoptBlockGaslimit = Word64
0
    , $sel:vmoptGasprice:VMOpts :: W256
vmoptGasprice = W256
0
    , $sel:vmoptPrevRandao:VMOpts :: W256
vmoptPrevRandao = W256
42069
    , $sel:vmoptGas:VMOpts :: Word64
vmoptGas = Word64
0xffffffffffffffff
    , $sel:vmoptGaslimit:VMOpts :: Word64
vmoptGaslimit = Word64
0xffffffffffffffff
    , $sel:vmoptBaseFee:VMOpts :: W256
vmoptBaseFee = W256
0
    , $sel:vmoptPriorityFee:VMOpts :: W256
vmoptPriorityFee = W256
0
    , $sel:vmoptMaxCodeSize:VMOpts :: W256
vmoptMaxCodeSize = W256
0xffffffff
    , $sel:vmoptSchedule:VMOpts :: FeeSchedule Word64
vmoptSchedule = forall n. Num n => FeeSchedule n
FeeSchedule.berlin
    , $sel:vmoptChainId:VMOpts :: W256
vmoptChainId = W256
1
    , $sel:vmoptCreate:VMOpts :: Bool
vmoptCreate = Bool
False
    , $sel:vmoptTxAccessList:VMOpts :: Map Addr [W256]
vmoptTxAccessList = forall a. Monoid a => a
mempty
    , $sel:vmoptAllowFFI:VMOpts :: Bool
vmoptAllowFFI = Bool
False
    }) forall a b. a -> (a -> b) -> b
& forall s t a b. ASetter s t a b -> b -> s -> t
set (Lens' VM Env
env forall b c a. (b -> c) -> (a -> b) -> a -> c
. Lens' Env (Map Addr Contract)
contracts forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall m. At m => Index m -> Lens' m (Maybe (IxValue m))
at Addr
ethrunAddress)
             (forall a. a -> Maybe a
Just (ContractCode -> Contract
initialContract (RuntimeCode -> ContractCode
RuntimeCode (ByteString -> RuntimeCode
ConcreteRuntimeCode ByteString
""))))

exec :: State VM VMResult
exec :: State VM VMResult
exec = do
  VM
vm <- forall (m :: * -> *) s. Monad m => StateT s m s
get
  case VM
vm._result of
    Maybe VMResult
Nothing -> EVM ()
exec1 forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> State VM VMResult
exec
    Just VMResult
r -> forall (f :: * -> *) a. Applicative f => a -> f a
pure VMResult
r

run :: State VM VM
run :: State VM VM
run = do
  VM
vm <- forall (m :: * -> *) s. Monad m => StateT s m s
get
  case VM
vm._result of
    Maybe VMResult
Nothing -> EVM ()
exec1 forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> State VM VM
run
    Just VMResult
_ -> forall (f :: * -> *) a. Applicative f => a -> f a
pure VM
vm

execWhile :: (VM -> Bool) -> State VM Int
execWhile :: (VM -> Bool) -> State VM Int
execWhile VM -> Bool
p = Int -> State VM Int
go Int
0
  where
    go :: Int -> State VM Int
go Int
i = do
      VM
vm <- forall (m :: * -> *) s. Monad m => StateT s m s
get
      if VM -> Bool
p VM
vm Bool -> Bool -> Bool
&& forall a. Maybe a -> Bool
isNothing VM
vm._result
        then do
          Int -> State VM Int
go forall a b. (a -> b) -> a -> b
$! (Int
i forall a. Num a => a -> a -> a
+ Int
1)
      else
        forall (f :: * -> *) a. Applicative f => a -> f a
pure Int
i