module EVM.Debug where import EVM (bytecode) import EVM.Expr (bufLength) import EVM.Solidity (SrcMap(..), SourceCache(..)) import EVM.Types (Contract(..), Addr) import Control.Arrow (second) import Data.ByteString (ByteString) import Data.ByteString qualified as ByteString import Data.Map (Map) import Data.Map qualified as Map import Optics.Core import Text.PrettyPrint.ANSI.Leijen import Witch (unsafeInto) data Mode = Debug | Run | JsonTrace deriving (Mode -> Mode -> Bool forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a /= :: Mode -> Mode -> Bool $c/= :: Mode -> Mode -> Bool == :: Mode -> Mode -> Bool $c== :: Mode -> Mode -> Bool Eq, Int -> Mode -> ShowS [Mode] -> ShowS Mode -> FilePath forall a. (Int -> a -> ShowS) -> (a -> FilePath) -> ([a] -> ShowS) -> Show a showList :: [Mode] -> ShowS $cshowList :: [Mode] -> ShowS show :: Mode -> FilePath $cshow :: Mode -> FilePath showsPrec :: Int -> Mode -> ShowS $cshowsPrec :: Int -> Mode -> ShowS Show) object :: [(Doc, Doc)] -> Doc object :: [(Doc, Doc)] -> Doc object [(Doc, Doc)] xs = Doc -> Doc group forall a b. (a -> b) -> a -> b $ Doc lbrace forall a. Semigroup a => a -> a -> a <> Doc line forall a. Semigroup a => a -> a -> a <> Int -> Doc -> Doc indent Int 2 ([Doc] -> Doc sep (Doc -> [Doc] -> [Doc] punctuate (Char -> Doc char Char ';') [Doc k Doc -> Doc -> Doc <+> Doc equals Doc -> Doc -> Doc <+> Doc v | (Doc k, Doc v) <- [(Doc, Doc)] xs])) forall a. Semigroup a => a -> a -> a <> Doc line forall a. Semigroup a => a -> a -> a <> Doc rbrace prettyContract :: Contract -> Doc prettyContract :: Contract -> Doc prettyContract Contract c = [(Doc, Doc)] -> Doc object [ (FilePath -> Doc text FilePath "codesize", FilePath -> Doc text forall b c a. (b -> c) -> (a -> b) -> a -> c . forall a. Show a => a -> FilePath show forall a b. (a -> b) -> a -> b $ (Expr 'Buf -> Expr 'EWord bufLength (Contract c forall k s (is :: IxList) a. Is k A_Getter => s -> Optic' k is s a -> a ^. Getter Contract (Expr 'Buf) bytecode))) , (FilePath -> Doc text FilePath "codehash", FilePath -> Doc text (forall a. Show a => a -> FilePath show Contract c.codehash)) , (FilePath -> Doc text FilePath "balance", Int -> Doc int (forall target source. (HasCallStack, TryFrom source target, Show source, Typeable source, Typeable target) => source -> target unsafeInto Contract c.balance)) , (FilePath -> Doc text FilePath "nonce", Int -> Doc int (forall target source. (HasCallStack, TryFrom source target, Show source, Typeable source, Typeable target) => source -> target unsafeInto Contract c.nonce)) ] prettyContracts :: Map Addr Contract -> Doc prettyContracts :: Map Addr Contract -> Doc prettyContracts Map Addr Contract x = [(Doc, Doc)] -> Doc object (forall a b. (a -> b) -> [a] -> [b] map (\(Addr a, Contract b) -> (FilePath -> Doc text (forall a. Show a => a -> FilePath show Addr a), Contract -> Doc prettyContract Contract b)) (forall k a. Map k a -> [(k, a)] Map.toList Map Addr Contract x)) srcMapCodePos :: SourceCache -> SrcMap -> Maybe (FilePath, Int) srcMapCodePos :: SourceCache -> SrcMap -> Maybe (FilePath, Int) srcMapCodePos SourceCache cache SrcMap sm = forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b fmap (forall (a :: * -> * -> *) b c d. Arrow a => a b c -> a (d, b) (d, c) second ByteString -> Int f) forall a b. (a -> b) -> a -> b $ SourceCache cache.files forall k s (is :: IxList) a. Is k An_AffineFold => s -> Optic' k is s a -> Maybe a ^? forall m. Ixed m => Index m -> Optic' (IxKind m) NoIx m (IxValue m) ix SrcMap sm.file where f :: ByteString -> Int f ByteString v = Word8 -> ByteString -> Int ByteString.count Word8 0xa (Int -> ByteString -> ByteString ByteString.take SrcMap sm.offset ByteString v) forall a. Num a => a -> a -> a + Int 1 srcMapCode :: SourceCache -> SrcMap -> Maybe ByteString srcMapCode :: SourceCache -> SrcMap -> Maybe ByteString srcMapCode SourceCache cache SrcMap sm = forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b fmap (FilePath, ByteString) -> ByteString f forall a b. (a -> b) -> a -> b $ SourceCache cache.files forall k s (is :: IxList) a. Is k An_AffineFold => s -> Optic' k is s a -> Maybe a ^? forall m. Ixed m => Index m -> Optic' (IxKind m) NoIx m (IxValue m) ix SrcMap sm.file where f :: (FilePath, ByteString) -> ByteString f (FilePath _, ByteString v) = Int -> ByteString -> ByteString ByteString.take (forall a. Ord a => a -> a -> a min Int 80 SrcMap sm.length) (Int -> ByteString -> ByteString ByteString.drop SrcMap sm.offset ByteString v)