Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 27 additions & 16 deletions src/EVM/Equivalence.hs
Original file line number Diff line number Diff line change
Expand Up @@ -256,22 +256,33 @@ equivalenceCheck' solvers sess branchesA branchesB create = do
-- code is equivalent. The constraints from the undeployed code (aProps,bProps) influence this check.
deployedCodeDiffer :: Expr Buf -> Expr Buf -> [Prop] -> [Prop] -> m EqIssues
deployedCodeDiffer aOut bOut aProps bProps = do
let simpA = Expr.simplify aOut
simpB = Expr.simplify bOut
conf <- readConfig
case (simpA, simpB) of
(ConcreteBuf codeA, ConcreteBuf codeB) -> do
-- TODO: use aProps/bProps to constrain the deployed code
-- since symbolic code (with constructors taking arguments) is not supported,
-- this is currently not necessary
when conf.debug $ liftIO $ do
liftIO $ putStrLn $ "create deployed code A: " <> bsToHex codeA
<> " with constraints: " <> (T.unpack . T.unlines $ map formatProp aProps)
liftIO $ putStrLn $ "create deployed code B: " <> bsToHex codeB
<> " with constraints: " <> (T.unpack . T.unlines $ map formatProp bProps)
(calldata, _) <- mkCalldata Nothing []
equivalenceCheck solvers sess codeA codeB defaultVeriOpts calldata False
_ -> internalError $ "Symbolic code returned from constructor." <> " A: " <> show simpA <> " B: " <> show simpB
-- Compare deployed runtimes only when both constructor paths can occur for
-- the same input. Otherwise an impossible pair of paths can create a
-- spurious runtime difference (notably for --create).
pathOverlap <- checkSatWithProps solvers (aProps <> bProps)
case pathOverlap of
Qed -> pure mempty
Cex _ -> do
let simpA = Expr.simplify aOut
simpB = Expr.simplify bOut
conf <- readConfig
case (simpA, simpB) of
(ConcreteBuf codeA, ConcreteBuf codeB) -> do
when conf.debug $ liftIO $ do
liftIO $ putStrLn $ "create deployed code A: " <> bsToHex codeA
<> " with constraints: " <> (T.unpack . T.unlines $ map formatProp aProps)
liftIO $ putStrLn $ "create deployed code B: " <> bsToHex codeB
<> " with constraints: " <> (T.unpack . T.unlines $ map formatProp bProps)
(calldata, _) <- mkCalldata Nothing []
equivalenceCheck solvers sess codeA codeB defaultVeriOpts calldata False
_ -> internalError $ "Symbolic code returned from constructor." <> " A: " <> show simpA <> " B: " <> show simpB
Unknown reason -> pure $ EqIssues
[(Unknown ("Unable to establish constructor-path compatibility: " <> reason),
"Could not establish compatible constructor paths before comparing deployed code.")]
mempty
Error err -> pure $ EqIssues
[(Error err, "Failed to check constructor-path compatibility before comparing deployed code.")]
mempty

statesDiffer :: Map (Expr EAddr) (Expr EContract) -> Map (Expr EAddr) (Expr EContract) -> Prop
statesDiffer aState bState
Expand Down
7 changes: 6 additions & 1 deletion test/EVM/Equivalence/EquivalenceTests.hs
Original file line number Diff line number Diff line change
Expand Up @@ -444,7 +444,12 @@ deploymentSolidityEquivalenceTests = testGroup "Solidity deployment equivalence"

bytecodeEquivalenceTests :: TestTree
bytecodeEquivalenceTests = testGroup "Bytecode equivalence"
[ testCase "eq-issue-with-length-cex-bug679" $ do -- check bug https://github.com/argotorg/hevm/issues/679
[ testCase "constructor-crossed-paths-do-not-compare-impossible-deployments" $ do
let a = "34600c5760fe5f5360015ff35b60005f5360015ff3"
b = "3415600d5760005f5360015ff35b60fe5f5360015ff3"
eq <- eqBytecode False a b
assertEqual "impossible constructor paths must not create a difference" [] (map fst eq.res)
, testCase "eq-issue-with-length-cex-bug679" $ do -- check bug https://github.com/argotorg/hevm/issues/679
let a = fromJust (hexByteString "5f610100526020610100f3")
b = fromJust (hexByteString "5f356101f40115610100526020610100f3")
eq <- Effects.runApp $ withSolvers Z3 1 Nothing defMemLimit $ \s -> do
Expand Down