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.State.Class (MonadState)
import Control.Monad.State.Strict (runState)
import Data.ByteString (ByteString)
import Data.Maybe (isNothing)

import qualified Control.Monad.State.Class as State

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
    { vmoptContract :: Contract
vmoptContract = ContractCode -> Contract
initialContract (ByteString -> Expr 'Buf -> ContractCode
InitCode ByteString
creationCode forall a. Monoid a => a
mempty)
    , vmoptCalldata :: (Expr 'Buf, [Prop])
vmoptCalldata = forall a. Monoid a => a
mempty
    , vmoptValue :: Expr 'EWord
vmoptValue = (W256 -> Expr 'EWord
Lit W256
0)
    , vmoptStorageBase :: StorageBase
vmoptStorageBase = StorageBase
Concrete
    , vmoptAddress :: Addr
vmoptAddress = Addr -> W256 -> Addr
createAddress Addr
ethrunAddress W256
1
    , vmoptCaller :: Expr 'EWord
vmoptCaller = Addr -> Expr 'EWord
litAddr Addr
ethrunAddress
    , vmoptOrigin :: Addr
vmoptOrigin = Addr
ethrunAddress
    , vmoptCoinbase :: Addr
vmoptCoinbase = Addr
0
    , vmoptNumber :: W256
vmoptNumber = W256
0
    , vmoptTimestamp :: Expr 'EWord
vmoptTimestamp = (W256 -> Expr 'EWord
Lit W256
0)
    , vmoptBlockGaslimit :: Word64
vmoptBlockGaslimit = Word64
0
    , vmoptGasprice :: W256
vmoptGasprice = W256
0
    , vmoptPrevRandao :: W256
vmoptPrevRandao = W256
42069
    , vmoptGas :: Word64
vmoptGas = Word64
0xffffffffffffffff
    , vmoptGaslimit :: Word64
vmoptGaslimit = Word64
0xffffffffffffffff
    , vmoptBaseFee :: W256
vmoptBaseFee = W256
0
    , vmoptPriorityFee :: W256
vmoptPriorityFee = W256
0
    , vmoptMaxCodeSize :: W256
vmoptMaxCodeSize = W256
0xffffffff
    , vmoptSchedule :: FeeSchedule Word64
vmoptSchedule = forall n. Num n => FeeSchedule n
FeeSchedule.berlin
    , vmoptChainId :: W256
vmoptChainId = W256
1
    , vmoptCreate :: Bool
vmoptCreate = Bool
False
    , vmoptTxAccessList :: Map Addr [W256]
vmoptTxAccessList = forall a. Monoid a => a
mempty
    , vmoptAllowFFI :: 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 :: MonadState VM m => m VMResult
exec :: forall (m :: * -> *). MonadState VM m => m VMResult
exec =
  forall s (m :: * -> *) a. MonadState s m => Getting a s a -> m a
use Lens' VM (Maybe VMResult)
EVM.result forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
    Maybe VMResult
Nothing -> forall s (m :: * -> *) a. MonadState s m => (s -> (a, s)) -> m a
State.state (forall s a. State s a -> s -> (a, s)
runState EVM ()
exec1) forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> forall (m :: * -> *). MonadState VM m => m VMResult
exec
    Just VMResult
x  -> forall (m :: * -> *) a. Monad m => a -> m a
return VMResult
x

run :: MonadState VM m => m VM
run :: forall (m :: * -> *). MonadState VM m => m VM
run =
  forall s (m :: * -> *) a. MonadState s m => Getting a s a -> m a
use Lens' VM (Maybe VMResult)
EVM.result forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
    Maybe VMResult
Nothing -> forall s (m :: * -> *) a. MonadState s m => (s -> (a, s)) -> m a
State.state (forall s a. State s a -> s -> (a, s)
runState EVM ()
exec1) forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> forall (m :: * -> *). MonadState VM m => m VM
run
    Just VMResult
_  -> forall s (m :: * -> *). MonadState s m => m s
State.get

execWhile :: MonadState VM m => (VM -> Bool) -> m Int
execWhile :: forall (m :: * -> *). MonadState VM m => (VM -> Bool) -> m Int
execWhile VM -> Bool
p = Int -> m Int
go Int
0
  where
    go :: Int -> m Int
go Int
i = do
      VM
x <- forall s (m :: * -> *). MonadState s m => m s
State.get
      if VM -> Bool
p VM
x Bool -> Bool -> Bool
&& forall a. Maybe a -> Bool
isNothing (forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view Lens' VM (Maybe VMResult)
result VM
x)
        then do
          forall s (m :: * -> *) a. MonadState s m => (s -> (a, s)) -> m a
State.state (forall s a. State s a -> s -> (a, s)
runState EVM ()
exec1)
          Int -> m Int
go forall a b. (a -> b) -> a -> b
$! (Int
i forall a. Num a => a -> a -> a
+ Int
1)
      else
        forall (m :: * -> *) a. Monad m => a -> m a
return Int
i