packages feed

ethereum-analyzer 3.0.0 → 3.1.0

raw patch · 18 files changed

+467/−404 lines, 18 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

- Ethereum.Analyzer.EVM: HplCode :: Maybe Label -> HplBody -> HplCode
- Ethereum.Analyzer.EVM: [bodyOf] :: HplCode -> HplBody
- Ethereum.Analyzer.EVM: [entryOf] :: HplCode -> Maybe Label
- Ethereum.Analyzer.EVM: data HplCode
- Ethereum.Analyzer.EVM: evmOps2HplCode :: [(Word256, Operation)] -> WordLabelMapM HplCode
- Ethereum.Analyzer.EVM: toDotText :: HplBody -> Text
- Ethereum.Analyzer.EVM: type HplBody = Body HplOp
+ Ethereum.Analyzer.EVM: [HpEnd] :: MyLabel -> HplOp O C
+ Ethereum.Analyzer.EVM: [HpJump] :: MyLabel -> Label -> HplOp O C
+ Ethereum.Analyzer.EVM: evmOps2HplCfg :: [(Word256, Operation)] -> WordLabelMapM HplCfg
+ Ethereum.Analyzer.EVM: type HplCfg = Graph HplOp O C
+ Ethereum.Analyzer.Solidity: HContract :: Text -> [VarDecl] -> [HFunDefinition] -> HContract
+ Ethereum.Analyzer.Solidity: HFunDefinition :: Idfr -> [VarDecl] -> [VarDecl] -> CFG -> HFunDefinition
+ Ethereum.Analyzer.Solidity: [hcFunctions] :: HContract -> [HFunDefinition]
+ Ethereum.Analyzer.Solidity: [hcName] :: HContract -> Text
+ Ethereum.Analyzer.Solidity: [hcStateVars] :: HContract -> [VarDecl]
+ Ethereum.Analyzer.Solidity: [hfCFG] :: HFunDefinition -> CFG
+ Ethereum.Analyzer.Solidity: [hfName] :: HFunDefinition -> Idfr
+ Ethereum.Analyzer.Solidity: [hfParams] :: HFunDefinition -> [VarDecl]
+ Ethereum.Analyzer.Solidity: [hfReturns] :: HFunDefinition -> [VarDecl]
+ Ethereum.Analyzer.Solidity: data HContract
+ Ethereum.Analyzer.Solidity: data HFunDefinition
+ Ethereum.Analyzer.Solidity: hoopleOf :: UniqueMonad m => Contract -> m HContract
+ Ethereum.Analyzer.Util: toDotText :: (NonLocal n, Show (Block n C C)) => Graph n O C -> Text
- Ethereum.Analyzer.EVM: HplContract :: HplCode -> HplCode -> HplContract
+ Ethereum.Analyzer.EVM: HplContract :: HplCfg -> HplCfg -> HplContract
- Ethereum.Analyzer.EVM: [ctorOf] :: HplContract -> HplCode
+ Ethereum.Analyzer.EVM: [ctorOf] :: HplContract -> HplCfg
- Ethereum.Analyzer.EVM: [dispatcherOf] :: HplContract -> HplCode
+ Ethereum.Analyzer.EVM: [dispatcherOf] :: HplContract -> HplCfg

Files

