{-# Language DataKinds #-}

module EVM.Concrete where

import Prelude hiding (Word)
import EVM.RLP
import EVM.Types

import Data.ByteString (ByteString)
import Data.ByteString qualified as BS
import Witch (unsafeInto, into)

byteStringSliceWithDefaultZeroes :: Int -> Int -> ByteString -> ByteString
byteStringSliceWithDefaultZeroes :: Int -> Int -> ByteString -> ByteString
byteStringSliceWithDefaultZeroes Int
offset Int
size ByteString
bs =
  if Int
size Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
0
  then ByteString
""
  else
    let bs' :: ByteString
bs' = Int -> ByteString -> ByteString
BS.take Int
size (Int -> ByteString -> ByteString
BS.drop Int
offset ByteString
bs)
    in ByteString
bs' ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> Int -> Word8 -> ByteString
BS.replicate (Int
size Int -> Int -> Int
forall a. Num a => a -> a -> a
- ByteString -> Int
BS.length ByteString
bs') Word8
0

sliceMemory :: W256 -> W256 -> ByteString -> ByteString
sliceMemory :: W256 -> W256 -> ByteString -> ByteString
sliceMemory W256
o W256
s =
  Int -> Int -> ByteString -> ByteString
byteStringSliceWithDefaultZeroes (W256 -> Int
forall target source.
(HasCallStack, TryFrom source target, Show source, Typeable source,
 Typeable target) =>
source -> target
unsafeInto W256
o) (W256 -> Int
forall target source.
(HasCallStack, TryFrom source target, Show source, Typeable source,
 Typeable target) =>
source -> target
unsafeInto W256
s)

writeMemory :: ByteString -> W256 -> W256 -> W256 -> ByteString -> ByteString
writeMemory :: ByteString -> W256 -> W256 -> W256 -> ByteString -> ByteString
writeMemory ByteString
bs1 W256
n W256
src W256
dst ByteString
bs0 =
  let
    (ByteString
a, ByteString
b) = Int -> ByteString -> (ByteString, ByteString)
BS.splitAt (W256 -> Int
forall target source.
(HasCallStack, TryFrom source target, Show source, Typeable source,
 Typeable target) =>
source -> target
unsafeInto W256
dst) ByteString
bs0
    a' :: ByteString
a'     = Int -> Word8 -> ByteString
BS.replicate (W256 -> Int
forall target source.
(HasCallStack, TryFrom source target, Show source, Typeable source,
 Typeable target) =>
source -> target
unsafeInto W256
dst Int -> Int -> Int
forall a. Num a => a -> a -> a
- ByteString -> Int
BS.length ByteString
a) Word8
0
    -- sliceMemory should work for both cases, but we are using 256 bit
    -- words, whereas ByteString is only defined up to 64 bit. For large n,
    -- src, dst this will cause problems (often in GeneralStateTests).
    -- Later we could reimplement ByteString for 256 bit arguments.
    c :: ByteString
c      = if W256
src W256 -> W256 -> Bool
forall a. Ord a => a -> a -> Bool
> Int -> W256
forall target source.
(HasCallStack, TryFrom source target, Show source, Typeable source,
 Typeable target) =>
source -> target
unsafeInto (ByteString -> Int
BS.length ByteString
bs1)
             then Int -> Word8 -> ByteString
BS.replicate (W256 -> Int
forall target source.
(HasCallStack, TryFrom source target, Show source, Typeable source,
 Typeable target) =>
source -> target
unsafeInto W256
n) Word8
0
             else W256 -> W256 -> ByteString -> ByteString
sliceMemory W256
src W256
n ByteString
bs1
    b' :: ByteString
b'     = Int -> ByteString -> ByteString
BS.drop (W256 -> Int
forall target source.
(HasCallStack, TryFrom source target, Show source, Typeable source,
 Typeable target) =>
source -> target
unsafeInto W256
n) ByteString
b
  in
    ByteString
a ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> ByteString
a' ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> ByteString
c ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> ByteString
b'

createAddress :: Addr -> W64 -> Expr EAddr
createAddress :: Addr -> W64 -> Expr 'EAddr
createAddress Addr
a W64
n = Addr -> Expr 'EAddr
LitAddr (Addr -> Expr 'EAddr) -> ([RLP] -> Addr) -> [RLP] -> Expr 'EAddr
forall b c a. (b -> c) -> (a -> b) -> a -> c
. W256 -> Addr
forall target source.
(HasCallStack, TryFrom source target, Show source, Typeable source,
 Typeable target) =>
source -> target
unsafeInto (W256 -> Addr) -> ([RLP] -> W256) -> [RLP] -> Addr
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> W256
keccak' (ByteString -> W256) -> ([RLP] -> ByteString) -> [RLP] -> W256
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [RLP] -> ByteString
rlpList ([RLP] -> Expr 'EAddr) -> [RLP] -> Expr 'EAddr
forall a b. (a -> b) -> a -> b
$ [Addr -> RLP
rlpAddrFull Addr
a, W256 -> RLP
rlpWord256 (W64 -> W256
forall target source. From source target => source -> target
into W64
n)]

create2Address :: Addr -> W256 -> ByteString -> Expr EAddr
create2Address :: Addr -> W256 -> ByteString -> Expr 'EAddr
create2Address Addr
a W256
s ByteString
b = Addr -> Expr 'EAddr
LitAddr (Addr -> Expr 'EAddr) -> Addr -> Expr 'EAddr
forall a b. (a -> b) -> a -> b
$ W256 -> Addr
forall target source.
(HasCallStack, TryFrom source target, Show source, Typeable source,
 Typeable target) =>
source -> target
unsafeInto (W256 -> Addr) -> W256 -> Addr
forall a b. (a -> b) -> a -> b
$ ByteString -> W256
keccak' (ByteString -> W256) -> ByteString -> W256
forall a b. (a -> b) -> a -> b
$ [ByteString] -> ByteString
forall a. Monoid a => [a] -> a
mconcat
  [Word8 -> ByteString
BS.singleton Word8
0xff, Addr -> ByteString
word160Bytes Addr
a, W256 -> ByteString
word256Bytes W256
s, W256 -> ByteString
word256Bytes (W256 -> ByteString) -> W256 -> ByteString
forall a b. (a -> b) -> a -> b
$ ByteString -> W256
keccak' ByteString
b]