@@ -27,7 +27,7 @@ import Data.ByteString (ByteString)
2727import Data.Text.Encoding (encodeUtf8 )
2828import Control.Concurrent.Async
2929import Control.Monad
30- import Data.Foldable (sequenceA_ )
30+ import Data.Foldable (sequenceA_ , traverse_ )
3131import Data.DoubleWord
3232import Data.Maybe
3333import Data.Type.Equality (TestEquality (.. ))
@@ -149,7 +149,8 @@ translateConstructor bytecode (Constructor cid iface _ preconds _ _ upds) cmap =
149149 preconds' <- mapM (toProp initmap) preconds
150150 cmap' <- applyUpdates initmap initmap upds
151151 fresh <- getFresh
152- pure $ ([EVM. Success (snd calldata <> preconds' <> symAddrCnstr 1 fresh) mempty (EVM. ConcreteBuf bytecode) (M. map fst cmap')], calldata, ifaceToSig iface, cmap')
152+ let acmap = abstractCmap initAddr cmap'
153+ pure $ ([EVM. Success (snd calldata <> preconds' <> symAddrCnstr 1 fresh) mempty (EVM. ConcreteBuf bytecode) (M. map fst cmap')], calldata, ifaceToSig iface, acmap)
153154 where
154155 calldata = makeCtrCalldata iface
155156 initcontract = EVM. C { EVM. code = EVM. RuntimeCode (EVM. ConcreteRuntimeCode bytecode)
@@ -162,7 +163,7 @@ translateConstructor bytecode (Constructor cid iface _ preconds _ _ upds) cmap =
162163symAddrCnstr :: Int -> Int -> [EVM. Prop ]
163164symAddrCnstr start end = fmap (\ i -> EVM. PNeg (EVM. PEq (EVM. WAddr (EVM. SymAddr $ " freshSymAddr" <> (T. pack $ show i))) (EVM. Lit 0 ))) [start.. end]
164165
165- translateBehvs :: Monad m => ContractMap -> [Behaviour ] -> ActT m [(Id , [EVM. Expr EVM. End ], Calldata , Sig )]
166+ translateBehvs :: Monad m => ContractMap -> [Behaviour ] -> ActT m [(Id , [( EVM. Expr EVM. End, ContractMap ) ], Calldata , Sig )]
166167translateBehvs cmap behvs = do
167168 let groups = (groupBy sameIface behvs) :: [[Behaviour ]]
168169 mapM (\ behvs' -> do
@@ -187,15 +188,16 @@ ifaceToSig (Interface name args) = Sig (T.pack name) (fmap fromdecl args)
187188 where
188189 fromdecl (Decl t _) = t
189190
190- translateBehv :: Monad m => ContractMap -> Behaviour -> ActT m (EVM. Expr EVM. End )
191+ translateBehv :: Monad m => ContractMap -> Behaviour -> ActT m (EVM. Expr EVM. End, ContractMap )
191192translateBehv cmap (Behaviour _ _ _ _ preconds caseconds _ upds ret) = do
192193 fresh <- getFresh
193194 preconds' <- mapM (toProp cmap) preconds
194195 caseconds' <- mapM (toProp cmap) caseconds
195196 ret' <- returnsToExpr cmap ret
196197 cmap' <- applyUpdates cmap cmap upds
197198 fresh' <- getFresh
198- pure $ EVM. Success (preconds' <> caseconds' <> symAddrCnstr (fresh+ 1 ) fresh') mempty ret' (M. map fst cmap')
199+ let acmap = abstractCmap initAddr cmap'
200+ pure $ (EVM. Success (preconds' <> caseconds' <> symAddrCnstr (fresh+ 1 ) fresh') mempty ret' (M. map fst cmap'), acmap)
199201
200202
201203applyUpdates :: Monad m => ContractMap -> ContractMap -> [StorageUpdate ] -> ActT m ContractMap
@@ -727,7 +729,7 @@ checkConstructors solvers initcode runtimecode (Contract ctor@(Constructor _ ifa
727729 res1 <- lift $ checkResult calldata (Just sig) =<< checkEquiv solvers solbehvs actbehvs
728730 lift $ showMsg " \x1b [1mChecking if constructor input spaces are the same.\x1b [m"
729731 res2 <- lift $ checkResult calldata (Just sig) =<< checkInputSpaces solvers solbehvs actbehvs
730- pure $ checks *> res1 *> res2 *> Success (abstractCmap initAddr $ cmap)
732+ pure $ checks *> res1 *> res2 *> Success cmap
731733 where
732734 removeFails branches = filter isSuccess $ branches
733735
@@ -737,17 +739,18 @@ checkBehaviours solvers (Contract _ behvs) actstorage = do
737739 let hevmstorage = translateCmap actstorage
738740 fresh <- getFresh
739741 actbehvs <- translateBehvs actstorage behvs
740- (liftM $ concatError def) $ flip mapM actbehvs $ \ (name,behvs',calldata, sig) -> do
742+ (liftM $ concatError def) $ flip mapM actbehvs $ \ (name,actbehv,calldata, sig) -> do
743+ let (behvs', fcmaps) = unzip actbehv
744+
741745 solbehvs <- lift $ removeFails <$> getRuntimeBranches solvers hevmstorage calldata fresh
742-
743746 lift $ showMsg $ " \x1b [1mChecking behavior \x1b [4m" <> name <> " \x1b [m of Act\x1b [m"
744747 -- equivalence check
745748 lift $ showMsg $ " \x1b [1mChecking if behaviour is matched by EVM\x1b [m"
746749 res1 <- lift $ checkResult calldata (Just sig) =<< checkEquiv solvers solbehvs behvs'
747750 -- input space exhaustiveness check
748751 lift $ showMsg $ " \x1b [1mChecking if the input spaces are the same\x1b [m"
749752 res2 <- lift $ checkResult calldata (Just sig) =<< checkInputSpaces solvers solbehvs behvs'
750- pure $ res1 *> res2
753+ pure $ traverse_ (checkStoreIsomorphism actstorage) fcmaps *> res1 *> res2
751754
752755 where
753756 removeFails branches = filter isSuccess $ branches
@@ -794,7 +797,7 @@ abstractCmap this cmap =
794797 traverseStorage _ _ = error $ " Internal error: unexpected storage shape"
795798
796799 makeContract :: EVM. Expr EVM. EAddr -> (EVM. Expr EVM. EContract , Id ) -> (EVM. Expr EVM. EContract , Id )
797- makeContract addr (EVM. C code storage _ _, cid) = (EVM. C code (traverseStorage addr (simplify storage)) (EVM. Balance addr) (Just 0 ), cid)
800+ makeContract addr (EVM. C code storage _ _, cid) = (EVM. C code (simplify ( traverseStorage addr (simplify storage) )) (EVM. Balance addr) (Just 0 ), cid)
798801 makeContract _ (EVM. GVar _, _) = error " Internal error: contract cannot be gvar"
799802
800803-- | Remove unreachable addresses from a contract map
@@ -833,42 +836,55 @@ pruneContractState entryaddr cmap =
833836
834837
835838-- | Check if two contract maps are isomorphic
836- -- Note that is problem is not as difficult as graph isomorphism since edges are labeld.
839+ -- Perform a breadth first traversal and try to find a bijection between the addresses of the two stores
840+ -- Note that is problem is not as difficult as graph isomorphism since edges are labeld.
841+ -- Assumes that the stores are abstracted, pruned, and simplified.
842+ -- All writes are to a unique concrete slot and the value is a simbolic address.
837843checkStoreIsomorphism :: ContractMap -> ContractMap -> Error String ()
838- checkStoreIsomorphism cmap1 cmap2 = visit [(initAddr, initAddr)] [] cmap1 cmap2 M. empty M. empty
844+ checkStoreIsomorphism cmap1 cmap2 = bfs [(idOfAddr initAddr, idOfAddr initAddr)] [] M. empty M. empty
839845 where
840846 -- tries to find a bijective renaming between the addresses of the two maps
841- visit :: [(EVM. Expr EVM. EAddr , EVM. Expr EVM. EAddr )] -- Queue of the addresses we are exploring (dequeue)
842- -> [(EVM. Expr EVM. EAddr , EVM. Expr EVM. EAddr )] -- Queue of the addresses we are exploring (enueue)
843- -> ContractMap -> ContractMap -- The two contract maps
844- -> M. Map Id Id -> M. Map Id Id -- Two renamings keeping track of the address correspondence on the two maps
845- -> Error String ()
846- visit [] [] _ _ _ _ = pure ()
847- visit [] q2 _ _ _ _ = visit (rev q2) [] _ _ _ _
848- visit ((addr1, addr2): q1) q2 cmap1 cmap2 map1 map2 = do
849- let addrs1 = sortOn (\ x y -> fst x <= fst y) $ getAddrs addr1 cmap1
850- let addrs2 = sortOn (\ x y -> fst x <= fst y) $ getAddrs addr2 cmap2
851- (renaming1, renaming2, q2) <- addNeighbors addrs1 addrs2 map1 map2 q2
852- visit q1 q2' cmap1 cmap2 renaming1 renaming2
847+ bfs :: [(T. Text , T. Text )] -- Queue of the addresses we are exploring (dequeue)
848+ -> [(T. Text , T. Text )] -- Queue of the addresses we are exploring (enueue)
849+ -> M. Map T. Text T. Text -> M. Map T. Text T. Text -- Two renamings keeping track of the address bijection
850+ -> Error String ()
851+ bfs [] [] _ _ = pure ()
852+ bfs [] q2 m1 m2 = bfs (reverse q2) [] m1 m2
853+ bfs ((addr1, addr2): q1) q2 map1 map2 =
854+ case (M. lookup (EVM. SymAddr addr1) cmap1, M. lookup (EVM. SymAddr addr2) cmap2) of
855+ (Just (EVM. C _ storage1 _ _, _), Just (EVM. C _ storage2 _ _, _)) ->
856+ let addrs1 = sortOn fst $ getAddrs storage1 in
857+ let addrs2 = sortOn fst $ getAddrs storage2 in
858+ visit addrs1 addrs2 map1 map2 q2 `bindValidation` (\ (renaming1, renaming2, q2') ->
859+ bfs q1 q2' renaming1 renaming2)
860+ (_, _) -> error " Internal error: contract not found in map"
853861
854862 -- assumes that slots are unique because of simplifcation
855- addNeighbors [] [] map1 map2 discovered = pure (map1, map2, discovered)
856- addNeighbors ((s1, a1): addrs1) ((s2, a2): addrs2) map1 map2 discovered | s1 == s2 =
857- case (M. lookup s1 map1, M. lookup s2 map2) of
858- (Just s1', Just s2') ->
859- if s2 == s2' && s1 == s2' then addNeighbors addrs1 addrs2 map1 map2 discovered
863+ visit :: [(Int , EVM. Expr EVM. EAddr )] -> [(Int , EVM. Expr EVM. EAddr )]
864+ -> M. Map T. Text T. Text -> M. Map T. Text T. Text
865+ -> [(T. Text , T. Text )]
866+ -> Error String (M. Map T. Text T. Text , M. Map T. Text T. Text , [(T. Text , T. Text )])
867+ visit [] [] map1 map2 discovered = pure (map1, map2, discovered)
868+ visit ((s1, EVM. SymAddr a1): addrs1) ((s2, EVM. SymAddr a2): addrs2) map1 map2 discovered | s1 == s2 =
869+ case (M. lookup a1 map1, M. lookup a2 map2) of
870+ (Just a2', Just a1') ->
871+ if a2 == a2' && a1 == a1' then visit addrs1 addrs2 map1 map2 discovered
860872 else throw (nowhere, " The shape of the resulting map is not preserved." )
861- Nothing -> pure $ visit addrs1 addrs2 (M. insert s1 s2 map1) (M. insert s2 s1 map2) ((s1, s2): discovered)
862- addNeighbors _ _ = throw (nowhere, " The shape of the resulting map is not preserved." )
873+ (Nothing , Nothing ) -> visit addrs1 addrs2 (M. insert a1 a2 map1) (M. insert a2 a1 map2) ((a1, a2): discovered)
874+ (_, _) -> throw (nowhere, " The shape of the resulting map is not preserved." )
875+ visit _ _ _ _ _ = throw (nowhere, " The shape of the resulting map is not preserved." )
863876
864877 -- Find addresses mentioned in storage
865878 getAddrs :: EVM. Expr EVM. Storage -> [(Int , EVM. Expr EVM. EAddr )]
866- getAddrs (EVM. SStore (EVM. Lit n) (EVM. WAddr symaddr) storage) = (n, symaddr) : getAddrs storage
879+ getAddrs (EVM. SStore (EVM. Lit n) (EVM. WAddr symaddr) storage) = (fromIntegral n, symaddr) : getAddrs storage
867880 getAddrs (EVM. SStore _ _ _) = error $ " Internal error: unexpected storage shape"
868881 getAddrs (EVM. ConcreteStore _) = error $ " Internal error: unexpected storage shape"
869882 getAddrs (EVM. AbstractStore {}) = []
870883 getAddrs _ = error $ " Internal error: unexpected storage shape"
871884
885+ idOfAddr :: EVM. Expr EVM. EAddr -> T. Text
886+ idOfAddr (EVM. SymAddr addr) = addr
887+ idOfAddr _ = error " Internal error: upecting symbolic address"
872888
873889-- | Find the input space of an expr list
874890inputSpace :: [EVM. Expr EVM. End ] -> [EVM. Prop ]
0 commit comments