ethereum-analyzer.cabal view
@@ -1,5 +1,5 @@ name:                ethereum-analyzer-version:             3.0.0+version:             3.1.0 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.0.0+  tag:      v3.1.0   subdir:   ethereum-analyzer  library@@ -48,6 +48,7 @@                      , Ethereum.Analyzer.EVM                      , Ethereum.Analyzer.Debug                      , Ethereum.Analyzer.Solidity+                     , Ethereum.Analyzer.Util   other-modules:       Ethereum.Analyzer.EVM.IR                      , Ethereum.Analyzer.EVM.CfgAugmentPass                      , Ethereum.Analyzer.EVM.CfgAugWithTopNPass@@ -56,6 +57,7 @@                      , Ethereum.Analyzer.Solidity.AstJson                      , Ethereum.Analyzer.Solidity.Finding                      , Ethereum.Analyzer.Solidity.Foreach+                     , Ethereum.Analyzer.Solidity.Hoople                      , Ethereum.Analyzer.Solidity.Simple   ghc-options:         -Wall   hs-source-dirs:      src@@ -75,6 +77,7 @@                      , Ethereum.Analyzer.EVM.UtilSpec                      , Ethereum.Analyzer.Solidity.AstJsonSpec                      , Ethereum.Analyzer.Solidity.ForeachSpec+                     , Ethereum.Analyzer.Solidity.HoopleSpec                      , Ethereum.Analyzer.Solidity.SimpleSpec                      , Ethereum.Analyzer.SoliditySpec                      , Ethereum.Analyzer.TestData.Asts
src/Ethereum/Analyzer/EVM/CfgAugWithTopNPass.hs view
@@ -154,6 +154,8 @@     ocT :: HplOp O C -> StackNFact -> FactBase StackNFact     -- TODO(zchn): Implement JUMPI narrowing     ocT hplop@(OcOp (_, op) _) f = distributeFact hplop (opT op f)+    ocT hplop@(HpJump _ _) f = distributeFact hplop f+    ocT hplop@(HpEnd _) f = distributeFact hplop f     opT :: Operation -> StackNFact -> StackNFact     opT STOP flist = flist     opT ADD flist = pairCompute (+) flist@@ -280,6 +282,8 @@ opGUnit oo@OoOp {} = gUnitOO $ BMiddle oo opGUnit oo@HpCodeCopy {} = gUnitOO $ BMiddle oo opGUnit oc@OcOp {} = gUnitOC $ BlockOC BNil oc+opGUnit oc@HpJump {} = gUnitOC $ BlockOC BNil oc+opGUnit oc@HpEnd {} = gUnitOC $ BlockOC BNil oc  -- catPElems :: [Pointed e x t] -> [t] -- catPElems = mapMaybe maybePElem@@ -307,6 +311,8 @@     ocR :: HplOp O C         -> StackNFact         -> WordLabelMapFuelM (Maybe (Graph HplOp O C))+    ocR op@HpJump {} _ = return (Just (opGUnit op))+    ocR op@HpEnd {} _ = return (Just (opGUnit op))     ocR op@(OcOp (loc, ope) ll) f =       case ope of         JUMP -> handleJmp@@ -340,57 +346,44 @@ doCfgAugWithTopNPass a = do   let disasmd = disasm a   contract <- evmOps2HplContract disasmd-  let entry_ = entryOf $ ctorOf contract-      body = bodyOf $ ctorOf contract-  case entry_ of-    Nothing -> return contract-    Just entry -> do-      newBody <-+  let body = ctorOf contract+  newBody <-+    runWithFuel+      10000000000+      ((\(h, _, _) -> h) <$>+       analyzeAndRewriteFwdOx+         cfgAugWithTopNPass+         body+         (fact_bot $ fp_lattice cfgAugWithTopNPass))+  let newHexstrings =+        foldGraphNodes+          (\n l ->+             case n of+               HpCodeCopy offset ->+                 let newhs =+                       EvmBytecode $+                       DB.drop (fromInteger (getBigWordInteger offset)) $+                       unEvmBytecode (evmBytecodeOf a)+                 in if DB.null $ unEvmBytecode newhs+                      then l+                      else l <> [newhs]+               _ -> l)+          newBody+          ([] :: [EvmBytecode])+  case newHexstrings of+    [] -> return contract {ctorOf = newBody}+    [newhs] -> do+      disBody <- evmOps2HplCfg $ disasm newhs+      newDisBody <-         runWithFuel           10000000000-          (fst <$>-           analyzeAndRewriteFwdBody+          ((\(h, _, _) -> h) <$>+           analyzeAndRewriteFwdOx              cfgAugWithTopNPass-             entry-             body-             (mapSingleton entry $ fact_bot $ fp_lattice cfgAugWithTopNPass))-      let blocks = DL.map snd $ bodyList newBody-          ooOps =-            DL.concatMap ((\(_, b, _) -> blockToList b) . blockSplit) blocks-          newHexstrings =-            mapMaybe-              (\op ->-                 case op of-                   HpCodeCopy offset ->-                     let newhs =-                           EvmBytecode $-                           DB.drop (fromInteger (getBigWordInteger offset)) $-                           unEvmBytecode (evmBytecodeOf a)-                     in if DB.null $ unEvmBytecode newhs-                          then Nothing-                          else Just newhs-                   _ -> Nothing)-              ooOps-      case newHexstrings of-        [] -> return contract {ctorOf = HplCode (Just entry) newBody}-        [newhs] -> do-          HplCode (Just disEntry) disBody <- evmOps2HplCode $ disasm newhs-          newDisBody <--            runWithFuel-              10000000000-              (fst <$>-               analyzeAndRewriteFwdBody-                 cfgAugWithTopNPass-                 disEntry-                 disBody-                 (mapSingleton disEntry $-                  fact_bot $ fp_lattice cfgAugWithTopNPass))-          return-            HplContract-            { ctorOf = HplCode (Just entry) newBody-            , dispatcherOf = HplCode (Just disEntry) newDisBody-            }-        _ ->-          panic $-          "doCfgAugWithTopNPass: unexpected newHexstrings length: " <>-          toS (show (DL.length newHexstrings))+             disBody+             (fact_bot $ fp_lattice cfgAugWithTopNPass))+      return HplContract {ctorOf = newBody, dispatcherOf = newDisBody}+    _ ->+      panic $+      "doCfgAugWithTopNPass: unexpected newHexstrings length: " <>+      toS (show (DL.length newHexstrings))
src/Ethereum/Analyzer/EVM/CfgAugmentPass.hs view
@@ -56,6 +56,8 @@     ooT (HpCodeCopy _) f = f     ocT :: HplOp O C -> StackTopFact -> FactBase StackTopFact     ocT hplop@(OcOp (_, op) _) f = distributeFact hplop (opT op f)+    ocT hplop@(HpJump _ _) f = distributeFact hplop f+    ocT hplop@(HpEnd _) f = distributeFact hplop f     opT :: Operation -> StackTopFact -> StackTopFact     opT DUP1 f = f     opT ISZERO (PElem st) =@@ -87,6 +89,8 @@ opGUnit oo@OoOp {} = gUnitOO $ BMiddle oo opGUnit oo@HpCodeCopy {} = gUnitOO $ BMiddle oo opGUnit oc@OcOp {} = gUnitOC $ BlockOC BNil oc+opGUnit oc@HpJump {} = gUnitOC $ BlockOC BNil oc+opGUnit oc@HpEnd {} = gUnitOC $ BlockOC BNil oc  cfgAugmentRewrite :: FwdRewrite WordLabelMapFuelM HplOp StackTopFact cfgAugmentRewrite = mkFRewrite3 coR ooR ocR@@ -102,6 +106,8 @@     ocR :: HplOp O C         -> StackTopFact         -> WordLabelMapFuelM (Maybe (Graph HplOp O C))+    ocR op@HpJump {} _ = return (Just (opGUnit op))+    ocR op@HpEnd {} _ = return (Just (opGUnit op))     ocR op@(OcOp (loc, ope) ll) f =       case ope of         JUMP -> handleJmp@@ -127,19 +133,10 @@   }  doCfgAugmentPass :: HplContract -> WordLabelMapM HplContract-doCfgAugmentPass contract =-  let entry_ = entryOf $ ctorOf contract-      body = bodyOf $ ctorOf contract-  in case entry_ of-       Nothing -> return contract-       Just entry -> do-         newBody <--           runWithFuel-             1000000-             (fst <$>-              analyzeAndRewriteFwdBody-                cfgAugmentPass-                entry-                body-                (mapSingleton entry Top))-         return contract {ctorOf = HplCode (Just entry) newBody}+doCfgAugmentPass contract = do+  let body = ctorOf contract+  newBody <-+    runWithFuel+      1000000+      ((\(a, _, _) -> a) <$> analyzeAndRewriteFwdOx cfgAugmentPass body Top)+  return contract {ctorOf = newBody}
src/Ethereum/Analyzer/EVM/IR.hs view
@@ -3,14 +3,13 @@   TypeFamilies, ScopedTypeVariables, UndecidableInstances #-}  module Ethereum.Analyzer.EVM.IR-  ( HplBody-  , HplCode(..)+  ( HplCfg   , HplContract(..)   , HplOp(..)   , WordLabelMapM   , WordLabelMapFuelM   , unWordLabelMapM-  , evmOps2HplCode+  , evmOps2HplCfg   , evmOps2HplContract   , labelFor   , labelsFor@@ -34,10 +33,16 @@ import GHC.Show import Legacy.Haskoin.V0102.Network.Haskoin.Crypto.BigWord +newtype MyLabel = MyLabel+  { unMyLabel :: Label+  } deriving (Eq)+ data HplOp e x where         CoOp :: Label -> HplOp C O         OoOp :: (Word256, Operation) -> HplOp O O         OcOp :: (Word256, Operation) -> [Label] -> HplOp O C+        HpJump :: MyLabel -> Label -> HplOp O C+        HpEnd :: MyLabel -> HplOp O C         HpCodeCopy :: Word256 -> HplOp O O  showLoc :: Word256 -> String@@ -53,6 +58,8 @@   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 Show (Block HplOp C C) where@@ -70,71 +77,73 @@  instance Eq (HplOp O C) where   (==) (OcOp a _) (OcOp b _) = a == b+  (==) (HpJump l1 _) (HpJump l2 _) = l1 == l2+  (==) (HpEnd l1) (HpEnd l2) = l1 == l2+  (==) _ _ = False  instance NonLocal HplOp where   entryLabel (CoOp l) = l   successors (OcOp _ ll) = ll+  successors (HpJump _ ll) = [ll]+  successors (HpEnd _) = [] -type HplBody = Body HplOp+type HplCfg = Graph HplOp O C -data HplCode = HplCode-  { entryOf :: Maybe Label-  , bodyOf :: HplBody-  } deriving (Show)+instance Show HplCfg where+  show = showGraph show  data HplContract = HplContract-  { ctorOf :: HplCode-  , dispatcherOf :: HplCode+  { ctorOf :: HplCfg+  , dispatcherOf :: HplCfg   } deriving (Show) -emptyCode :: HplCode-emptyCode = HplCode Nothing emptyBody+emptyHplCfg+  :: UniqueMonad m+  => m HplCfg+emptyHplCfg = do+  l <- myFreshLabel+  return $ mkLast (HpEnd l)  evmOps2HplContract :: [(Word256, Operation)] -> WordLabelMapM HplContract evmOps2HplContract l = do-  ctorBody <- evmOps2HplCode l-  return HplContract {ctorOf = ctorBody, dispatcherOf = emptyCode}+  ctorBody <- evmOps2HplCfg l+  ec <- emptyHplCfg+  return HplContract {ctorOf = ctorBody, dispatcherOf = ec} -evmOps2HplCode :: [(Word256, Operation)] -> WordLabelMapM HplCode-evmOps2HplCode [] = return emptyCode-evmOps2HplCode l@((loc, _):_) = do-  entry <- labelFor loc-  body <- _evmOps2HplBody l-  return HplCode {entryOf = Just entry, bodyOf = body}+myFreshLabel+  :: UniqueMonad m+  => m MyLabel+myFreshLabel = fmap MyLabel freshLabel -_evmOps2HplBody :: [(Word256, Operation)] -> WordLabelMapM HplBody-_evmOps2HplBody [] = return emptyBody-_evmOps2HplBody el@((loc, _):_) = do+evmOps2HplCfg :: [(Word256, Operation)] -> WordLabelMapM HplCfg+evmOps2HplCfg [] = emptyHplCfg+evmOps2HplCfg el@((loc, _):_) = do   l <- labelFor loc-  doEvmOps2HplBody emptyBody (blockJoinHead (CoOp l) emptyBlock) el+  jpLabel <- myFreshLabel+  doEvmOps2HplCfg (mkLast $ HpJump jpLabel l) (mkFirst $ CoOp l) el   where-    doEvmOps2HplBody-      :: HplBody-      -> Block HplOp C O-      -> [(Word256, Operation)]-      -> WordLabelMapM HplBody-    doEvmOps2HplBody body _ [] = return body -- sliently discarding bad hds-    doEvmOps2HplBody body hd [h'] =+    doEvmOps2HplCfg :: HplCfg+                    -> Graph HplOp C O+                    -> [(Word256, Operation)]+                    -> WordLabelMapM HplCfg+    doEvmOps2HplCfg body _ [] = return body -- sliently discarding bad hds+    doEvmOps2HplCfg body hd [h'] =       if isTerminator (snd h')-        then return $ addBlock (blockJoinTail hd (OcOp h' [])) body-        else return body-    doEvmOps2HplBody body hd (h':(t'@((loc', op'):_)))+        then return $ body |*><*| hd CH.<*> mkLast (OcOp h' [])+        else return body -- sliently discarding bad hds+    doEvmOps2HplCfg body hd (h':(t'@((loc', op'):_)))       | isTerminator (snd h') = do         l' <- labelFor loc'-        doEvmOps2HplBody-          (addBlock-             (blockJoinTail hd (OcOp h' [l' | canPassThrough (snd h')]))-             body)-          (blockJoinHead (CoOp l') emptyBlock)+        doEvmOps2HplCfg+          (body |*><*| hd CH.<*> mkLast (OcOp h' [l' | canPassThrough (snd h')]))+          (mkFirst $ CoOp l')           t'-      | op' /= JUMPDEST = doEvmOps2HplBody body (blockSnoc hd (OoOp h')) t'+      | op' /= JUMPDEST = doEvmOps2HplCfg body (hd CH.<*> mkMiddle (OoOp h')) t'       | otherwise = do         l' <- labelFor loc'-        doEvmOps2HplBody-          (addBlock-             (blockJoinTail hd (OcOp h' [l' | canPassThrough (snd h')]))-             body)-          (blockJoinHead (CoOp l') emptyBlock)+        doEvmOps2HplCfg+          (body |*><*| hd CH.<*> mkLast (OcOp h' [l' | canPassThrough (snd h')]))+          (mkFirst $ CoOp l')           t'  isTerminator :: Operation -> Bool@@ -181,6 +190,13 @@           _ <- CH.restart suCheckpoint           return (m, ())     in WordLabelMapM mapper++instance UniqueMonad WordLabelMapM where+  freshUnique = WordLabelMapM f+    where+      f m = do+        u <- freshUnique+        return (m, u)  type WordLabelMapFuelM = CheckingFuelMonad WordLabelMapM 
src/Ethereum/Analyzer/EVM/Util.hs view
@@ -3,25 +3,17 @@   #-}  module Ethereum.Analyzer.EVM.Util-  ( toDotText-  , disasmToDotText+  ( disasmToDotText   , disasmToDotText2   ) where  import Protolude hiding (show) -import Compiler.Hoopl-import Data.Graph.Inductive.Graph as DGIG-import Data.Graph.Inductive.PatriciaTree-import Data.GraphViz-import Data.GraphViz.Printing hiding ((<>))-import qualified Data.Text.Lazy as DTL import Ethereum.Analyzer.EVM.CfgAugWithTopNPass import Ethereum.Analyzer.EVM.CfgAugmentPass import Ethereum.Analyzer.EVM.Disasm import Ethereum.Analyzer.EVM.IR-import GHC.Show-import Text.Read (read)+import Ethereum.Analyzer.Util  disasmToDotText   :: HasEvmBytecode a@@ -31,7 +23,7 @@       result =         unWordLabelMapM $ do           contract <- evmOps2HplContract disasmd-          toDotText <$> (bodyOf . ctorOf <$> doCfgAugmentPass contract)+          toDotText <$> (ctorOf <$> doCfgAugmentPass contract)   in result  disasmToDotText2@@ -42,36 +34,5 @@         unWordLabelMapM $ do           contract' <- doCfgAugWithTopNPass a           return-            ( toDotText $ bodyOf (ctorOf contract')-            , toDotText $ bodyOf (dispatcherOf contract'))+            (toDotText (ctorOf contract'), toDotText (dispatcherOf contract'))   in result--toDotText :: HplBody -> Text-toDotText bd =-  let bdGr = toGr bd-      dotG = toDotGraph bdGr-      dotCode = toDot dotG-  in DTL.toStrict $ renderDot dotCode--toGr :: HplBody -> Gr (Block HplOp C C) ()-toGr bd =-  let lblToNode l = read (drop 1 $ toS $ show l)-      (nList, eList) =-        mapFoldWithKey-          (\lbl blk (nList', eList') ->-             let node = lblToNode lbl-                 edgs = map (\l -> (node, lblToNode l, ())) (successors blk)-             in (nList' <> [(node, blk)], eList' <> edgs))-          ([], [])-          bd-  in mkGraph nList eList--visParams-  :: forall n el.-     GraphvizParams n (Block HplOp C C) el () (Block HplOp C C)-visParams =-  nonClusteredParams-  {fmtNode = \(_, nl) -> [textLabel (toS $ show nl), shape BoxShape]}--toDotGraph :: Gr (Block HplOp C C) () -> DotGraph Node-toDotGraph = graphToDot visParams
src/Ethereum/Analyzer/Solidity.hs view
@@ -2,10 +2,12 @@   ( module Ethereum.Analyzer.Solidity.AstJson   , module Ethereum.Analyzer.Solidity.Finding   , module Ethereum.Analyzer.Solidity.Foreach+  , module Ethereum.Analyzer.Solidity.Hoople   , module Ethereum.Analyzer.Solidity.Simple   ) where  import Ethereum.Analyzer.Solidity.AstJson import Ethereum.Analyzer.Solidity.Finding import Ethereum.Analyzer.Solidity.Foreach+import Ethereum.Analyzer.Solidity.Hoople import Ethereum.Analyzer.Solidity.Simple
src/Ethereum/Analyzer/Solidity/Finding.hs view
@@ -13,8 +13,8 @@ selfdestruct :: Contract -> [Text] selfdestruct c = concatMap sdExp $ expressionsOf c   where-    sdExp exp =-      case exp of+    sdExp e =+      case e of         ExpCall (JustId (Idfr "suicide")) _ ->           ["Prefer 'selfdestruct' over 'suicide'."]         _ -> []
src/Ethereum/Analyzer/Solidity/Foreach.hs view
@@ -33,7 +33,7 @@ _eOf :: Statement -> [Expression] _eOf (StLocalVarDecl _) = [] _eOf (StAssign _ e) = [e]-_eOf (StIf{}) = []+_eOf StIf {} = [] _eOf (StLoop _) = [] _eOf StBreak = [] _eOf StContinue = []
+ src/Ethereum/Analyzer/Solidity/Hoople.hs view
@@ -0,0 +1,107 @@+{-# LANGUAGE GADTs #-}++module Ethereum.Analyzer.Solidity.Hoople+  ( hoopleOf+  , HContract(..)+  , HFunDefinition(..)+  ) where++import Protolude hiding ((<*>))++import Compiler.Hoopl+import Ethereum.Analyzer.Solidity.Simple++data HContract = HContract+  { hcName :: Text+  , hcStateVars :: [VarDecl]+  , hcFunctions :: [HFunDefinition]+  }++type CFG = Graph HStatement O C++type ACFG = AGraph HStatement O C++data HFunDefinition = HFunDefinition+  { hfName :: Idfr+  , hfParams :: [VarDecl]+  , hfReturns :: [VarDecl]+  , hfCFG :: CFG+  }++data HStatement e x where+        CoSt :: Label -> HStatement C O+        OoSt :: Statement -> HStatement O O+        OcSt :: Statement -> [Label] -> HStatement O C+        OcJump :: Label -> HStatement O C++instance NonLocal HStatement where+  entryLabel (CoSt lbl) = lbl+  successors (OcSt _ lbls) = lbls+  successors (OcJump lbl) = [lbl]++instance HooplNode HStatement where+  mkBranchNode = OcJump+  mkLabelNode = CoSt++hoopleOf+  :: UniqueMonad m+  => Contract -> m HContract+hoopleOf Contract {cName = name, cStateVars = vars, cFunctions = funs} = do+  hFuns <- mapM hfunOf funs+  return $ HContract name vars hFuns++hfunOf+  :: UniqueMonad m+  => FunDefinition -> m HFunDefinition+hfunOf FunDefinition { fName = name+                     , fParams = params+                     , fReturns = returns+                     , fBody = stmts+                     } = do+  entryL <- freshLabel+  exitL <- freshLabel+  stmtGraph <- graphOf stmts exitL entryL+  let acfg = (mkBranch entryL |*><*| mkLabel entryL <*> stmtGraph) :: ACFG+  cfg <- graphOfAGraph acfg+  return $ HFunDefinition name params returns cfg++graphOf+  :: UniqueMonad m+  => [Statement] -> Label -> Label -> m ACFG+graphOf [] exitL _ = return $ mkBranch exitL+graphOf (h:t) exitL loopL = do+  postDom <- graphOf t exitL loopL+  case h of+    StLocalVarDecl _ -> return $ mkMiddle' h <*> postDom+    StAssign _ _ -> return $ mkMiddle' h <*> postDom+    StDelete _ -> return $ mkMiddle' h <*> postDom+    StTodo _ -> return $ mkMiddle' h <*> postDom+    StReturn _ -> do+      pdL <- freshLabel+      return $ mkLast (OcSt h []) |*><*| (mkLabel pdL <*> postDom)+    StThrow -> do+      pdL <- freshLabel+      return $ mkLast (OcSt h []) |*><*| (mkLabel pdL <*> postDom)+    StIf _ thenSts elseSts -> do+      pdL <- freshLabel+      thenG <- graphOf thenSts pdL loopL+      elseG <- graphOf elseSts pdL loopL+      -- TODO(zchn): remove the then and else statements in h when+      -- constructing OcSt.+      let ifte =+            mkIfThenElse+              (\thenLbl elseLbl -> mkLast (OcSt h [thenLbl, elseLbl]))+              thenG+              elseG+      return $ ifte |*><*| (mkLabel pdL <*> postDom)+    StLoop stmts -> do+      pdL <- freshLabel+      bodyLbl <- freshLabel+      bodyG <- graphOf stmts pdL bodyLbl+      return $+        mkBranch bodyLbl |*><*| (mkLabel bodyLbl <*> bodyG) |*><*|+        (mkLabel pdL <*> postDom)+    StBreak -> return $ mkBranch exitL+    StContinue -> return $ mkBranch loopL+  where+    mkMiddle' a = mkMiddle (OoSt a)
src/Ethereum/Analyzer/Solidity/Simple.hs view
@@ -196,11 +196,11 @@   return     [StAssign newidfr $ ExpLiteral "1", StAssign idfr $ ExpBin "+" idfr newidfr] s2sStatements SolNode { name = Just "UnaryOperation"-                        , children = Just [SolNode { name = Just "Identifier"-                                                   , attributes = Just SolNode {value = Just idName}-                                                   }]-                        , attributes = Just SolNode {operator = Just "--"}-                        } = do+                      , children = Just [SolNode { name = Just "Identifier"+                                                 , attributes = Just SolNode {value = Just idName}+                                                 }]+                      , attributes = Just SolNode {operator = Just "--"}+                      } = do   let idfr = JustId $ Idfr idName   newVar <- uniqueVar   let newidfr = JustId $ Idfr newVar
+ src/Ethereum/Analyzer/Util.hs view
@@ -0,0 +1,55 @@+{-# LANGUAGE FlexibleContexts, FlexibleInstances, GADTs,+  NoImplicitPrelude, Rank2Types, TypeFamilies, UndecidableInstances+  #-}++module Ethereum.Analyzer.Util+  ( toDotText+  ) where++import Protolude hiding (show)++import Compiler.Hoopl as CH+import Data.Graph.Inductive.Graph as DGIG+import Data.Graph.Inductive.PatriciaTree+import Data.GraphViz+import Data.GraphViz.Printing hiding ((<>))+import qualified Data.Text.Lazy as DTL+import GHC.Show+import Text.Read (read)++toDotText+  :: (NonLocal n, Show (Block n C C))+  => CH.Graph n O C -> Text+toDotText bd =+  let bdGr = toGr bd+      dotG = toDotGraph bdGr+      dotCode = toDot dotG+  in DTL.toStrict $ renderDot dotCode++toGr+  :: NonLocal n+  => CH.Graph n O C -> Gr (Block n C C) ()+toGr bd =+  let lblToNode l = read (drop 1 $ toS $ show l)+      blocks = postorder_dfs bd+      (nList, eList) =+        foldr+          (\blk (nList', eList') ->+             let node = lblToNode $ entryLabel blk+                 edgs = map (\l -> (node, lblToNode l, ())) (successors blk)+             in (nList' <> [(node, blk)], eList' <> edgs))+          ([], [])+          blocks+  in mkGraph nList eList++visParams+  :: (Show (Block n C C))+  => GraphvizParams p (Block n C C) el () (Block n C C)+visParams =+  nonClusteredParams+  {fmtNode = \(_, nl) -> [textLabel (toS $ show nl), shape BoxShape]}++toDotGraph+  :: (Show (Block n C C))+  => Gr (Block n C C) () -> DotGraph Node+toDotGraph = graphToDot visParams
test/Ethereum/Analyzer/EVM/CfgAugWithTopNPassSpec.hs view
@@ -19,10 +19,10 @@     it "works for hexstring1" $ do       let result =             unWordLabelMapM $ toS . show <$> doCfgAugWithTopNPass hexstring1-      DT.length result `shouldBe` 4815+      DT.length result `shouldBe` 4634     it "works for hexstring2" $ do       let result =             toS $             unWordLabelMapM               ((toS . show <$> doCfgAugWithTopNPass hexstring2) :: WordLabelMapM Text)-      (result :: [Char]) `shouldContain` "OC: 9: JUMPI -> [L2,L4]"+      (result :: [Char]) `shouldContain` "OC: 9: JUMPI -> [L3,L5]"
test/Ethereum/Analyzer/EVM/CfgAugmentPassSpec.hs view
@@ -21,25 +21,25 @@             unWordLabelMapM $ do               contract <- evmOps2HplContract disasmd               (toS . show <$> doCfgAugmentPass contract) :: WordLabelMapM Text-      Data.Text.length result `shouldBe` 4769+      Data.Text.length result `shouldBe` 4588     it "works for hexstring2" $ do       let disasmd@((_, _):_) = disasm hexstring2           result =             unWordLabelMapM $ do               contract <- evmOps2HplContract disasmd-              toS . show . bodyOf . ctorOf <$> doCfgAugmentPass contract+              toS . show . ctorOf <$> doCfgAugmentPass contract       result `shouldBe` expectedHexString2CtorBody  expectedHexString2CtorBody :: Text expectedHexString2CtorBody =-  "LM (UM (fromList [(1,CO: L1\n" <> "OO: 0: PUSH [96]\n" <>+  "OC: HpJump -> L1\n" <> "CO: L1\n" <> "OO: 0: PUSH [96]\n" <>   "OO: 2: PUSH [64]\n" <>   "OO: 4: MSTORE\n" <>   "OO: 5: CALLDATASIZE\n" <>   "OO: 6: ISZERO\n" <>   "OO: 7: PUSH [39]\n" <>-  "OC: 9: JUMPI -> [L2,L4]\n" <>-  "),(2,CO: L2\n" <>+  "OC: 9: JUMPI -> [L3,L5]\n" <>+  "CO: L3\n" <>   "OO: 10: PUSH [224]\n" <>   "OO: 12: PUSH [2]\n" <>   "OO: 14: EXP\n" <>@@ -50,14 +50,14 @@   "OO: 24: DUP2\n" <>   "OO: 25: EQ\n" <>   "OO: 26: PUSH [110]\n" <>-  "OC: 28: JUMPI -> [L3,L7]\n" <>-  "),(3,CO: L3\n" <>+  "OC: 28: JUMPI -> [L4,L8]\n" <>+  "CO: L4\n" <>   "OO: 29: DUP1\n" <>   "OO: 30: PUSH [229,34,83,129]\n" <>   "OO: 35: EQ\n" <>   "OO: 36: PUSH [150]\n" <>-  "OC: 38: JUMPI -> [L4,L9]\n" <>-  "),(4,CO: L4\n" <>+  "OC: 38: JUMPI -> [L5,L10]\n" <>+  "CO: L5\n" <>   "OO: 39: JUMPDEST\n" <>   "OO: 40: PUSH [213]\n" <>   "OO: 42: PUSH [0]\n" <>@@ -65,8 +65,8 @@   "OO: 45: GT\n" <>   "OO: 46: ISZERO\n" <>   "OO: 47: PUSH [108]\n" <>-  "OC: 49: JUMPI -> [L5,L6]\n" <>-  "),(5,CO: L5\n" <>+  "OC: 49: JUMPI -> [L6,L7]\n" <>+  "CO: L6\n" <>   "OO: 50: CALLVALUE\n" <>   "OO: 51: PUSH [96]\n" <>   "OO: 53: SWAP1\n" <>@@ -86,11 +86,11 @@   "OO: 103: SWAP1\n" <>   "OO: 104: PUSH [32]\n" <>   "OO: 106: SWAP1\n" <>-  "OC: 107: LOG3 -> [L6]\n" <>-  "),(6,CO: L6\n" <>+  "OC: 107: LOG3 -> [L7]\n" <>+  "CO: L7\n" <>   "OO: 108: JUMPDEST\n" <>   "OC: 109: JUMP -> []\n" <>-  "),(7,CO: L7\n" <>+  "CO: L8\n" <>   "OO: 110: JUMPDEST\n" <>   "OO: 111: PUSH [213]\n" <>   "OO: 113: PUSH [0]\n" <>@@ -111,8 +111,8 @@   "OO: 132: EQ\n" <>   "OO: 133: ISZERO\n" <>   "OO: 134: PUSH [108]\n" <>-  "OC: 136: JUMPI -> [L6,L8]\n" <>-  "),(8,CO: L8\n" <>+  "OC: 136: JUMPI -> [L7,L9]\n" <>+  "CO: L9\n" <>   "OO: 137: PUSH [0]\n" <>   "OO: 139: SLOAD\n" <>   "OO: 140: PUSH [1]\n" <>@@ -122,7 +122,7 @@   "OO: 147: SUB\n" <>   "OO: 148: AND\n" <>   "OC: 149: SUICIDE -> []\n" <>-  "),(9,CO: L9\n" <>+  "CO: L10\n" <>   "OO: 150: JUMPDEST\n" <>   "OO: 151: PUSH [213]\n" <>   "OO: 153: PUSH [0]\n" <>@@ -143,8 +143,8 @@   "OO: 172: EQ\n" <>   "OO: 173: ISZERO\n" <>   "OO: 174: PUSH [108]\n" <>-  "OC: 176: JUMPI -> [L6,L10]\n" <>-  "),(10,CO: L10\n" <>+  "OC: 176: JUMPI -> [L7,L11]\n" <>+  "CO: L11\n" <>   "OO: 177: PUSH [0]\n" <>   "OO: 179: DUP1\n" <>   "OO: 180: SLOAD\n" <>@@ -169,12 +169,11 @@   "OO: 203: DUP6\n" <>   "OO: 204: DUP9\n" <>   "OO: 205: DUP4\n" <>-  "OC: 206: CALL -> [L11]\n" <>-  "),(11,CO: L11\n" <>+  "OC: 206: CALL -> [L12]\n" <>+  "CO: L12\n" <>   "OO: 207: POP\n" <>   "OO: 208: POP\n" <>   "OO: 209: POP\n" <>   "OO: 210: POP\n" <>   "OO: 211: POP\n" <>-  "OC: 212: JUMP -> []\n" <>-  ")]))"+  "OC: 212: JUMP -> []\n"
test/Ethereum/Analyzer/EVM/IRSpec.hs view
@@ -15,31 +15,33 @@   describe "e2h" $ do     it "works for hexstring1" $ do       let disasmd = disasm hexstring1-      unWordLabelMapM (mapSize . bodyOf . ctorOf <$> evmOps2HplContract disasmd) `shouldBe`-        327+      unWordLabelMapM+        (setSize . labelsUsed . ctorOf <$> evmOps2HplContract disasmd) `shouldBe`+        189     it "works for hexstring2" $ do       let disasmd = disasm hexstring2-      unWordLabelMapM (mapSize . bodyOf . ctorOf <$> evmOps2HplContract disasmd) `shouldBe`-        12+      unWordLabelMapM+        (setSize . labelsUsed . ctorOf <$> evmOps2HplContract disasmd) `shouldBe`+        9      -- it "shows voteHexstring" $      --   do let disasmd = disasm voteHexstring-     --      unWordLabelMapM (show <$> (evmOps2HplBody disasmd)) `shouldBe` ""-    it "shows HplBody" $ do+     --      unWordLabelMapM (show <$> (evmOps2HplCfg disasmd)) `shouldBe` ""+    it "shows HplCfg" $ do       let disasmd = disasm hexstring2       unWordLabelMapM-        ((toS . show . bodyOf . ctorOf <$> evmOps2HplContract disasmd) :: WordLabelMapM Text) `shouldBe`+        ((toS . show . ctorOf <$> evmOps2HplContract disasmd) :: WordLabelMapM Text) `shouldBe`         toS expectedHexString2CtorBody  expectedHexString2CtorBody :: Text expectedHexString2CtorBody =-  "LM (UM (fromList [(1,CO: L1\n" <> "OO: 0: PUSH [96]\n" <>+  "OC: HpJump -> L1\n" <> "CO: L1\n" <> "OO: 0: PUSH [96]\n" <>   "OO: 2: PUSH [64]\n" <>   "OO: 4: MSTORE\n" <>   "OO: 5: CALLDATASIZE\n" <>   "OO: 6: ISZERO\n" <>   "OO: 7: PUSH [39]\n" <>-  "OC: 9: JUMPI -> [L2]\n" <>-  "),(2,CO: L2\n" <>+  "OC: 9: JUMPI -> [L3]\n" <>+  "CO: L3\n" <>   "OO: 10: PUSH [224]\n" <>   "OO: 12: PUSH [2]\n" <>   "OO: 14: EXP\n" <>@@ -50,14 +52,14 @@   "OO: 24: DUP2\n" <>   "OO: 25: EQ\n" <>   "OO: 26: PUSH [110]\n" <>-  "OC: 28: JUMPI -> [L3]\n" <>-  "),(3,CO: L3\n" <>+  "OC: 28: JUMPI -> [L4]\n" <>+  "CO: L4\n" <>   "OO: 29: DUP1\n" <>   "OO: 30: PUSH [229,34,83,129]\n" <>   "OO: 35: EQ\n" <>   "OO: 36: PUSH [150]\n" <>-  "OC: 38: JUMPI -> [L4]\n" <>-  "),(4,CO: L4\n" <>+  "OC: 38: JUMPI -> [L5]\n" <>+  "CO: L5\n" <>   "OO: 39: JUMPDEST\n" <>   "OO: 40: PUSH [213]\n" <>   "OO: 42: PUSH [0]\n" <>@@ -65,8 +67,8 @@   "OO: 45: GT\n" <>   "OO: 46: ISZERO\n" <>   "OO: 47: PUSH [108]\n" <>-  "OC: 49: JUMPI -> [L5]\n" <>-  "),(5,CO: L5\n" <>+  "OC: 49: JUMPI -> [L6]\n" <>+  "CO: L6\n" <>   "OO: 50: CALLVALUE\n" <>   "OO: 51: PUSH [96]\n" <>   "OO: 53: SWAP1\n" <>@@ -86,11 +88,11 @@   "OO: 103: SWAP1\n" <>   "OO: 104: PUSH [32]\n" <>   "OO: 106: SWAP1\n" <>-  "OC: 107: LOG3 -> [L6]\n" <>-  "),(6,CO: L6\n" <>+  "OC: 107: LOG3 -> [L7]\n" <>+  "CO: L7\n" <>   "OO: 108: JUMPDEST\n" <>   "OC: 109: JUMP -> []\n" <>-  "),(7,CO: L7\n" <>+  "CO: L8\n" <>   "OO: 110: JUMPDEST\n" <>   "OO: 111: PUSH [213]\n" <>   "OO: 113: PUSH [0]\n" <>@@ -111,8 +113,8 @@   "OO: 132: EQ\n" <>   "OO: 133: ISZERO\n" <>   "OO: 134: PUSH [108]\n" <>-  "OC: 136: JUMPI -> [L8]\n" <>-  "),(8,CO: L8\n" <>+  "OC: 136: JUMPI -> [L9]\n" <>+  "CO: L9\n" <>   "OO: 137: PUSH [0]\n" <>   "OO: 139: SLOAD\n" <>   "OO: 140: PUSH [1]\n" <>@@ -122,7 +124,7 @@   "OO: 147: SUB\n" <>   "OO: 148: AND\n" <>   "OC: 149: SUICIDE -> []\n" <>-  "),(9,CO: L9\n" <>+  "CO: L10\n" <>   "OO: 150: JUMPDEST\n" <>   "OO: 151: PUSH [213]\n" <>   "OO: 153: PUSH [0]\n" <>@@ -143,8 +145,8 @@   "OO: 172: EQ\n" <>   "OO: 173: ISZERO\n" <>   "OO: 174: PUSH [108]\n" <>-  "OC: 176: JUMPI -> [L10]\n" <>-  "),(10,CO: L10\n" <>+  "OC: 176: JUMPI -> [L11]\n" <>+  "CO: L11\n" <>   "OO: 177: PUSH [0]\n" <>   "OO: 179: DUP1\n" <>   "OO: 180: SLOAD\n" <>@@ -169,15 +171,14 @@   "OO: 203: DUP6\n" <>   "OO: 204: DUP9\n" <>   "OO: 205: DUP4\n" <>-  "OC: 206: CALL -> [L11]\n" <>-  "),(11,CO: L11\n" <>+  "OC: 206: CALL -> [L12]\n" <>+  "CO: L12\n" <>   "OO: 207: POP\n" <>   "OO: 208: POP\n" <>   "OO: 209: POP\n" <>   "OO: 210: POP\n" <>   "OO: 211: POP\n" <>   "OC: 212: JUMP -> []\n" <>-  "),(12,CO: L12\n" <>+  "CO: L13\n" <>   "OO: 213: JUMPDEST\n" <>-  "OC: 214: STOP -> []\n" <>-  ")]))"+  "OC: 214: STOP -> []\n"
test/Ethereum/Analyzer/EVM/UtilSpec.hs view
@@ -9,24 +9,26 @@ import Data.Text import Ethereum.Analyzer.EVM import Ethereum.Analyzer.TestData.Basic+import Ethereum.Analyzer.Util import Test.Hspec  spec :: Spec spec =   describe "toDotText" $ do-    it "shows HplBody's dot graph" $ do+    it "shows HplCfg's dot graph" $ do       let disasmd = disasm hexstring2       (unpack . unWordLabelMapM)-        (toDotText . bodyOf . ctorOf <$> evmOps2HplContract disasmd) `shouldBe`+        (toDotText . ctorOf <$> evmOps2HplContract disasmd) `shouldBe`         toS expectedHexString2RawDot-    it "shows HplBody after CfgAugmentPass" $ do+    it "shows HplCfg after CfgAugmentPass" $ do       let disasmd@((_, _):_) = disasm hexstring2           result =             (unpack . unWordLabelMapM) $ do               contract <- evmOps2HplContract disasmd-              toDotText . bodyOf . ctorOf <$> doCfgAugmentPass contract+              toDotText . ctorOf <$> doCfgAugmentPass contract       result `shouldBe` toS expectedHexString2AugDot +-- There are more opcode in the hexstring than printed here. expectedHexString2RawDot :: Text expectedHexString2RawDot =   "digraph {\n" <> "    1 [label=\"CO: L1\\n" <> "OO: 0: PUSH [96]\\n" <>@@ -35,10 +37,10 @@   "OO: 5: CALLDATASIZE\\n" <>   "OO: 6: ISZERO\\n" <>   "OO: 7: PUSH [39]\\n" <>-  "OC: 9: JUMPI -> [L2]\\n" <>+  "OC: 9: JUMPI -> [L3]\\n" <>   "\"\n" <>   "      ,shape=box];\n" <>-  "    2 [label=\"CO: L2\\n" <>+  "    3 [label=\"CO: L3\\n" <>   "OO: 10: PUSH [224]\\n" <>   "OO: 12: PUSH [2]\\n" <>   "OO: 14: EXP\\n" <>@@ -49,18 +51,18 @@   "OO: 24: DUP2\\n" <>   "OO: 25: EQ\\n" <>   "OO: 26: PUSH [110]\\n" <>-  "OC: 28: JUMPI -> [L3]\\n" <>+  "OC: 28: JUMPI -> [L4]\\n" <>   "\"\n" <>   "      ,shape=box];\n" <>-  "    3 [label=\"CO: L3\\n" <>+  "    4 [label=\"CO: L4\\n" <>   "OO: 29: DUP1\\n" <>   "OO: 30: PUSH [229,34,83,129]\\n" <>   "OO: 35: EQ\\n" <>   "OO: 36: PUSH [150]\\n" <>-  "OC: 38: JUMPI -> [L4]\\n" <>+  "OC: 38: JUMPI -> [L5]\\n" <>   "\"\n" <>   "      ,shape=box];\n" <>-  "    4 [label=\"CO: L4\\n" <>+  "    5 [label=\"CO: L5\\n" <>   "OO: 39: JUMPDEST\\n" <>   "OO: 40: PUSH [213]\\n" <>   "OO: 42: PUSH [0]\\n" <>@@ -68,10 +70,10 @@   "OO: 45: GT\\n" <>   "OO: 46: ISZERO\\n" <>   "OO: 47: PUSH [108]\\n" <>-  "OC: 49: JUMPI -> [L5]\\n" <>+  "OC: 49: JUMPI -> [L6]\\n" <>   "\"\n" <>   "      ,shape=box];\n" <>-  "    5 [label=\"CO: L5\\n" <>+  "    6 [label=\"CO: L6\\n" <>   "OO: 50: CALLVALUE\\n" <>   "OO: 51: PUSH [96]\\n" <>   "OO: 53: SWAP1\\n" <>@@ -91,124 +93,19 @@   "OO: 103: SWAP1\\n" <>   "OO: 104: PUSH [32]\\n" <>   "OO: 106: SWAP1\\n" <>-  "OC: 107: LOG3 -> [L6]\\n" <>+  "OC: 107: LOG3 -> [L7]\\n" <>   "\"\n" <>   "      ,shape=box];\n" <>-  "    6 [label=\"CO: L6\\n" <>+  "    7 [label=\"CO: L7\\n" <>   "OO: 108: JUMPDEST\\n" <>   "OC: 109: JUMP -> []\\n" <>   "\"\n" <>   "      ,shape=box];\n" <>-  "    7 [label=\"CO: L7\\n" <>-  "OO: 110: JUMPDEST\\n" <>-  "OO: 111: PUSH [213]\\n" <>-  "OO: 113: PUSH [0]\\n" <>-  "OO: 115: SLOAD\\n" <>-  "OO: 116: PUSH [1]\\n" <>-  "OO: 118: PUSH [160]\\n" <>-  "OO: 120: PUSH [2]\\n" <>-  "OO: 122: EXP\\n" <>-  "OO: 123: SUB\\n" <>-  "OO: 124: SWAP1\\n" <>-  "OO: 125: DUP2\\n" <>-  "OO: 126: AND\\n" <>-  "OO: 127: CALLER\\n" <>-  "OO: 128: SWAP2\\n" <>-  "OO: 129: SWAP1\\n" <>-  "OO: 130: SWAP2\\n" <>-  "OO: 131: AND\\n" <>-  "OO: 132: EQ\\n" <>-  "OO: 133: ISZERO\\n" <>-  "OO: 134: PUSH [108]\\n" <>-  "OC: 136: JUMPI -> [L8]\\n" <>-  "\"\n" <>-  "      ,shape=box];\n" <>-  "    8 [label=\"CO: L8\\n" <>-  "OO: 137: PUSH [0]\\n" <>-  "OO: 139: SLOAD\\n" <>-  "OO: 140: PUSH [1]\\n" <>-  "OO: 142: PUSH [160]\\n" <>-  "OO: 144: PUSH [2]\\n" <>-  "OO: 146: EXP\\n" <>-  "OO: 147: SUB\\n" <>-  "OO: 148: AND\\n" <>-  "OC: 149: SUICIDE -> []\\n" <>-  "\"\n" <>-  "      ,shape=box];\n" <>-  "    9 [label=\"CO: L9\\n" <>-  "OO: 150: JUMPDEST\\n" <>-  "OO: 151: PUSH [213]\\n" <>-  "OO: 153: PUSH [0]\\n" <>-  "OO: 155: SLOAD\\n" <>-  "OO: 156: PUSH [1]\\n" <>-  "OO: 158: PUSH [160]\\n" <>-  "OO: 160: PUSH [2]\\n" <>-  "OO: 162: EXP\\n" <>-  "OO: 163: SUB\\n" <>-  "OO: 164: SWAP1\\n" <>-  "OO: 165: DUP2\\n" <>-  "OO: 166: AND\\n" <>-  "OO: 167: CALLER\\n" <>-  "OO: 168: SWAP2\\n" <>-  "OO: 169: SWAP1\\n" <>-  "OO: 170: SWAP2\\n" <>-  "OO: 171: AND\\n" <>-  "OO: 172: EQ\\n" <>-  "OO: 173: ISZERO\\n" <>-  "OO: 174: PUSH [108]\\n" <>-  "OC: 176: JUMPI -> [L10]\\n" <>-  "\"\n" <>-  "      ,shape=box];\n" <>-  "    10 [label=\"CO: L10\\n" <>-  "OO: 177: PUSH [0]\\n" <>-  "OO: 179: DUP1\\n" <>-  "OO: 180: SLOAD\\n" <>-  "OO: 181: PUSH [1]\\n" <>-  "OO: 183: PUSH [160]\\n" <>-  "OO: 185: PUSH [2]\\n" <>-  "OO: 187: EXP\\n" <>-  "OO: 188: SUB\\n" <>-  "OO: 189: SWAP1\\n" <>-  "OO: 190: DUP2\\n" <>-  "OO: 191: AND\\n" <>-  "OO: 192: SWAP2\\n" <>-  "OO: 193: SWAP1\\n" <>-  "OO: 194: ADDRESS\\n" <>-  "OO: 195: AND\\n" <>-  "OO: 196: BALANCE\\n" <>-  "OO: 197: PUSH [96]\\n" <>-  "OO: 199: DUP3\\n" <>-  "OO: 200: DUP2\\n" <>-  "OO: 201: DUP2\\n" <>-  "OO: 202: DUP2\\n" <>-  "OO: 203: DUP6\\n" <>-  "OO: 204: DUP9\\n" <>-  "OO: 205: DUP4\\n" <>-  "OC: 206: CALL -> [L11]\\n" <>-  "\"\n" <>-  "       ,shape=box];\n" <>-  "    11 [label=\"CO: L11\\n" <>-  "OO: 207: POP\\n" <>-  "OO: 208: POP\\n" <>-  "OO: 209: POP\\n" <>-  "OO: 210: POP\\n" <>-  "OO: 211: POP\\n" <>-  "OC: 212: JUMP -> []\\n" <>-  "\"\n" <>-  "       ,shape=box];\n" <>-  "    12 [label=\"CO: L12\\n" <>-  "OO: 213: JUMPDEST\\n" <>-  "OC: 214: STOP -> []\\n" <>-  "\"\n" <>-  "       ,shape=box];\n" <>-  "    1 -> 2;\n" <>-  "    2 -> 3;\n" <>+  "    1 -> 3;\n" <>   "    3 -> 4;\n" <>   "    4 -> 5;\n" <>   "    5 -> 6;\n" <>-  "    7 -> 8;\n" <>-  "    9 -> 10;\n" <>-  "    10 -> 11;\n" <>+  "    6 -> 7;\n" <>   "}"  expectedHexString2AugDot :: Text@@ -219,10 +116,10 @@   "OO: 5: CALLDATASIZE\\n" <>   "OO: 6: ISZERO\\n" <>   "OO: 7: PUSH [39]\\n" <>-  "OC: 9: JUMPI -> [L2,L4]\\n" <>+  "OC: 9: JUMPI -> [L3,L5]\\n" <>   "\"\n" <>   "      ,shape=box];\n" <>-  "    2 [label=\"CO: L2\\n" <>+  "    3 [label=\"CO: L3\\n" <>   "OO: 10: PUSH [224]\\n" <>   "OO: 12: PUSH [2]\\n" <>   "OO: 14: EXP\\n" <>@@ -233,18 +130,18 @@   "OO: 24: DUP2\\n" <>   "OO: 25: EQ\\n" <>   "OO: 26: PUSH [110]\\n" <>-  "OC: 28: JUMPI -> [L3,L7]\\n" <>+  "OC: 28: JUMPI -> [L4,L8]\\n" <>   "\"\n" <>   "      ,shape=box];\n" <>-  "    3 [label=\"CO: L3\\n" <>+  "    4 [label=\"CO: L4\\n" <>   "OO: 29: DUP1\\n" <>   "OO: 30: PUSH [229,34,83,129]\\n" <>   "OO: 35: EQ\\n" <>   "OO: 36: PUSH [150]\\n" <>-  "OC: 38: JUMPI -> [L4,L9]\\n" <>+  "OC: 38: JUMPI -> [L5,L10]\\n" <>   "\"\n" <>   "      ,shape=box];\n" <>-  "    4 [label=\"CO: L4\\n" <>+  "    5 [label=\"CO: L5\\n" <>   "OO: 39: JUMPDEST\\n" <>   "OO: 40: PUSH [213]\\n" <>   "OO: 42: PUSH [0]\\n" <>@@ -252,10 +149,10 @@   "OO: 45: GT\\n" <>   "OO: 46: ISZERO\\n" <>   "OO: 47: PUSH [108]\\n" <>-  "OC: 49: JUMPI -> [L5,L6]\\n" <>+  "OC: 49: JUMPI -> [L6,L7]\\n" <>   "\"\n" <>   "      ,shape=box];\n" <>-  "    5 [label=\"CO: L5\\n" <>+  "    6 [label=\"CO: L6\\n" <>   "OO: 50: CALLVALUE\\n" <>   "OO: 51: PUSH [96]\\n" <>   "OO: 53: SWAP1\\n" <>@@ -275,15 +172,15 @@   "OO: 103: SWAP1\\n" <>   "OO: 104: PUSH [32]\\n" <>   "OO: 106: SWAP1\\n" <>-  "OC: 107: LOG3 -> [L6]\\n" <>+  "OC: 107: LOG3 -> [L7]\\n" <>   "\"\n" <>   "      ,shape=box];\n" <>-  "    6 [label=\"CO: L6\\n" <>+  "    7 [label=\"CO: L7\\n" <>   "OO: 108: JUMPDEST\\n" <>   "OC: 109: JUMP -> []\\n" <>   "\"\n" <>   "      ,shape=box];\n" <>-  "    7 [label=\"CO: L7\\n" <>+  "    8 [label=\"CO: L8\\n" <>   "OO: 110: JUMPDEST\\n" <>   "OO: 111: PUSH [213]\\n" <>   "OO: 113: PUSH [0]\\n" <>@@ -304,10 +201,10 @@   "OO: 132: EQ\\n" <>   "OO: 133: ISZERO\\n" <>   "OO: 134: PUSH [108]\\n" <>-  "OC: 136: JUMPI -> [L6,L8]\\n" <>+  "OC: 136: JUMPI -> [L7,L9]\\n" <>   "\"\n" <>   "      ,shape=box];\n" <>-  "    8 [label=\"CO: L8\\n" <>+  "    9 [label=\"CO: L9\\n" <>   "OO: 137: PUSH [0]\\n" <>   "OO: 139: SLOAD\\n" <>   "OO: 140: PUSH [1]\\n" <>@@ -319,7 +216,7 @@   "OC: 149: SUICIDE -> []\\n" <>   "\"\n" <>   "      ,shape=box];\n" <>-  "    9 [label=\"CO: L9\\n" <>+  "    10 [label=\"CO: L10\\n" <>   "OO: 150: JUMPDEST\\n" <>   "OO: 151: PUSH [213]\\n" <>   "OO: 153: PUSH [0]\\n" <>@@ -340,10 +237,10 @@   "OO: 172: EQ\\n" <>   "OO: 173: ISZERO\\n" <>   "OO: 174: PUSH [108]\\n" <>-  "OC: 176: JUMPI -> [L6,L10]\\n" <>+  "OC: 176: JUMPI -> [L7,L11]\\n" <>   "\"\n" <>-  "      ,shape=box];\n" <>-  "    10 [label=\"CO: L10\\n" <>+  "       ,shape=box];\n" <>+  "    11 [label=\"CO: L11\\n" <>   "OO: 177: PUSH [0]\\n" <>   "OO: 179: DUP1\\n" <>   "OO: 180: SLOAD\\n" <>@@ -368,10 +265,10 @@   "OO: 203: DUP6\\n" <>   "OO: 204: DUP9\\n" <>   "OO: 205: DUP4\\n" <>-  "OC: 206: CALL -> [L11]\\n" <>+  "OC: 206: CALL -> [L12]\\n" <>   "\"\n" <>   "       ,shape=box];\n" <>-  "    11 [label=\"CO: L11\\n" <>+  "    12 [label=\"CO: L12\\n" <>   "OO: 207: POP\\n" <>   "OO: 208: POP\\n" <>   "OO: 209: POP\\n" <>@@ -380,18 +277,18 @@   "OC: 212: JUMP -> []\\n" <>   "\"\n" <>   "       ,shape=box];\n" <>-  "    1 -> 2;\n" <>-  "    1 -> 4;\n" <>-  "    2 -> 3;\n" <>-  "    2 -> 7;\n" <>+  "    1 -> 3;\n" <>+  "    1 -> 5;\n" <>   "    3 -> 4;\n" <>-  "    3 -> 9;\n" <>+  "    3 -> 8;\n" <>   "    4 -> 5;\n" <>-  "    4 -> 6;\n" <>+  "    4 -> 10;\n" <>   "    5 -> 6;\n" <>-  "    7 -> 6;\n" <>-  "    7 -> 8;\n" <>-  "    9 -> 6;\n" <>-  "    9 -> 10;\n" <>+  "    5 -> 7;\n" <>+  "    6 -> 7;\n" <>+  "    8 -> 7;\n" <>+  "    8 -> 9;\n" <>+  "    10 -> 7;\n" <>   "    10 -> 11;\n" <>+  "    11 -> 12;\n" <>   "}"
test/Ethereum/Analyzer/Solidity/ForeachSpec.hs view
@@ -11,13 +11,13 @@ spec :: Spec spec = do   describe "statementsOf" $-    it "works for storageJson" $ do+    it "works for storageJson" $     case decodeContracts storageJson of       Right contracts ->         sum (map (length . statementsOf) contracts) `shouldBe` 2       Left err -> expectationFailure $ toS err   describe "expressionsOf" $-    it "works for storageJson" $ do+    it "works for storageJson" $     case decodeContracts storageJson of       Right contracts ->         sum (map (length . expressionsOf) contracts) `shouldBe` 1
+ test/Ethereum/Analyzer/Solidity/HoopleSpec.hs view
@@ -0,0 +1,32 @@+module Ethereum.Analyzer.Solidity.HoopleSpec+  ( spec+  ) where++import Protolude hiding (show)++import Compiler.Hoopl++import Ethereum.Analyzer.Solidity+import Ethereum.Analyzer.TestData.Asts+import GHC.Show (Show(..))++import Test.Hspec++spec :: Spec+spec = describe "hoopleOf" $ mapM_ hoopleOfWorks testFilepaths++hoopleOfWorks :: Text -> SpecWith ()+hoopleOfWorks filepath =+  context (toS filepath) $+  it "converts Contract to HContract" $ do+    cfgs -- IO+       <-+      do solNodes <- solNodesOf filepath+         return $+           runSimpleUniqueMonad $ -- UniqueMonad+            do+             contracts <- concat <$> mapM s2sContracts solNodes+             hContracts <- mapM hoopleOf contracts+             return $ map hfCFG $ concatMap hcFunctions hContracts+    sum (map (\g -> foldGraphNodes (const (1 +)) g 0) cfgs) `shouldSatisfy`+      (> 0)
test/Ethereum/Analyzer/Solidity/SimpleSpec.hs view
@@ -19,40 +19,40 @@ spec = do   describe "e2h" $     it "parses storageJson" $ do-    let eitherContracts = do-          solNodes <- decodeSoleNodes (toS storageJson)-          let mContracts = mapM s2sContracts solNodes-          let contracts = concat $ runSimpleUniqueMonad mContracts-          return contracts+      let eitherContracts = do+            solNodes <- decodeSoleNodes (toS storageJson)+            let mContracts = mapM s2sContracts solNodes+            let contracts = concat $ runSimpleUniqueMonad mContracts+            return contracts     -- GP.pp eitherContracts-    eitherContracts `shouldBe`-      Right-        [ Contract-          { cName = "SimpleStorage"-          , cStateVars =-              [VarDecl {vName = Idfr "storedData", vType = Unknown "uint256"}]-          , cFunctions =-              [ FunDefinition-                { fName = Idfr "set"-                , fParams =-                    [VarDecl {vName = Idfr "x", vType = Unknown "uint256"}]-                , fReturns = []-                , fBody =-                    [ StAssign-                        (JustId (Idfr "storedData"))-                        (ExpLval (JustId (Idfr "x")))-                    ]-                }-              , FunDefinition-                { fName = Idfr "get"-                , fParams = []-                , fReturns =-                    [VarDecl {vName = Idfr "", vType = Unknown "uint256"}]-                , fBody = [StReturn [JustId (Idfr "storedData")]]-                }-              ]-          }-        ]+      eitherContracts `shouldBe`+        Right+          [ Contract+            { cName = "SimpleStorage"+            , cStateVars =+                [VarDecl {vName = Idfr "storedData", vType = Unknown "uint256"}]+            , cFunctions =+                [ FunDefinition+                  { fName = Idfr "set"+                  , fParams =+                      [VarDecl {vName = Idfr "x", vType = Unknown "uint256"}]+                  , fReturns = []+                  , fBody =+                      [ StAssign+                          (JustId (Idfr "storedData"))+                          (ExpLval (JustId (Idfr "x")))+                      ]+                  }+                , FunDefinition+                  { fName = Idfr "get"+                  , fParams = []+                  , fReturns =+                      [VarDecl {vName = Idfr "", vType = Unknown "uint256"}]+                  , fBody = [StReturn [JustId (Idfr "storedData")]]+                  }+                ]+            }+          ]   describe "Simple" $ mapM_ nonEmptySimple testFilepaths  nonEmptySimple :: Text -> SpecWith ()