module EVM.Concrete where import Prelude hiding (Word) import EVM.RLP import EVM.Types import Control.Lens ((^?), ix) import Data.Bits (Bits (..), shiftR) import Data.ByteString (ByteString) import Data.Maybe (fromMaybe) import Data.Word (Word8) import qualified Data.ByteString as BS wordAt :: Int -> ByteString -> W256 wordAt i bs = word (padRight 32 (BS.drop i bs)) readByteOrZero :: Int -> ByteString -> Word8 readByteOrZero i bs = fromMaybe 0 (bs ^? ix i) byteStringSliceWithDefaultZeroes :: Int -> Int -> ByteString -> ByteString byteStringSliceWithDefaultZeroes offset size bs = if size == 0 then "" -- else if offset > BS.length bs -- then BS.replicate size 0 -- todo: this ^^ should work, investigate why it causes more GST fails else let bs' = BS.take size (BS.drop offset bs) in bs' <> BS.replicate (size - BS.length bs') 0 sliceMemory :: (Integral a, Integral b) => a -> b -> ByteString -> ByteString sliceMemory o s = byteStringSliceWithDefaultZeroes (num o) (num s) writeMemory :: ByteString -> W256 -> W256 -> W256 -> ByteString -> ByteString writeMemory bs1 n src dst bs0 = let (a, b) = BS.splitAt (num dst) bs0 a' = BS.replicate (num dst - BS.length a) 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 = if src > num (BS.length bs1) then BS.replicate (num n) 0 else sliceMemory src n bs1 b' = BS.drop (num n) b in a <> a' <> c <> b' -- Copied from the standard library just to get specialization. -- We also use bit operations instead of modulo and multiply. -- (This operation was significantly slow.) (^) :: W256 -> W256 -> W256 x0 ^ y0 | y0 < 0 = errorWithoutStackTrace "Negative exponent" | y0 == 0 = 1 | otherwise = f x0 y0 where f x y | not (testBit y 0) = f (x * x) (y `shiftR` 1) | y == 1 = x | otherwise = g (x * x) ((y - 1) `shiftR` 1) x g x y z | not (testBit y 0) = g (x * x) (y `shiftR` 1) z | y == 1 = x * z | otherwise = g (x * x) ((y - 1) `shiftR` 1) (x * z) createAddress :: Addr -> W256 -> Addr createAddress a n = num $ keccak' $ rlpList [rlpAddrFull a, rlpWord256 n] create2Address :: Addr -> W256 -> ByteString -> Addr create2Address a s b = num $ keccak' $ mconcat [BS.singleton 0xff, word160Bytes a, word256Bytes s, word256Bytes $ keccak' b]