packages feed

ethereum-analyzer 3.3.0 → 3.3.1

raw patch · 18 files changed

+258/−227 lines, 18 files

Files

ChangeLog.md view
@@ -1,3 +1,9 @@+3.3.1 / 2017-12-24+==================++ * Replace usage of String with Text.+ * Fix the name collision bug that causes a Hackage build failure.+ TODOs ==================   * Support struct type.
ethereum-analyzer.cabal view
@@ -1,5 +1,5 @@ name:                ethereum-analyzer-version:             3.3.0+version:             3.3.1 synopsis:            A Ethereum contract analyzer. homepage:            https://github.com/zchn/ethereum-analyzer license:             Apache-2.0@@ -21,7 +21,7 @@ source-repository this   type:     git   location: https://github.com/zchn/ethereum-analyzer-  tag:      v3.3.0+  tag:      v3.3.1   subdir:   ethereum-analyzer  library@@ -49,6 +49,7 @@                      , Ethereum.Analyzer.Debug                      , Ethereum.Analyzer.Solidity                      , Ethereum.Analyzer.Util+                     , Ckev.In.Text   other-modules:       Ethereum.Analyzer.EVM.IR                      , Ethereum.Analyzer.EVM.CfgAugmentPass                      , Ethereum.Analyzer.EVM.CfgAugWithTopNPass
+ src/Ckev/In/Text.hs view
@@ -0,0 +1,22 @@+{-# LANGUAGE CPP, RankNTypes, GADTs, ScopedTypeVariables, FlexibleContexts #-}+module Ckev.In.Text ( ShowText(..)+                    , showT+                    , showGraphT) where++import Protolude hiding (show)++import Compiler.Hoopl+import GHC.Show (Show(..))++showT :: (Show a) => a -> Text+showT = toS . show++class ShowText a where+  showText :: a -> Text++-- Compiler.Hoopl++type ShowingT n = forall e x . n e x -> Text++showGraphT :: forall n e x . ShowingT n -> Graph n e x -> Text+showGraphT n = toS . (showGraph $ toS . n)
src/Ethereum/Analyzer/Common.hs view
@@ -13,7 +13,7 @@ import Blockchain.ExtWord import Data.ByteString as DB import Data.Either (Either(..))-import GHC.Show (Show(..))+import Ckev.In.Text  fromRight :: b -> Either a b -> b fromRight _ (Right v) = v@@ -23,12 +23,12 @@ s2t4Either (Left s) = Left $ toS s s2t4Either (Right r) = Right r -unexpectedPanic :: Show a => a -> b-unexpectedPanic n = panic . toS $ "unexpected: " <> show n <> show callStack+unexpectedPanic :: ShowText a => a -> b+unexpectedPanic n = panic $ "unexpected: " <> showText n -unimplementedPanic :: Show a => a -> b+unimplementedPanic :: ShowText a => a -> b unimplementedPanic n =-  panic . toS $ "unimplemented: " <> show n <> show callStack+  panic $ "unimplemented: " <> showText n  varBytesToWord256 :: [Word8] -> Word256 varBytesToWord256 w8l =
src/Ethereum/Analyzer/Debug.hs view
@@ -7,7 +7,7 @@  import Protolude hiding (show) -import GHC.Show (Show(..))+import Ckev.In.Text  import Ethereum.Analyzer.Solidity import Text.PrettyPrint.Leijen.Text as PP hiding ((<$>))@@ -27,4 +27,4 @@ pprintContracts = putDoc . pretty  prettyContracts :: [Contract] -> Text-prettyContracts = toS . show . pretty+prettyContracts = showT . pretty
src/Ethereum/Analyzer/EVM/CfgAugWithTopNPass.hs view
@@ -19,7 +19,7 @@ import Ethereum.Analyzer.Common import Ethereum.Analyzer.EVM.Disasm import Ethereum.Analyzer.EVM.IR-import GHC.Show+import Ckev.In.Text import Legacy.Haskoin.V0102.Network.Haskoin.Crypto.BigWord  type StackElemFact = WithTop (Set Word256)@@ -265,14 +265,14 @@     -- opT DATA ByteString flist = flist     -- opT MalformedOpcode Word8 flist = flist     opT op@LABEL {} _ =-      panic $ "Unexpected(stackTopTransfer): " <> toS (show op)+      panic $ "Unexpected(stackTopTransfer): " <> toS (showT op)     opT op@PUSHLABEL {} _ =-      panic $ "Unexpected(stackTopTransfer): " <> toS (show op)+      panic $ "Unexpected(stackTopTransfer): " <> toS (showT op)     opT op@PUSHDIFF {} _ =-      panic $ "Unexpected(stackTopTransfer): " <> toS (show op)-    opT op@DATA {} _ = panic $ "Unexpected(stackTopTransfer): " <> toS (show op)+      panic $ "Unexpected(stackTopTransfer): " <> toS (showT op)+    opT op@DATA {} _ = panic $ "Unexpected(stackTopTransfer): " <> toS (showT op)     opT op@MalformedOpcode {} _ =-      panic $ "Unexpected(stackTopTransfer): " <> toS (show op)+      panic $ "Unexpected(stackTopTransfer): " <> toS (showT op)     -- TODO(zchn): Implement interp     opT _ flist = DL.map (const Top) flist @@ -382,4 +382,4 @@     _ ->       panic $       "doCfgAugWithTopNPass: unexpected newHexstrings length: " <>-      toS (show (DL.length newHexstrings))+      toS (showT (DL.length newHexstrings))
src/Ethereum/Analyzer/EVM/CfgAugmentPass.hs view
@@ -17,7 +17,7 @@ import Data.Set as DS hiding (toList) import Ethereum.Analyzer.Common import Ethereum.Analyzer.EVM.IR-import GHC.Show+import Ckev.In.Text  type StackTopFact = WithTop (Set Word256) @@ -74,14 +74,14 @@       PElem $ DS.map (bytesToWord256 . DL.map complement . word256ToBytes) st     opT (PUSH w8l) _ = PElem $ DS.singleton $ varBytesToWord256 w8l     opT op@LABEL {} _ =-      panic $ "Unexpected(stackTopTransfer): " <> toS (show op)+      panic $ "Unexpected(stackTopTransfer): " <> toS (showT op)     opT op@PUSHLABEL {} _ =-      panic $ "Unexpected(stackTopTransfer): " <> toS (show op)+      panic $ "Unexpected(stackTopTransfer): " <> toS (showT op)     opT op@PUSHDIFF {} _ =-      panic $ "Unexpected(stackTopTransfer): " <> toS (show op)-    opT op@DATA {} _ = panic $ "Unexpected(stackTopTransfer): " <> toS (show op)+      panic $ "Unexpected(stackTopTransfer): " <> toS (showT op)+    opT op@DATA {} _ = panic $ "Unexpected(stackTopTransfer): " <> toS (showT op)     opT op@MalformedOpcode {} _ =-      panic $ "Unexpected(stackTopTransfer): " <> toS (show op)+      panic $ "Unexpected(stackTopTransfer): " <> toS (showT op)     opT _ _ = Top  opGUnit :: HplOp e x -> Graph HplOp e x
src/Ethereum/Analyzer/EVM/IR.hs view
@@ -23,19 +23,14 @@ import Blockchain.VM.Opcodes as BVO import Compiler.Hoopl as CH --- import Control.Monad as CM import Data.Bimap as DB-import Data.List as DL-import Data.String (String)---- import Data.Graph.Inductive.Graph as DGIG import qualified Data.Text.Lazy as DTL-import GHC.Show+import Ckev.In.Text import Legacy.Haskoin.V0102.Network.Haskoin.Crypto.BigWord  newtype MyLabel = MyLabel   { unMyLabel :: Label-  } deriving (Eq)+  } deriving (Eq, Show)  data HplOp e x where   CoOp :: Label -> HplOp C O@@ -45,22 +40,22 @@   HpEnd :: MyLabel -> HplOp O C   HpCodeCopy :: Word256 -> HplOp O O -showLoc :: Word256 -> String-showLoc = show . getBigWordInteger+showLoc :: Word256 -> Text+showLoc = showT . getBigWordInteger -showOp :: (Word256, Operation) -> String-showOp (lineNo, op) = showLoc lineNo <> ": " <> show op+showOp :: (Word256, Operation) -> Text+showOp (lineNo, op) = showLoc lineNo <> ": " <> showT op -showOps :: [(Word256, Operation)] -> [String]+showOps :: [(Word256, Operation)] -> [Text] showOps = fmap showOp -instance Show (HplOp e x) where-  show (CoOp l) = "CO: " <> show l-  show (OoOp op) = "OO: " <> showOp op-  show (OcOp op ll) = "OC: " <> showOp op <> " -> " <> show ll-  show (HpJump _ l) = "OC: HpJump -> " <> show l-  show HpEnd {} = "OC: HpEnd"-  show (HpCodeCopy offset) = "HpCodeCopy " <> show offset+instance ShowText (HplOp e x) where+  showText (CoOp l) = "CO: " <> showT l+  showText (OoOp op) = "OO: " <> showOp op+  showText (OcOp op ll) = "OC: " <> showOp op <> " -> " <> showT ll+  showText (HpJump _ l) = "OC: HpJump -> " <> showT l+  showText HpEnd {} = "OC: HpEnd"+  showText (HpCodeCopy offset) = "HpCodeCopy " <> showT offset  instance Eq (HplOp C O) where   (==) (CoOp a) (CoOp b) = a == b@@ -84,13 +79,16 @@  type HplCfg = Graph HplOp O C -instance Show HplCfg where-  show = showGraph show+instance ShowText HplCfg where+  showText = showGraphT showText  data HplContract = HplContract   { ctorOf :: HplCfg   , dispatcherOf :: HplCfg-  } deriving (Show)+  }++instance ShowText HplContract where+  showText c = showT [showText $ ctorOf c, showText $ dispatcherOf c]  emptyHplCfg :: UniqueMonad m => m HplCfg emptyHplCfg = do
src/Ethereum/Analyzer/Solidity/AstJson.hs view
@@ -13,7 +13,7 @@ import Data.Aeson.Types import Data.HashMap.Lazy hiding (map) import Ethereum.Analyzer.Common-import GHC.Show (Show(..))+import Ckev.In.Text import Text.PrettyPrint.Leijen.Text as PP  decodeSoleNodes :: LByteString -> Either Text [SolNode]@@ -57,6 +57,9 @@   , visibility :: Maybe Text   , children :: Maybe [SolNode]   } deriving (Eq, Generic, Show)++instance ShowText SolNode where+  showText = showT  instance ToJSON SolNode where   toJSON =
src/Ethereum/Analyzer/Solidity/Hoople.hs view
@@ -10,9 +10,9 @@  import Compiler.Hoopl import Ethereum.Analyzer.Solidity.Simple-import GHC.Show (Show(..))+import Ckev.In.Text import Text.PrettyPrint.Leijen.Text hiding ((<$>))-import qualified Text.PrettyPrint.Leijen.Text as PP+-- import qualified Text.PrettyPrint.Leijen.Text as PP  data HContract = HContract   { hcName :: Text@@ -32,7 +32,7 @@   }  instance Pretty Label where-  pretty = textStrict . toS . show+  pretty = textStrict . toS . showT  data HStatement e x where   CoSt :: Label -> HStatement C O@@ -50,8 +50,8 @@   pretty (OcSt st ll) = pretty st <+> textStrict "->" <+> prettyList ll   pretty (OcJump l) = textStrict "jump" <+> textStrict "->" <+> pretty l -instance Show (HStatement e x) where-  show = show . pretty+instance ShowText (HStatement e x) where+  showText = showT . pretty  instance NonLocal HStatement where   entryLabel (CoSt lbl) = lbl
src/Ethereum/Analyzer/Solidity/Simple.hs view
@@ -15,15 +15,15 @@   , decodeContracts   ) where -import Protolude hiding (show)+import Protolude hiding ((<>), show)  import Compiler.Hoopl import Data.Text (replace) import Ethereum.Analyzer.Common import Ethereum.Analyzer.Solidity.AstJson-import GHC.Show (Show(..))+import Ckev.In.Text import Text.PrettyPrint.Leijen.Text hiding ((<$>))-import qualified Text.PrettyPrint.Leijen.Text as PP+-- import qualified Text.PrettyPrint.Leijen.Text as PP  decodeContracts :: Text -> Either Text [Contract] decodeContracts astJsonText = do@@ -70,6 +70,9 @@   | Tuple [LValue]   deriving (Eq, Generic, Show) +instance ShowText LValue where+  showText = showT+ instance Pretty LValue where   pretty (JustId v) = pretty v   pretty (Index a i) = pretty a <> brackets (pretty i)@@ -224,25 +227,24 @@                       } = concat <$> mapM s2sStatements sChildren s2sStatements SolNode { name = Just "Assignment"                       , children = Just [lval, rval]-                      , attributes = Just SolNode {operator = Just op}+                      , attributes = Just SolNode {operator = Just _}                       } = do   (prelval, simpleLval) <- s2sLval lval   (prerval, simpleRval) <- s2sLval rval   return $ prerval <> prelval <> [StAssign simpleLval $ ExpLval simpleRval]-s2sStatements e@SolNode {name = Just "Return", children = ch} = do+s2sStatements SolNode {name = Just "Return", children = ch} = do   let sChildren = fromMaybe [] ch   presAndRvals <- mapM s2sLval sChildren   let prerval = concatMap fst presAndRvals   let simpleRvals = map snd presAndRvals   return $ prerval <> [StReturn simpleRvals]-s2sStatements e@SolNode { name = Just "UnaryOperation"+s2sStatements SolNode { name = Just "UnaryOperation"                         , children = Just [op1]                         , attributes = Just SolNode {operator = Just "delete"}                         } = do   (preOp1, lvalOp1) <- s2sLval op1-  newVar <- uniqueVar-  return $ preOp1 <> [StDelete (JustId $ Idfr newVar)]-s2sStatements e@SolNode { name = Just "UnaryOperation"+  return $ preOp1 <> [StDelete lvalOp1]+s2sStatements SolNode { name = Just "UnaryOperation"                         , children = Just [SolNode { name = Just "Identifier"                                                    , attributes = Just SolNode {value = Just idName}                                                    }]@@ -253,7 +255,7 @@   let newidfr = JustId $ Idfr newVar   return     [StAssign newidfr $ ExpLiteral "1", StAssign idfr $ ExpBin "+" idfr newidfr]-s2sStatements e@SolNode { name = Just "UnaryOperation"+s2sStatements SolNode { name = Just "UnaryOperation"                         , children = Just [op1]                         , attributes = Just SolNode {operator = Just "++"}                         } = do@@ -276,7 +278,7 @@   let newidfr = JustId $ Idfr newVar   return     [StAssign newidfr $ ExpLiteral "1", StAssign idfr $ ExpBin "-" idfr newidfr]-s2sStatements e@SolNode { name = Just "UnaryOperation"+s2sStatements SolNode { name = Just "UnaryOperation"                         , children = Just [op1]                         , attributes = Just SolNode {operator = Just "--"}                         } = do@@ -357,7 +359,7 @@                 } = do   (prelval, simpleLval) <- s2sLval obj   return (prelval, Member simpleLval (Idfr mName))-s2sLval n@SolNode {name = Just "IndexAccess", children = Just (c1:ctail)} = do+s2sLval SolNode {name = Just "IndexAccess", children = Just (c1:ctail)} = do   (prelval, simpleLval) <- s2sLval c1   (presub, simpleLvalSub) <- handleSubscription simpleLval ctail   return (presub <> prelval, Index simpleLval simpleLvalSub)@@ -450,10 +452,10 @@ s2sLval n = unimplementedPanic n {children = Nothing}  uniqueVar :: UniqueMonad m => m Text-uniqueVar = ("v" <>) . toS . show <$> freshUnique+uniqueVar = ("v" <>) . toS . showT <$> freshUnique  -- lastLvalOf :: [Statement] -> LValue -- lastLvalOf [_, StAssign lval _] = lval -- lastLvalOf (_ : t) = lastLvalOf t -- lastLvalOf _ = errorLValue-errorLValue = JustId (Idfr "ERROR!")+-- errorLValue = JustId (Idfr "ERROR!")
src/Ethereum/Analyzer/Util.hs view
@@ -9,21 +9,21 @@ import Protolude hiding (show)  import Compiler.Hoopl as CH+import Ckev.In.Text import Data.Graph.Inductive.Graph as DGIG import Data.Graph.Inductive.PatriciaTree import Data.GraphViz import Data.GraphViz.Printing hiding ((<>))-import qualified Data.List as DL+import qualified Data.Text as DT import qualified Data.Text.Lazy as DTL-import GHC.Show import Text.Read (read) -instance (Show (n C O), Show (n O O), Show (n O C)) => Show (Block n C C) where-  show a =+instance (ShowText (n C O), ShowText (n O O), ShowText (n O C)) => ShowText (Block n C C) where+  showText a =     let (h, m, t) = blockSplit a-    in DL.unlines $ [show h] <> map show (blockToList m) <> [show t]+    in DT.unlines $ [showText h] <> map showText (blockToList m) <> [showText t] -toDotText :: (NonLocal n, Show (Block n C C)) => CH.Graph n O C -> Text+toDotText :: (NonLocal n, ShowText (Block n C C)) => CH.Graph n O C -> Text toDotText bd =   let bdGr = toGr bd       dotG = toDotGraph bdGr@@ -32,7 +32,7 @@  toGr :: NonLocal n => CH.Graph n O C -> Gr (Block n C C) () toGr bd =-  let lblToNode l = read (drop 1 $ toS $ show l)+  let lblToNode l = read (drop 1 $ toS $ showT l)       blocks = postorder_dfs bd       (nList, eList) =         foldr@@ -45,13 +45,13 @@   in mkGraph nList eList  visParams ::-     (Show (Block n C C)) => GraphvizParams p (Block n C C) el () (Block n C C)+     (ShowText (Block n C C)) => GraphvizParams p (Block n C C) el () (Block n C C) visParams =   nonClusteredParams   { fmtNode =       \(_, nl) ->-        [textLabel (DTL.replace "\n" "\\l" $ toS $ show nl), shape BoxShape]+        [textLabel (DTL.replace "\n" "\\l" $ toS $ showText nl), shape BoxShape]   } -toDotGraph :: (Show (Block n C C)) => Gr (Block n C C) () -> DotGraph Node+toDotGraph :: (ShowText (Block n C C)) => Gr (Block n C C) () -> DotGraph Node toDotGraph = graphToDot visParams
test/Ethereum/Analyzer/EVM/CfgAugWithTopNPassSpec.hs view
@@ -10,7 +10,7 @@ import Data.Text as DT import Ethereum.Analyzer.EVM import Ethereum.Analyzer.TestData.Basic-import GHC.Show+import Ckev.In.Text import Test.Hspec  spec :: Spec@@ -18,11 +18,11 @@   describe "doCfgAugWithTopNPass" $ do     it "works for hexstring1" $ do       let result =-            unWordLabelMapM $ toS . show <$> doCfgAugWithTopNPass hexstring1+            unWordLabelMapM $ showText <$> doCfgAugWithTopNPass hexstring1       DT.length result `shouldBe` 4634     it "works for hexstring2" $ do       let result =             toS $             unWordLabelMapM-              ((toS . show <$> doCfgAugWithTopNPass hexstring2) :: WordLabelMapM Text)+              ((toS . showText <$> doCfgAugWithTopNPass hexstring2) :: WordLabelMapM Text)       (result :: [Char]) `shouldContain` "OC: 9: JUMPI -> [L3,L5]"
test/Ethereum/Analyzer/EVM/CfgAugmentPassSpec.hs view
@@ -9,7 +9,7 @@ import Data.Text (length) import Ethereum.Analyzer.EVM import Ethereum.Analyzer.TestData.Basic-import GHC.Show+import Ckev.In.Text import Test.Hspec  spec :: Spec@@ -20,14 +20,14 @@           result =             unWordLabelMapM $ do               contract <- evmOps2HplContract disasmd-              (toS . show <$> doCfgAugmentPass contract) :: WordLabelMapM Text+              (showText <$> doCfgAugmentPass contract) :: WordLabelMapM Text       Data.Text.length result `shouldBe` 4588     it "works for hexstring2" $ do       let disasmd@((_, _):_) = disasm hexstring2           result =             unWordLabelMapM $ do               contract <- evmOps2HplContract disasmd-              toS . show . ctorOf <$> doCfgAugmentPass contract+              showText . ctorOf <$> doCfgAugmentPass contract       result `shouldBe` expectedHexString2CtorBody  expectedHexString2CtorBody :: Text
test/Ethereum/Analyzer/EVM/IRSpec.hs view
@@ -5,9 +5,9 @@ import Protolude hiding (show)  import Compiler.Hoopl+import Ckev.In.Text import Ethereum.Analyzer.EVM import Ethereum.Analyzer.TestData.Basic-import GHC.Show import Test.Hspec  spec :: Spec@@ -29,7 +29,7 @@     it "shows HplCfg" $ do       let disasmd = disasm hexstring2       unWordLabelMapM-        ((toS . show . ctorOf <$> evmOps2HplContract disasmd) :: WordLabelMapM Text) `shouldBe`+        ((showText . ctorOf <$> evmOps2HplContract disasmd) :: WordLabelMapM Text) `shouldBe`         toS expectedHexString2CtorBody  expectedHexString2CtorBody :: Text
test/Ethereum/Analyzer/Solidity/SimpleSpec.hs view
@@ -11,7 +11,7 @@ import Ethereum.Analyzer.TestData.Asts import Ethereum.Analyzer.TestData.StorageJson (storageJson) --- import GHC.Show (Show(..))+-- import Ckev.In.Text import Test.Hspec  spec :: Spec
test/Ethereum/Analyzer/SoliditySpec.hs view
@@ -4,9 +4,9 @@  import Protolude hiding (show) +import Ckev.In.Text import Ethereum.Analyzer.Solidity import Ethereum.Analyzer.TestData.StorageJson (storageJson)-import GHC.Show (Show(..)) import Test.Hspec import Text.PrettyPrint.Leijen.Text (Doc, pretty, renderPretty) @@ -15,7 +15,7 @@   describe "e2h" $ do     it "pretty-prints storageJson" $ do       let prettySol =-            (show <$> renderPretty 1.0 80) . (pretty :: [SolNode] -> Doc) <$>+            (showT <$> renderPretty 1.0 80) . (pretty :: [SolNode] -> Doc) <$>             decodeSoleNodes (toS storageJson)       -- putStrLn $ fromRight "" prettySol       prettySol `shouldBe`
test/Ethereum/AnalyzerSpec.hs view
@@ -6,156 +6,155 @@  import Protolude hiding (show) -import Data.List as DL-import Data.List.Extra as DLE+import Ckev.In.Text+import Data.Text as DT import Ethereum.Analyzer.EVM import Ethereum.Analyzer.TestData.Basic-import GHC.Show import Test.Hspec  spec :: Spec spec =   describe "disasm" $ do     it "works for hexstring1" $ do-      let disasmd1 = show $ showOps $ disasm hexstring1-      DL.take 60 disasmd1 `shouldBe`+      let disasmd1 = showT $ showOps $ disasm hexstring1+      DT.take 60 disasmd1 `shouldBe`         "[\"0: PUSH [96]\",\"2: PUSH [64]\",\"4: MSTORE\",\"5: PUSH [2]\",\"7:"-      DLE.takeEnd 60 disasmd1 `shouldBe`+      DT.takeEnd 60 disasmd1 `shouldBe`         "]\",\"6989: JUMP\",\"6990: JUMPDEST\",\"6991: SWAP1\",\"6992: JUMP\"]"     it "works for hexstring2" $ do-      let disasmd2 = show $ showOps $ disasm hexstring2-      disasmd2 `shouldBe` "[\"0: PUSH [96]\"," ++-        "\"2: PUSH [64]\"," ++-        "\"4: MSTORE\"," ++-        "\"5: CALLDATASIZE\"," ++-        "\"6: ISZERO\"," ++-        "\"7: PUSH [39]\"," ++-        "\"9: JUMPI\"," ++-        "\"10: PUSH [224]\"," ++-        "\"12: PUSH [2]\"," ++-        "\"14: EXP\"," ++-        "\"15: PUSH [0]\"," ++-        "\"17: CALLDATALOAD\"," ++-        "\"18: DIV\"," ++-        "\"19: PUSH [65,192,225,181]\"," ++-        "\"24: DUP2\"," ++-        "\"25: EQ\"," ++-        "\"26: PUSH [110]\"," ++-        "\"28: JUMPI\"," ++-        "\"29: DUP1\"," ++-        "\"30: PUSH [229,34,83,129]\"," ++-        "\"35: EQ\"," ++-        "\"36: PUSH [150]\"," ++-        "\"38: JUMPI\"," ++-        "\"39: JUMPDEST\"," ++-        "\"40: PUSH [213]\"," ++-        "\"42: PUSH [0]\"," ++-        "\"44: CALLVALUE\"," ++-        "\"45: GT\"," ++-        "\"46: ISZERO\"," ++-        "\"47: PUSH [108]\"," ++-        "\"49: JUMPI\"," ++-        "\"50: CALLVALUE\"," ++-        "\"51: PUSH [96]\"," ++-        "\"53: SWAP1\"," ++-        "\"54: DUP2\"," ++-        "\"55: MSTORE\"," ++-        "\"56: PUSH [88]\"," ++-        "\"58: SWAP1\"," ++-        "\"59: PUSH [1]\"," ++-        "\"61: PUSH [160]\"," ++-        "\"63: PUSH [2]\"," ++-        "\"65: EXP\"," ++-        "\"66: SUB\"," ++-        "\"67: CALLER\"," ++-        "\"68: AND\"," ++-        "\"69: SWAP1\"," ++-        "\"70: PUSH [144,137,8,9,198,84,241,29,110,114,162,143,166,1,73,119,10,13,17,236,108,146,49,157,108,235,43,176,164,234,26,21]\"," ++-        "\"103: SWAP1\"," ++-        "\"104: PUSH [32]\"," ++-        "\"106: SWAP1\"," ++-        "\"107: LOG3\"," ++-        "\"108: JUMPDEST\"," ++-        "\"109: JUMP\"," ++-        "\"110: JUMPDEST\"," ++-        "\"111: PUSH [213]\"," ++-        "\"113: PUSH [0]\"," ++-        "\"115: SLOAD\"," ++-        "\"116: PUSH [1]\"," ++-        "\"118: PUSH [160]\"," ++-        "\"120: PUSH [2]\"," ++-        "\"122: EXP\"," ++-        "\"123: SUB\"," ++-        "\"124: SWAP1\"," ++-        "\"125: DUP2\"," ++-        "\"126: AND\"," ++-        "\"127: CALLER\"," ++-        "\"128: SWAP2\"," ++-        "\"129: SWAP1\"," ++-        "\"130: SWAP2\"," ++-        "\"131: AND\"," ++-        "\"132: EQ\"," ++-        "\"133: ISZERO\"," ++-        "\"134: PUSH [108]\"," ++-        "\"136: JUMPI\"," ++-        "\"137: PUSH [0]\"," ++-        "\"139: SLOAD\"," ++-        "\"140: PUSH [1]\"," ++-        "\"142: PUSH [160]\"," ++-        "\"144: PUSH [2]\"," ++-        "\"146: EXP\"," ++-        "\"147: SUB\"," ++-        "\"148: AND\"," ++-        "\"149: SUICIDE\"," ++-        "\"150: JUMPDEST\"," ++-        "\"151: PUSH [213]\"," ++-        "\"153: PUSH [0]\"," ++-        "\"155: SLOAD\"," ++-        "\"156: PUSH [1]\"," ++-        "\"158: PUSH [160]\"," ++-        "\"160: PUSH [2]\"," ++-        "\"162: EXP\"," ++-        "\"163: SUB\"," ++-        "\"164: SWAP1\"," ++-        "\"165: DUP2\"," ++-        "\"166: AND\"," ++-        "\"167: CALLER\"," ++-        "\"168: SWAP2\"," ++-        "\"169: SWAP1\"," ++-        "\"170: SWAP2\"," ++-        "\"171: AND\"," ++-        "\"172: EQ\"," ++-        "\"173: ISZERO\"," ++-        "\"174: PUSH [108]\"," ++-        "\"176: JUMPI\"," ++-        "\"177: PUSH [0]\"," ++-        "\"179: DUP1\"," ++-        "\"180: SLOAD\"," ++-        "\"181: PUSH [1]\"," ++-        "\"183: PUSH [160]\"," ++-        "\"185: PUSH [2]\"," ++-        "\"187: EXP\"," ++-        "\"188: SUB\"," ++-        "\"189: SWAP1\"," ++-        "\"190: DUP2\"," ++-        "\"191: AND\"," ++-        "\"192: SWAP2\"," ++-        "\"193: SWAP1\"," ++-        "\"194: ADDRESS\"," ++-        "\"195: AND\"," ++-        "\"196: BALANCE\"," ++-        "\"197: PUSH [96]\"," ++-        "\"199: DUP3\"," ++-        "\"200: DUP2\"," ++-        "\"201: DUP2\"," ++-        "\"202: DUP2\"," ++-        "\"203: DUP6\"," ++-        "\"204: DUP9\"," ++-        "\"205: DUP4\"," ++-        "\"206: CALL\"," ++-        "\"207: POP\"," ++-        "\"208: POP\"," ++-        "\"209: POP\"," ++-        "\"210: POP\"," ++-        "\"211: POP\"," ++-        "\"212: JUMP\"," ++ "\"213: JUMPDEST\"," ++ "\"214: STOP\"]"+      let disasmd2 = showT $ showOps $ disasm hexstring2+      disasmd2 `shouldBe` DT.concat ["[\"0: PUSH [96]\",",+        "\"2: PUSH [64]\",",+        "\"4: MSTORE\",",+        "\"5: CALLDATASIZE\",",+        "\"6: ISZERO\",",+        "\"7: PUSH [39]\",",+        "\"9: JUMPI\",",+        "\"10: PUSH [224]\",",+        "\"12: PUSH [2]\",",+        "\"14: EXP\",",+        "\"15: PUSH [0]\",",+        "\"17: CALLDATALOAD\",",+        "\"18: DIV\",",+        "\"19: PUSH [65,192,225,181]\",",+        "\"24: DUP2\",",+        "\"25: EQ\",",+        "\"26: PUSH [110]\",",+        "\"28: JUMPI\",",+        "\"29: DUP1\",",+        "\"30: PUSH [229,34,83,129]\",",+        "\"35: EQ\",",+        "\"36: PUSH [150]\",",+        "\"38: JUMPI\",",+        "\"39: JUMPDEST\",",+        "\"40: PUSH [213]\",",+        "\"42: PUSH [0]\",",+        "\"44: CALLVALUE\",",+        "\"45: GT\",",+        "\"46: ISZERO\",",+        "\"47: PUSH [108]\",",+        "\"49: JUMPI\",",+        "\"50: CALLVALUE\",",+        "\"51: PUSH [96]\",",+        "\"53: SWAP1\",",+        "\"54: DUP2\",",+        "\"55: MSTORE\",",+        "\"56: PUSH [88]\",",+        "\"58: SWAP1\",",+        "\"59: PUSH [1]\",",+        "\"61: PUSH [160]\",",+        "\"63: PUSH [2]\",",+        "\"65: EXP\",",+        "\"66: SUB\",",+        "\"67: CALLER\",",+        "\"68: AND\",",+        "\"69: SWAP1\",",+        "\"70: PUSH [144,137,8,9,198,84,241,29,110,114,162,143,166,1,73,119,10,13,17,236,108,146,49,157,108,235,43,176,164,234,26,21]\",",+        "\"103: SWAP1\",",+        "\"104: PUSH [32]\",",+        "\"106: SWAP1\",",+        "\"107: LOG3\",",+        "\"108: JUMPDEST\",",+        "\"109: JUMP\",",+        "\"110: JUMPDEST\",",+        "\"111: PUSH [213]\",",+        "\"113: PUSH [0]\",",+        "\"115: SLOAD\",",+        "\"116: PUSH [1]\",",+        "\"118: PUSH [160]\",",+        "\"120: PUSH [2]\",",+        "\"122: EXP\",",+        "\"123: SUB\",",+        "\"124: SWAP1\",",+        "\"125: DUP2\",",+        "\"126: AND\",",+        "\"127: CALLER\",",+        "\"128: SWAP2\",",+        "\"129: SWAP1\",",+        "\"130: SWAP2\",",+        "\"131: AND\",",+        "\"132: EQ\",",+        "\"133: ISZERO\",",+        "\"134: PUSH [108]\",",+        "\"136: JUMPI\",",+        "\"137: PUSH [0]\",",+        "\"139: SLOAD\",",+        "\"140: PUSH [1]\",",+        "\"142: PUSH [160]\",",+        "\"144: PUSH [2]\",",+        "\"146: EXP\",",+        "\"147: SUB\",",+        "\"148: AND\",",+        "\"149: SUICIDE\",",+        "\"150: JUMPDEST\",",+        "\"151: PUSH [213]\",",+        "\"153: PUSH [0]\",",+        "\"155: SLOAD\",",+        "\"156: PUSH [1]\",",+        "\"158: PUSH [160]\",",+        "\"160: PUSH [2]\",",+        "\"162: EXP\",",+        "\"163: SUB\",",+        "\"164: SWAP1\",",+        "\"165: DUP2\",",+        "\"166: AND\",",+        "\"167: CALLER\",",+        "\"168: SWAP2\",",+        "\"169: SWAP1\",",+        "\"170: SWAP2\",",+        "\"171: AND\",",+        "\"172: EQ\",",+        "\"173: ISZERO\",",+        "\"174: PUSH [108]\",",+        "\"176: JUMPI\",",+        "\"177: PUSH [0]\",",+        "\"179: DUP1\",",+        "\"180: SLOAD\",",+        "\"181: PUSH [1]\",",+        "\"183: PUSH [160]\",",+        "\"185: PUSH [2]\",",+        "\"187: EXP\",",+        "\"188: SUB\",",+        "\"189: SWAP1\",",+        "\"190: DUP2\",",+        "\"191: AND\",",+        "\"192: SWAP2\",",+        "\"193: SWAP1\",",+        "\"194: ADDRESS\",",+        "\"195: AND\",",+        "\"196: BALANCE\",",+        "\"197: PUSH [96]\",",+        "\"199: DUP3\",",+        "\"200: DUP2\",",+        "\"201: DUP2\",",+        "\"202: DUP2\",",+        "\"203: DUP6\",",+        "\"204: DUP9\",",+        "\"205: DUP4\",",+        "\"206: CALL\",",+        "\"207: POP\",",+        "\"208: POP\",",+        "\"209: POP\",",+        "\"210: POP\",",+        "\"211: POP\",",+        "\"212: JUMP\",", "\"213: JUMPDEST\",", "\"214: STOP\"]"]